IBR-DTNSuite
0.8
|
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 }