From: Will Sobel Date: 2001-08-01T09:05:56+09:00 Subject: [ruby-talk:18925] RE: IP multicast with UDPSocket This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_001_01C11A1F.2CECF680 Content-Type: text/plain; charset="iso-8859-1" Something I threw together a few weeks ago. It has only been tested using Ruby 1.7.1 on Win32, but It should work on the other platforms as well. You may have to take out the definition of the constants since they should already be defined in socket.c. There are some some differences in the C headers #defines of these constants, but I did not have time to look into this and fix it on Windows. enjoy... - Will require 'socket' #struct ip_mreq { # struct in_addr imr_multiaddr; /* IP multicast address of group */ # struct in_addr imr_interface; /* local IP address of interface */ #}; class MulticastSocket < UDPSocket # Some constants that are not set in Win32 version of socket.c IPPROTO_IP = 0 IPPROTO_UDP = 17 IP_DROP_MEMBERSHIP = 6 def convAddr(a) h = nil case a when String h = a.split('.').collect! { |b| b.to_i }.pack('CCCC') when Array h = a.pack('CCCC') else raise "Bad address" end h end private :convAddr def addMembership(mcaddr) mreq = convAddr(mcaddr) + Socket.gethostbyname(Socket.gethostname)[3] setsockopt(IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, mreq) end def dropMembership(mcaddr) mreq = convAddr(mcaddr) + Socket.gethostbyname(Socket.gethostname)[3] setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq) end def setMCTTL(ttl) setsockopt(IPPROTO_IP, Socket::IP_MULTICAST_TTL, ttl) end def setMCLoop(loop) setsockopt(IPPROTO_IP, Socket::IP_MULTICAST_LOOP, loop) end def setMCInterface(int) host = Socket.gethostbyname(int)[3] setsockopt(IPPROTO_IP, Socket::IP_MULTICAST_IF, host) end end if $0 == __FILE__ $port = 1900 $addr = '239.192.0.1' sock = MulticastSocket.open sock.bind(Socket.gethostname, $port) sock.addMembership($addr) thread = Thread.start do 2.times { p sock.recvfrom(8000) } end sock.send('Hello', 0, $addr, $port) sock.send('There', 0, $addr, $port) thread.join sock.dropMembership($addr) end -----Original Message----- From: Nat Pryce [mailto:nat.pryce@b13media.com] Sent: Tuesday, July 31, 2001 5:09 AM To: ruby-talk@ruby-lang.org Subject: [ruby-talk:18883] IP multicast with UDPSocket Does anyone have example code for joining/leaving multicast groups using the UDPSocket? Also, how is it possible to write this in a platform independent manner? As far as I can tell, the API for setting socket options seems to be completely platform dependent. It is also hard to code to, because you have to build strings of binary data that contain valid C structures used by the OS APIs. Would there be interest in code to replace or wrap setsockopt/getsockopt with methods and attribute accessors? For example: socket = UDPSocket.new socket.add_membership "240.212.100.200" # or whatever a valid IP group number is socket.ip_multicast_ttl = Socket::TTL_LOCAL_NETWORK socket.ip_multicast_loopback = false socket.sol_reuse_address = true socket.bind( 15630 ) Or: socket = TCPSocket.new( 'www.b13media.com', 80 ) socket.sol_sndbuf = 512 socket.sol_rcvbuf = 4096 Would this be a useful RCR? Cheers, Nat. ------_=_NextPart_001_01C11A1F.2CECF680 Content-Type: text/html; charset="iso-8859-1"
 
Something I threw together a few weeks ago. It has only been tested using Ruby 1.7.1 on Win32, but It should work on the other platforms as well. You may have to take out the definition of the constants since they should already be defined in socket.c. There are some some differences in the C headers #defines of these constants, but I did not have time to look into this and fix it on Windows.
 
enjoy...
 
- Will
 
<SNIP filename='multicast.rb' >

require 'socket'
 
#struct ip_mreq {
#        struct in_addr  imr_multiaddr;  /* IP multicast address of group */
#        struct in_addr  imr_interface;  /* local IP address of interface */
#};
 

class MulticastSocket < UDPSocket
 
 # Some constants that are not set in Win32 version of socket.c
 IPPROTO_IP = 0
 IPPROTO_UDP = 17
 IP_DROP_MEMBERSHIP = 6
 
 def convAddr(a)
  h = nil
  case a
  when String
   h = a.split('.').collect! { |b| b.to_i }.pack('CCCC')
 
  when Array
   h = a.pack('CCCC')
 
  else
   raise "Bad address"
  end
  h
 end
 private :convAddr
 
 def addMembership(mcaddr)
  mreq = convAddr(mcaddr) + Socket.gethostbyname(Socket.gethostname)[3]
  setsockopt(IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, mreq)
 end
 
 def dropMembership(mcaddr)
  mreq = convAddr(mcaddr) + Socket.gethostbyname(Socket.gethostname)[3]
  setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq)
 end
 
 def setMCTTL(ttl)
  setsockopt(IPPROTO_IP, Socket::IP_MULTICAST_TTL, ttl)
 end
 
 def setMCLoop(loop)
  setsockopt(IPPROTO_IP, Socket::IP_MULTICAST_LOOP, loop)
 end
 
 def setMCInterface(int)
  host = Socket.gethostbyname(int)[3]
  setsockopt(IPPROTO_IP, Socket::IP_MULTICAST_IF, host)
 end
 
end
 
if $0 == __FILE__
 
 $port = 1900
 $addr = '239.192.0.1'
 
 sock = MulticastSocket.open
 sock.bind(Socket.gethostname, $port)
 sock.addMembership($addr)
  
 thread = Thread.start do
  2.times { p sock.recvfrom(8000) }
 end
 
 sock.send('Hello', 0, $addr, $port)
 sock.send('There', 0, $addr, $port)
 
 thread.join
 sock.dropMembership($addr)
end
 

</SNIP>
-----Original Message-----
From: Nat Pryce [mailto:nat.pryce@b13media.com]
Sent: Tuesday, July 31, 2001 5:09 AM
To: ruby-talk@ruby-lang.org
Subject: [ruby-talk:18883] IP multicast with UDPSocket

Does anyone have example code for joining/leaving multicast groups using the UDPSocket?
 
Also, how is it possible to write this in a platform independent manner?  As far as I can tell, the API for setting socket options seems to be completely platform dependent.  It is also hard to code to, because you have to build strings of binary data that contain valid C structures used by the OS APIs.  Would there be interest in code to replace or wrap setsockopt/getsockopt with methods and attribute accessors? 
 
For example:
 
socket = UDPSocket.new
socket.add_membership "240.212.100.200"  # or whatever a valid IP group number is
socket.ip_multicast_ttl = Socket::TTL_LOCAL_NETWORK
socket.ip_multicast_loopback = false
socket.sol_reuse_address = true
socket.bind( 15630 )
 
Or:
 
socket = TCPSocket.new( 'www.b13media.com', 80 )
socket.sol_sndbuf = 512
socket.sol_rcvbuf = 4096
 
Would this be a useful RCR?
 
Cheers,
    Nat.
 
 
------_=_NextPart_001_01C11A1F.2CECF680--