IBR-DTNSuite  0.8
ibrcommon/ibrcommon/net/MulticastSocket.cpp
Go to the documentation of this file.
00001 /*
00002  * MulticastSocket.cpp
00003  *
00004  *  Created on: 28.06.2010
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/config.h"
00009 #include "ibrcommon/net/MulticastSocket.h"
00010 #include "ibrcommon/net/vsocket.h"
00011 #include "ibrcommon/Logger.h"
00012 #include <netdb.h>
00013 #include <string.h>
00014 
00015 #ifndef HAVE_BZERO
00016 #define bzero(s,n) (memset((s), '\0', (n)), (void) 0)
00017 #endif
00018 
00019 namespace ibrcommon
00020 {
00021         MulticastSocket::MulticastSocket(const int fd)
00022          : _fd(fd)
00023         {
00024         }
00025 
00026         MulticastSocket::~MulticastSocket()
00027         {
00028         }
00029 
00030         void MulticastSocket::setInterface(const vinterface &iface)
00031         {
00032                 struct ip_mreq imr;
00033                 ::memset(&imr, 0, sizeof(ip_mreq));
00034 
00035                 std::list<vaddress> addrs = iface.getAddresses(vaddress::VADDRESS_INET);
00036                 if (addrs.empty()) return;
00037 
00038                 const vaddress &vaddr = addrs.front();
00039 
00040                 // set interface address
00041                 struct addrinfo hints, *addr;
00042                 memset(&hints, 0, sizeof hints);
00043 
00044                 hints.ai_family = vaddr.getFamily();
00045                 hints.ai_socktype = SOCK_DGRAM;
00046                 hints.ai_flags = AI_PASSIVE;
00047 
00048                 getaddrinfo(vaddr.get().c_str(), NULL, &hints, &addr);
00049 
00050                 struct sockaddr_in *saddr = (struct sockaddr_in *) addr->ai_addr;
00051 
00052                 if ( ::setsockopt(_fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&saddr->sin_addr, sizeof(saddr->sin_addr)) < 0 )
00053                 {
00054                         throw vsocket_exception("MulticastSocket: cannot set default interface");
00055                 }
00056 
00057                 freeaddrinfo(addr);
00058         }
00059 
00060         void MulticastSocket::joinGroup(const vaddress &group)
00061         {
00062                 struct ip_mreq imr;
00063                 ::memset(&imr, 0, sizeof(ip_mreq));
00064                 imr.imr_interface.s_addr = INADDR_ANY;
00065 
00066                 if (inet_pton(group.getFamily(), group.get().c_str(), &imr.imr_multiaddr) <= 0)
00067                 {
00068                         throw vsocket_exception("MulticastSocket: can not parse address " + group.get());
00069                 }
00070 
00071                 if ( ::setsockopt(_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(struct ip_mreq)) < 0)
00072                 {
00073                         throw vsocket_exception("MulticastSocket: setsockopt(IP_ADD_MEMBERSHIP)");
00074                 }
00075 
00076                 IBRCOMMON_LOGGER_DEBUG(5) << "multicast join group successful to "<< group.toString() << IBRCOMMON_LOGGER_ENDL;
00077         }
00078 
00079         void MulticastSocket::joinGroup(const vaddress &group, const vinterface &iface)
00080         {
00081                 std::list<vaddress> addrlist = iface.getAddresses(vaddress::VADDRESS_INET);
00082 
00083                 for (std::list<vaddress>::const_iterator iter = addrlist.begin(); iter != addrlist.end(); iter++)
00084                 {
00085                         const vaddress &vaddr = *iter;
00086 
00087                         // currently we only support IPv4 addresses
00088                         if (vaddr.getFamily() != vaddress::VADDRESS_INET) continue;
00089 
00090                         try {
00091                                 struct ip_mreq imr;
00092                                 ::memset(&imr, 0, sizeof(ip_mreq));
00093 
00094                                 if (inet_pton(group.getFamily(), group.get().c_str(), &imr.imr_multiaddr) <= 0)
00095                                 {
00096                                         throw vsocket_exception("MulticastSocket: can not parse address " + group.get());
00097                                 }
00098 
00099                                 // set join address
00100                                 struct addrinfo hints, *addr;
00101                                 memset(&hints, 0, sizeof hints);
00102 
00103                                 hints.ai_family = group.getFamily();
00104                                 hints.ai_socktype = SOCK_DGRAM;
00105                                 hints.ai_flags = AI_PASSIVE;
00106 
00107                                 getaddrinfo(vaddr.get().c_str(), NULL, &hints, &addr);
00108 
00109                                 struct sockaddr_in *saddr = (struct sockaddr_in *) addr->ai_addr;
00110                                 ::memcpy(&imr.imr_interface, &saddr->sin_addr, sizeof(saddr->sin_addr));
00111 
00112                                 if ( ::setsockopt(_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(struct ip_mreq)) < 0)
00113                                 {
00114                                         freeaddrinfo(addr);
00115                                         throw vsocket_exception("MulticastSocket: setsockopt(IP_ADD_MEMBERSHIP)");
00116                                 }
00117 
00118                                 freeaddrinfo(addr);
00119 
00120                                 // successful!
00121                                 IBRCOMMON_LOGGER_DEBUG(5) << "multicast join group successful to " << group.toString() << " on " << vaddr.toString() << IBRCOMMON_LOGGER_ENDL;
00122                                 return;
00123                         } catch (const vsocket_exception&) {
00124                                 // try the next address
00125                         }
00126                 }
00127         }
00128 
00129         void MulticastSocket::leaveGroup(const vaddress &group)
00130         {
00131                 struct ip_mreq imr;
00132                 ::memset(&imr, 0, sizeof(ip_mreq));
00133 
00134                 if (inet_pton(group.getFamily(), group.get().c_str(), &imr.imr_multiaddr) <= 0)
00135                 {
00136                         throw vsocket_exception("MulticastSocket: can not parse address " + group.get());
00137                 }
00138 
00139                 if ( ::setsockopt(_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(struct ip_mreq)) < 0)
00140                 {
00141                         throw vsocket_exception("MulticastSocket: setsockopt(IP_DROP_MEMBERSHIP)");
00142                 }
00143         }
00144 
00145         void MulticastSocket::leaveGroup(const vaddress &group, const vinterface &iface)
00146         {
00147                 struct ip_mreq imr;
00148                 ::memset(&imr, 0, sizeof(ip_mreq));
00149 
00150                 if (inet_pton(group.getFamily(), group.get().c_str(), &imr.imr_multiaddr) <= 0)
00151                 {
00152                         throw vsocket_exception("MulticastSocket: can not parse address " + group.get());
00153                 }
00154 
00155                 // set leave address
00156                 struct addrinfo hints, *addr;
00157                 memset(&hints, 0, sizeof hints);
00158 
00159                 hints.ai_family = group.getFamily();
00160                 hints.ai_socktype = SOCK_DGRAM;
00161                 hints.ai_flags = AI_PASSIVE;
00162 
00163                 getaddrinfo(group.get().c_str(), NULL, &hints, &addr);
00164 
00165                 struct sockaddr_in *saddr = (struct sockaddr_in *) addr->ai_addr;
00166                 ::memcpy(&imr.imr_interface, &saddr->sin_addr, sizeof(saddr->sin_addr));
00167 
00168                 if ( ::setsockopt(_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char *)&imr, sizeof(struct ip_mreq)) < 0)
00169                 {
00170                         throw vsocket_exception("MulticastSocket: setsockopt(IP_DROP_MEMBERSHIP)");
00171                 }
00172 
00173                 freeaddrinfo(addr);
00174         }
00175 }