Show
Ignore:
Timestamp:
08/23/06 14:57:55 (8 years ago)
Author:
piers
Message:

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

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • vic/trunk/net/net-ipv6.cpp

    r3746 r3796  
    6060#include "net.h" 
    6161#include "vic_tcl.h" 
    62 //#include "inet_ntop.h" //SV-XXX: FreeBSD 
     62#include "inet_ntop.h" //SV-XXX: FreeBSD 
    6363 
    6464#include "inet6.h" 
     
    8181 
    8282#ifndef INET6_ADDRSTRLEN 
     83// Max IPv6 Address len = 8*4(addr hex)+7(semicolons)+1(null terminator)=40 
    8384#define INET6_ADDRSTRLEN (46) 
    8485#endif 
     
    121122class IP6Network : public Network { 
    122123  public: 
    123           IP6Network() : Network(*(new IP6Address), *(new IP6Address))  {;} 
     124          IP6Network() : Network(*(new IP6Address), *(new IP6Address), *(new IP6Address))  {;} 
    124125        virtual int command(int argc, const char*const* argv); 
    125126        virtual void reset(); 
     
    141142        int localname(sockaddr_in6*); 
    142143        int openssock(Address & addr, u_short port, int ttl); 
    143         int openrsock(Address & addr, u_short port, Address & local); 
     144        int openrsock(Address & g_addr, Address & s_addr_ssm, u_short port, Address & local); 
    144145        time_t last_reset_; 
    145146        unsigned int flowLabel_;        /* Flowlabel for all traffic */ 
     
    192193                if (strcmp(argv[1], "addr") == 0) { 
    193194/* __IPV6 use Address */ 
    194                         strcpy(cp, addr_); 
     195                        strcpy(cp, g_addr_); 
    195196                        return (TCL_OK); 
    196197                } 
     
    214215/* __IPV6 use IN6_IS_ADDR */ 
    215216                if (strcmp(argv[1], "ismulticast") == 0) { 
    216                         const in6_addr & addr = (IP6Address&)addr_; 
     217                        const in6_addr & addr = (IP6Address&)g_addr_; 
    217218                        tcl.result(IN6_IS_ADDR_MULTICAST(&addr)? "1" : "0"); 
    218219                        return (TCL_OK); 
     
    257258int IP6Network::open(const char * host, int port, int ttl) 
    258259{ 
    259         addr_ = host; 
     260        char *g_addr; 
     261        // Check for SSM src address: Src,Group 
     262        if ((g_addr=strchr(host,(int)','))!=NULL) { 
     263                char s_addr_ssm[MAXHOSTNAMELEN]; 
     264                int i=0; 
     265                while (&host[i]<g_addr) { 
     266                        s_addr_ssm[i]=host[i++]; 
     267                } 
     268                s_addr_ssm[i]='\0'; 
     269                g_addr_=++g_addr; 
     270                s_addr_ssm_=s_addr_ssm; 
     271        } else { 
     272                // No SSM address found - just use group host address 
     273                g_addr_=host; 
     274        } 
     275        g_addr_ = host; 
    260276        port_ = port; 
    261277        ttl_ = ttl; 
    262278 
    263         ssock_ = openssock(addr_, port, ttl); 
     279        ssock_ = openssock(g_addr_, port, ttl); 
    264280        if (ssock_ < 0) 
    265281                return (-1); 
     
    275291        (IP6Address&)local_ = local.sin6_addr; 
    276292 
    277         rsock_ = openrsock(addr_, port, local_); 
     293        rsock_ = openrsock(g_addr_, s_addr_ssm_, port, local_); 
    278294        if (rsock_ < 0) { 
    279295                (void)::close(ssock_); 
     
    314330        // Use Local name if already set via command line 
    315331        // But use port derived from getsockname 
    316         if (((const char*)local_)[0]!='\0') { 
     332  if (local_.isset()) { 
    317333                p->sin6_addr=(IP6Address&)local_; 
    318334                return (result); 
     
    338354                last_reset_ = t; 
    339355                (void)::close(ssock_); 
    340                 ssock_ = openssock(addr_, port_, ttl_); 
    341         } 
    342 } 
    343  
    344 int IP6Network::openrsock(Address & addr, u_short port, Address & local) 
     356                ssock_ = openssock(g_addr_, port_, ttl_); 
     357        } 
     358} 
     359 
     360int IP6Network::openrsock(Address & g_addr, Address & s_addr_ssm, u_short port, Address & local) 
    345361{ 
    346362        int fd; 
     
    368384        memset((char *)&sin, 0, sizeof(sin)); 
    369385        sin.sin6_family = AF_INET6; 
    370         sin.sin6_addr = (IP6Address&)addr; 
     386        sin.sin6_addr = (IP6Address&)g_addr; 
    371387        sin.sin6_port = port; 
     388 
    372389#ifdef IPV6_ADD_MEMBERSHIP 
    373390        if (IN6_IS_ADDR_MULTICAST(&sin.sin6_addr)) { 
     
    386403                        } 
    387404                } 
    388                 /*  
    389                  * XXX This is bogus multicast setup that really 
    390                  * shouldn't have to be done (group membership should be 
    391                  * implicit in the IP class D address, route should contain 
    392                  * ttl & no loopback flag, etc.).  Steve Deering has promised 
    393                  * to fix this for the 4.4bsd release.  We're all waiting 
    394                  * with bated breath. 
    395                  */ 
    396                 struct ipv6_mreq mr; 
    397  
    398 /* __IPV6 memcopy address */ 
    399 #ifdef MUSICA_IPV6 
    400                 mr.i6mr_interface = (ifIndex_<0)?0:ifIndex_; 
    401                 mr.i6mr_multiaddr = (IP6Address&)addr; 
    402 #else 
    403                 mr.ipv6mr_interface = (ifIndex_<0)?0:ifIndex_; 
    404                 mr.ipv6mr_multiaddr = (IP6Address&)addr; 
    405 #endif 
    406  
    407                 int mreqsize = sizeof(mr); 
    408 #ifdef WIN2K_IPV6 
    409                 mreqsize += 4; 
    410 #endif 
    411                 if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,  
    412                                (char *)&mr, mreqsize) < 0) { 
    413                         perror("IPV6_ADD_MEMBERSHIP"); 
    414                         exit(1); 
     405 
     406#ifdef IPV6_ADD_SOURCE_MEMBERSHIP   
     407        struct ipv6_mreq_source mrs; 
     408                /* Check if an Src addr - as in S,G has been set */ 
     409        if (s_addr_ssm.isset()) { 
     410                mrs.ipv6mr_sourceaddr = (IP6Address&)s_addr_ssm; 
     411                                mrs.ipv6mr_interface = (ifIndex_<0)?0:ifIndex_; 
     412                                mrs.ipv6mr_multiaddr = (IP6Address&)g_addr; 
     413 
     414                                if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_SOURCE_MEMBERSHIP, 
     415                                (char*)&mrs, sizeof(mrs)) < 0) { 
     416                        perror("IPV6_ADD_SOURCE_MEMBERSHIP"); 
     417                        exit (1); 
     418                } 
     419        } else 
     420                         
     421#endif /* IPV6_ADD_SOURCE_MEMBERSHIP */ 
     422                { 
     423                                /*  
     424                                * XXX This is bogus multicast setup that really 
     425                                * shouldn't have to be done (group membership should be 
     426                                * implicit in the IP class D address, route should contain 
     427                                * ttl & no loopback flag, etc.).  Steve Deering has promised 
     428                                * to fix this for the 4.4bsd release.  We're all waiting 
     429                                * with bated breath. 
     430                                */ 
     431                                                struct ipv6_mreq mr; 
     432 
     433                /* __IPV6 memcopy address */ 
     434                #ifdef MUSICA_IPV6 
     435                                mr.i6mr_interface = (ifIndex_<0)?0:ifIndex_; 
     436                                mr.i6mr_multiaddr = (IP6Address&)g_addr; 
     437                #else 
     438                                mr.ipv6mr_interface = (ifIndex_<0)?0:ifIndex_; 
     439                                mr.ipv6mr_multiaddr = (IP6Address&)g_addr; 
     440                #endif 
     441 
     442                                int mreqsize = sizeof(mr); 
     443 
     444                // Fix for buggy header files in Win2k 
     445                #ifdef WIN2K_IPV6 
     446                                mreqsize += 4; 
     447                #endif 
     448                                if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,  
     449                                                (char *)&mr, mreqsize) < 0) { 
     450                                        perror("IPV6_ADD_MEMBERSHIP"); 
     451                                        exit(1); 
     452                                } 
    415453                } 
    416454        } else 
     
    481519        sin.sin6_flowinfo = flowLabel_; 
    482520/* __IPV6 memcopy address */ 
    483         // Use Local name if already set via command line 
    484         if (((const char*)local_)[0]!='\0') { 
     521    // Use Local name if already set via command line 
     522        if (local_.isset()) { 
    485523                sin.sin6_addr = (IP6Address&)local_; 
    486         } else { 
     524    } else { 
    487525                sin.sin6_addr = in6addr_any; 
    488526        } 
     
    503541        } 
    504542        if (IN6_IS_ADDR_MULTICAST(&sin.sin6_addr)) { 
     543 
    505544#ifdef IPV6_ADD_MEMBERSHIP 
    506545                char c;