00001
00002
00003
00004
00005
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
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
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
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
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
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
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 }