[Sumover-dev] [svn commit] r3796 - vic/trunk/net

sumover-dev at cs.ucl.ac.uk sumover-dev at cs.ucl.ac.uk
Wed Aug 23 14:58:24 BST 2006


Author: piers
Date: Wed Aug 23 14:57:55 2006
New Revision: 3796

Modified:
   vic/trunk/net/net-ip.cpp
   vic/trunk/net/net-ipv6.cpp
   vic/trunk/net/net.cpp
   vic/trunk/net/net.h

Log:
Added Source-Specific Multicast (SSM) support - tested IPv4 on WinXP.

Modified: vic/trunk/net/net-ip.cpp
==============================================================================
--- vic/trunk/net/net-ip.cpp	(original)
+++ vic/trunk/net/net-ip.cpp	Wed Aug 23 14:57:55 2006
@@ -56,6 +56,7 @@
 #include "net-addr.h"
 
 #ifndef INET_ADDRSTRLEN
+// IPv4 Address len = 4*3(addr bytes)+3(dots)+1(null terminator)=16
 #define INET_ADDRSTRLEN (16)
 #endif
 
@@ -96,7 +97,7 @@
 
 class IPNetwork : public Network {
     public:
-		IPNetwork() : Network(*(new IPAddress), *(new IPAddress)) {;}
+		IPNetwork() : Network(*(new IPAddress), *(new IPAddress), *(new IPAddress)) {;}
 	virtual int command(int argc, const char*const* argv);
 	virtual void reset();
 	virtual Address* alloc(const char* name) { 
@@ -116,7 +117,7 @@
 	int close();
 	int localname(sockaddr_in*);
 	int openssock(Address & addr, u_short port, int ttl);
-	int openrsock(Address & addr, u_short port, Address & local);
+	int openrsock(Address & g_addr, Address & s_addr_ssm, u_short port, Address & local);
 	time_t last_reset_;
 };
 
@@ -160,7 +161,7 @@
 		}
 		char* cp = tcl.result();
 		if (strcmp(argv[1], "addr") == 0) {
-			strcpy(cp, addr_);
+			strcpy(cp, g_addr_);
 			return (TCL_OK);
 		}
 		if (strcmp(argv[1], "interface") == 0) {
@@ -180,7 +181,7 @@
 			return (TCL_OK);
 		}
 		if (strcmp(argv[1], "ismulticast") == 0) {
-			u_int32_t addri = (IPAddress&)addr_;
+			u_int32_t addri = (IPAddress&)g_addr_;
 			tcl.result(IN_CLASSD(ntohl(addri))? "1" : "0");
 			return (TCL_OK);
 		}
@@ -218,11 +219,26 @@
 
 int IPNetwork::open(const char * host, int port, int ttl)
 {
-	addr_ = host;
+	char *g_addr;
+	// Check for SSM src address: Src,Group
+	if ((g_addr=strchr(host,(int)','))!=NULL) {
+		char s_addr_ssm[MAXHOSTNAMELEN];
+		int i=0;
+		while (&host[i]<g_addr) {
+			s_addr_ssm[i]=host[i++];
+		}
+		s_addr_ssm[i]='\0';
+		g_addr_=++g_addr;
+		s_addr_ssm_=s_addr_ssm;
+	} else {
+		// No SSM address found - just use group host address
+		g_addr_=host;
+	}
 	port_ = port;
 	ttl_ = ttl;
 
-	ssock_ = openssock(addr_, port, ttl);
+
+	ssock_ = openssock(g_addr_, port, ttl);
 	if (ssock_ < 0)
 		return (-1);
 	/*
@@ -235,7 +251,7 @@
 		return (-1);
 	}
 	(IPAddress&)local_ = local.sin_addr;
-	rsock_ = openrsock(addr_, port, local_);
+	rsock_ = openrsock(g_addr_, s_addr_ssm_, port, local_);
 	if (rsock_ < 0) {
 		(void)::close(ssock_);
 		return (-1);
@@ -272,7 +288,7 @@
 		p->sin_port = 0;
 	}
 	// Use Local interface name if already set via command line
-	if (((const char*)local_)[0]!='\0') {
+	if (local_.isset()) {
 		p->sin_addr.s_addr=(IPAddress&)local_;
 		return (0);
 	}
@@ -292,16 +308,17 @@
 	if (d > 3) {
 		last_reset_ = t;
 		(void)::close(ssock_);
-		ssock_ = openssock(addr_, port_, ttl_);
+		ssock_ = openssock(g_addr_, port_, ttl_);
 	}
 }
 
-int IPNetwork::openrsock(Address & addr, u_short port, Address & local)
+int IPNetwork::openrsock(Address & g_addr, Address & s_addr_ssm, u_short port, Address & local)
 {
 	int fd;
 	struct sockaddr_in sin;
 
-	u_int32_t addri = (IPAddress&)addr;
+	u_int32_t g_addri = (IPAddress&)g_addr;
+	u_int32_t g_addri_ssm = (IPAddress&)s_addr_ssm;
 	u_int32_t locali = (IPAddress&)local;
 
 	fd = socket(AF_INET, SOCK_DGRAM, 0);
@@ -327,14 +344,14 @@
 	sin.sin_family = AF_INET;
 	sin.sin_port = port;
 #ifdef IP_ADD_MEMBERSHIP
-	if (IN_CLASSD(ntohl(addri))) {
+	if (IN_CLASSD(ntohl(g_addri))) {
 		/*
 		 * Try to bind the multicast address as the socket
 		 * dest address.  On many systems this won't work
 		 * so fall back to a destination of INADDR_ANY if
 		 * the first bind fails.
 		 */
-		sin.sin_addr.s_addr = addri;
+		sin.sin_addr.s_addr = g_addri;
 		if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
 			sin.sin_addr.s_addr = INADDR_ANY;
 			if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
@@ -342,25 +359,43 @@
 				exit(1);
 			}
 		}
-		/* 
-		 * XXX This is bogus multicast setup that really
-		 * shouldn't have to be done (group membership should be
-		 * implicit in the IP class D address, route should contain
-		 * ttl & no loopback flag, etc.).  Steve Deering has promised
-		 * to fix this for the 4.4bsd release.  We're all waiting
-		 * with bated breath.
-		 */
-		struct ip_mreq mr;
-
-		mr.imr_multiaddr.s_addr = addri;
-		mr.imr_interface.s_addr = INADDR_ANY;
-		if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
-			       (char *)&mr, sizeof(mr)) < 0) {
-			perror("IP_ADD_MEMBERSHIP");
-			exit(1);
+		/* SSM code */
+#ifdef IP_ADD_SOURCE_MEMBERSHIP  
+        struct ip_mreq_source mrs;
+		/* Check if an Src addr - as in S,G has been set */
+        if (s_addr_ssm.isset()) {
+                mrs.imr_sourceaddr.s_addr = g_addri_ssm;
+                mrs.imr_multiaddr.s_addr = g_addri;
+                mrs.imr_interface.s_addr = INADDR_ANY;
+                if (setsockopt(fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
+                                (char*)&mrs, sizeof(mrs)) < 0) {
+                        perror("IP_ADD_SOURCE_MEMBERSHIP");
+                        exit (1);
+                }
+        } else
+                        
+#endif /* IP_ADD_SOURCE_MEMBERSHIP */
+		{
+				/* 
+				* XXX This is bogus multicast setup that really
+				* shouldn't have to be done (group membership should be
+				* implicit in the IP class D address, route should contain
+				* ttl & no loopback flag, etc.).  Steve Deering has promised
+				* to fix this for the 4.4bsd release.  We're all waiting
+				* with bated breath.
+				*/
+				struct ip_mreq mr;
+
+				mr.imr_multiaddr.s_addr = g_addri;
+				mr.imr_interface.s_addr = INADDR_ANY;
+				if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
+						(char *)&mr, sizeof(mr)) < 0) {
+					perror("IP_ADD_MEMBERSHIP");
+					exit(1);
+				}
 		}
 	} else
-#endif
+#endif /* IP_ADD_MEMBERSHIP */
 	{
 		/*
 		 * bind the local host's address to this socket.  If that

Modified: vic/trunk/net/net-ipv6.cpp
==============================================================================
--- vic/trunk/net/net-ipv6.cpp	(original)
+++ vic/trunk/net/net-ipv6.cpp	Wed Aug 23 14:57:55 2006
@@ -59,7 +59,7 @@
 #include "config.h"
 #include "net.h"
 #include "vic_tcl.h"
-//#include "inet_ntop.h" //SV-XXX: FreeBSD
+#include "inet_ntop.h" //SV-XXX: FreeBSD
 
 #include "inet6.h"
 #include "net-addr.h"
@@ -80,6 +80,7 @@
 #endif
 
 #ifndef INET6_ADDRSTRLEN
+// Max IPv6 Address len = 8*4(addr hex)+7(semicolons)+1(null terminator)=40
 #define INET6_ADDRSTRLEN (46)
 #endif
 
@@ -120,7 +121,7 @@
 
 class IP6Network : public Network {
   public:
-	  IP6Network() : Network(*(new IP6Address), *(new IP6Address))  {;}
+	  IP6Network() : Network(*(new IP6Address), *(new IP6Address), *(new IP6Address))  {;}
 	virtual int command(int argc, const char*const* argv);
 	virtual void reset();
 	virtual Address* alloc(const char* name) { 
@@ -140,7 +141,7 @@
 	int close();
 	int localname(sockaddr_in6*);
 	int openssock(Address & addr, u_short port, int ttl);
-	int openrsock(Address & addr, u_short port, Address & local);
+	int openrsock(Address & g_addr, Address & s_addr_ssm, u_short port, Address & local);
 	time_t last_reset_;
 	unsigned int flowLabel_;	/* Flowlabel for all traffic */
 	int ifIndex_;		/* Interface index to bind to on all layers */
@@ -191,7 +192,7 @@
 		char* cp = tcl.result();
 		if (strcmp(argv[1], "addr") == 0) {
 /* __IPV6 use Address */
-			strcpy(cp, addr_);
+			strcpy(cp, g_addr_);
 			return (TCL_OK);
 		}
 		if (strcmp(argv[1], "interface") == 0) {
@@ -213,7 +214,7 @@
 		}
 /* __IPV6 use IN6_IS_ADDR */
 		if (strcmp(argv[1], "ismulticast") == 0) {
-			const in6_addr & addr = (IP6Address&)addr_;
+			const in6_addr & addr = (IP6Address&)g_addr_;
 			tcl.result(IN6_IS_ADDR_MULTICAST(&addr)? "1" : "0");
 			return (TCL_OK);
 /* __IPV6 user IPV6_MULTICAST_LOOP */
@@ -256,11 +257,26 @@
 
 int IP6Network::open(const char * host, int port, int ttl)
 {
-	addr_ = host;
+	char *g_addr;
+	// Check for SSM src address: Src,Group
+	if ((g_addr=strchr(host,(int)','))!=NULL) {
+		char s_addr_ssm[MAXHOSTNAMELEN];
+		int i=0;
+		while (&host[i]<g_addr) {
+			s_addr_ssm[i]=host[i++];
+		}
+		s_addr_ssm[i]='\0';
+		g_addr_=++g_addr;
+		s_addr_ssm_=s_addr_ssm;
+	} else {
+		// No SSM address found - just use group host address
+		g_addr_=host;
+	}
+	g_addr_ = host;
 	port_ = port;
 	ttl_ = ttl;
 
-	ssock_ = openssock(addr_, port, ttl);
+	ssock_ = openssock(g_addr_, port, ttl);
 	if (ssock_ < 0)
 		return (-1);
 	/*
@@ -274,7 +290,7 @@
 	}
 	(IP6Address&)local_ = local.sin6_addr;
 
-	rsock_ = openrsock(addr_, port, local_);
+	rsock_ = openrsock(g_addr_, s_addr_ssm_, port, local_);
 	if (rsock_ < 0) {
 		(void)::close(ssock_);
 		return (-1);
@@ -313,7 +329,7 @@
 
 	// Use Local name if already set via command line
 	// But use port derived from getsockname
-	if (((const char*)local_)[0]!='\0') {
+  if (local_.isset()) {
 		p->sin6_addr=(IP6Address&)local_;
 		return (result);
 	}
@@ -337,11 +353,11 @@
 	if (d > 3) {
 		last_reset_ = t;
 		(void)::close(ssock_);
-		ssock_ = openssock(addr_, port_, ttl_);
+		ssock_ = openssock(g_addr_, port_, ttl_);
 	}
 }
 
-int IP6Network::openrsock(Address & addr, u_short port, Address & local)
+int IP6Network::openrsock(Address & g_addr, Address & s_addr_ssm, u_short port, Address & local)
 {
 	int fd;
 	struct sockaddr_in6 sin;
@@ -367,8 +383,9 @@
 #endif
 	memset((char *)&sin, 0, sizeof(sin));
 	sin.sin6_family = AF_INET6;
-	sin.sin6_addr = (IP6Address&)addr;
+	sin.sin6_addr = (IP6Address&)g_addr;
 	sin.sin6_port = port;
+
 #ifdef IPV6_ADD_MEMBERSHIP
 	if (IN6_IS_ADDR_MULTICAST(&sin.sin6_addr)) {
 		/*
@@ -385,33 +402,54 @@
 				exit(1);
 			}
 		}
-		/* 
-		 * XXX This is bogus multicast setup that really
-		 * shouldn't have to be done (group membership should be
-		 * implicit in the IP class D address, route should contain
-		 * ttl & no loopback flag, etc.).  Steve Deering has promised
-		 * to fix this for the 4.4bsd release.  We're all waiting
-		 * with bated breath.
-		 */
-                struct ipv6_mreq mr;
 
-/* __IPV6 memcopy address */
-#ifdef MUSICA_IPV6
-		mr.i6mr_interface = (ifIndex_<0)?0:ifIndex_;
-		mr.i6mr_multiaddr = (IP6Address&)addr;
-#else
-		mr.ipv6mr_interface = (ifIndex_<0)?0:ifIndex_;
-		mr.ipv6mr_multiaddr = (IP6Address&)addr;
-#endif
-
-		int mreqsize = sizeof(mr);
-#ifdef WIN2K_IPV6
-		mreqsize += 4;
-#endif
-		if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, 
-			       (char *)&mr, mreqsize) < 0) {
-			perror("IPV6_ADD_MEMBERSHIP");
-			exit(1);
+#ifdef IPV6_ADD_SOURCE_MEMBERSHIP  
+        struct ipv6_mreq_source mrs;
+		/* Check if an Src addr - as in S,G has been set */
+        if (s_addr_ssm.isset()) {
+                mrs.ipv6mr_sourceaddr = (IP6Address&)s_addr_ssm;
+				mrs.ipv6mr_interface = (ifIndex_<0)?0:ifIndex_;
+				mrs.ipv6mr_multiaddr = (IP6Address&)g_addr;
+
+				if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_SOURCE_MEMBERSHIP,
+                                (char*)&mrs, sizeof(mrs)) < 0) {
+                        perror("IPV6_ADD_SOURCE_MEMBERSHIP");
+                        exit (1);
+                }
+        } else
+                        
+#endif /* IPV6_ADD_SOURCE_MEMBERSHIP */
+		{
+				/* 
+				* XXX This is bogus multicast setup that really
+				* shouldn't have to be done (group membership should be
+				* implicit in the IP class D address, route should contain
+				* ttl & no loopback flag, etc.).  Steve Deering has promised
+				* to fix this for the 4.4bsd release.  We're all waiting
+				* with bated breath.
+				*/
+						struct ipv6_mreq mr;
+
+		/* __IPV6 memcopy address */
+		#ifdef MUSICA_IPV6
+				mr.i6mr_interface = (ifIndex_<0)?0:ifIndex_;
+				mr.i6mr_multiaddr = (IP6Address&)g_addr;
+		#else
+				mr.ipv6mr_interface = (ifIndex_<0)?0:ifIndex_;
+				mr.ipv6mr_multiaddr = (IP6Address&)g_addr;
+		#endif
+
+				int mreqsize = sizeof(mr);
+
+		// Fix for buggy header files in Win2k
+		#ifdef WIN2K_IPV6
+				mreqsize += 4;
+		#endif
+				if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, 
+						(char *)&mr, mreqsize) < 0) {
+					perror("IPV6_ADD_MEMBERSHIP");
+					exit(1);
+				}
 		}
 	} else
 #endif
@@ -480,10 +518,10 @@
 	sin.sin6_port = 0;
 	sin.sin6_flowinfo = flowLabel_;
 /* __IPV6 memcopy address */
-        // Use Local name if already set via command line
-        if (((const char*)local_)[0]!='\0') {
+    // Use Local name if already set via command line
+	if (local_.isset()) {
 		sin.sin6_addr = (IP6Address&)local_;
-        } else {
+    } else {
 		sin.sin6_addr = in6addr_any;
 	}
 	if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
@@ -502,6 +540,7 @@
 		exit(1);
 	}
 	if (IN6_IS_ADDR_MULTICAST(&sin.sin6_addr)) {
+
 #ifdef IPV6_ADD_MEMBERSHIP
 		char c;
 

Modified: vic/trunk/net/net.cpp
==============================================================================
--- vic/trunk/net/net.cpp	(original)
+++ vic/trunk/net/net.cpp	Wed Aug 23 14:57:55 2006
@@ -110,10 +110,15 @@
 	Address * result = alloc(name);
 	return (result ? result : new Address());
 }
-
+int Address::isset() {
+	if (text_!=0) 
+		if (*text_!='\0') return 1;
+	return 0;
+}
 
 Network::Network() :
-	addr_(*(Address::default_alloc())),
+	g_addr_(*(Address::default_alloc())),
+	s_addr_ssm_(*(Address::default_alloc())),
 	local_(*(Address::default_alloc())),
 	lport_(0),
 	port_(0),
@@ -125,8 +130,9 @@
 {
 }
 
-Network::Network(Address & addr, Address & local) :
-	addr_(addr),
+Network::Network(Address & g_addr, Address & s_addr_ssm, Address & local) :
+	g_addr_(g_addr),
+	s_addr_ssm_(s_addr_ssm),
 	local_(local),
 	lport_(0),
 	port_(0),
@@ -140,7 +146,8 @@
 
 Network::~Network()
 {
-	if (&addr_) delete &addr_; 
+	if (&g_addr_) delete &g_addr_; 
+	if (&s_addr_ssm_) delete &s_addr_ssm_; 
 	if (&local_) delete &local_;
 }
 

Modified: vic/trunk/net/net.h
==============================================================================
--- vic/trunk/net/net.h	(original)
+++ vic/trunk/net/net.h	Wed Aug 23 14:57:55 2006
@@ -68,6 +68,7 @@
 
 	static Address * alloc(const char * name);
 	static Address * default_alloc();
+	int isset();
 protected:
 	char *text_;
 };
@@ -75,7 +76,7 @@
 class Network : public TclObject {
 public:
 	Network();
-	Network(Address & addr, Address & local);
+	Network(Address & g_addr, Address & s_addr_ssm, Address & local);
 	virtual ~Network();
 	virtual int command(int argc, const char*const* argv);
 	virtual void send(u_char* buf, int len);
@@ -85,7 +86,7 @@
 	virtual int recv(u_char* buf, int len, Address &from);
 	inline int rchannel() const { return (rsock_); }
 	inline int schannel() const { return (ssock_); }
-	inline const Address & addr() const { return (addr_); }
+	inline const Address & addr() const { return (g_addr_); }
 	inline const Address & interface() const { return (local_); }
 	inline int port() const { return (port_); }
 	inline int ttl() const { return (ttl_); }
@@ -100,7 +101,8 @@
     virtual int dorecv(u_char* buf, int len, u_int32_t& from, int fd);
 	virtual int dorecv(u_char* buf, int len, Address &from, int fd) {UNUSED(buf); UNUSED(len); UNUSED(from); UNUSED(fd); return (0);}
 
-	Address & addr_;
+	Address & g_addr_; // Group or host address
+	Address & s_addr_ssm_; // Src address (as in S,G) for SSM groups
 	Address & local_;
 	u_short lport_;
 	u_short port_;



More information about the Sumover-dev mailing list