static bool set_address(sockaddr_storage &t, const address &addr) { if (addr.family() == AF_INET) memcpy(&t, addr.v4(), addr.addrlen()); else if (addr.family() == AF_INET6) memcpy(&t, addr.v6(), addr.addrlen()); else return false; return true; }
static void CountSSMLeave(const address &group, const address &source) { address source_addr; char tmp[64], tmp2[64]; GroupMap::iterator g = groupMap.find(group); assert(g != groupMap.end()); source_addr.set_family(source.family()); source_addr.copy_address(source); source_addr.set_port(0); SourceMap::iterator s = g->second.find(source_addr); assert(s != g->second.end()); SourceSet::iterator ss = s->second.find(source); if (ss == s->second.end()) { return; } if (verbose) info("Removing beacon %s from (%s, %s)", source.to_string(tmp, sizeof(tmp)), source_addr.to_string(tmp2, sizeof(tmp2)), group.to_string(tmp2, sizeof(tmp2))); s->second.erase(ss); if (s->second.empty()) { if (verbose) info("No more beacons for (%s, %s), leaving group", source_addr.to_string(tmp, sizeof(tmp)), group.to_string(tmp2, sizeof(tmp2))); SSMLeave(ssmMcastSock,group, source_addr); g->second.erase(s); } if (g->second.empty()) { if (verbose) info("No more sources, unregistering group %s, ", group.to_string(tmp, sizeof(tmp))); groupMap.erase(g); } }
int SendTo(int sock, const uint8_t *buffer, int len, const address &from, const address &to) { #ifdef IPV6_PKTINFO if (from.family() == AF_INET6) { uint8_t ctlbuf[CMSG_SPACE(sizeof(in6_pktinfo))]; cmsghdr *chdr = (cmsghdr *)ctlbuf; chdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo)); chdr->cmsg_level = IPPROTO_IPV6; chdr->cmsg_type = IPV6_PKTINFO; in6_pktinfo *info = (in6_pktinfo *)CMSG_DATA(chdr); info->ipi6_addr = from.v6()->sin6_addr; info->ipi6_ifindex = 0; msghdr msg; iovec iov; msg.msg_name = (char *)to.saddr(); msg.msg_namelen = to.addrlen(); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (char *)ctlbuf; msg.msg_controllen = sizeof(ctlbuf); msg.msg_flags = 0; iov.iov_base = (char *)buffer; iov.iov_len = len; return sendmsg(sock, &msg, 0); } #endif return sendto(sock, buffer, len, 0, to.saddr(), to.addrlen()); }
static void CountSSMJoin(const address &group, const address &source) { address source_addr; char tmp[64], tmp2[64], tmp3[64]; source_addr.set_family(source.family()); source_addr.copy_address(source); source_addr.set_port(0); GroupMap::iterator g = groupMap.find(group); if (g == groupMap.end()) { if (verbose) info("Registering SSM group %s", group.to_string(tmp, sizeof(tmp))); g = groupMap.insert(std::make_pair(group, SourceMap())).first; } SourceMap::iterator s = g->second.find(source_addr); if (s == g->second.end()) { if (verbose) info("Joining (%s, %s)", source_addr.to_string(tmp, sizeof(tmp)), group.to_string(tmp2, sizeof(tmp2))); if (SSMJoin(ssmMcastSock, group, source_addr) < 0) { if (verbose) info("Join failed, reason: %s", strerror(errno)); return; } else { s = g->second.insert(std::make_pair(source_addr, SourceSet())).first; } } SourceSet::iterator ss = s->second.find(source); if (ss == s->second.end()) { if (verbose) info("Adding beacon %s to (%s, %s)", source.to_string(tmp, sizeof(tmp)), source_addr.to_string(tmp2, sizeof(tmp2)), group.to_string(tmp3, sizeof(tmp3))); s->second.insert(source); } }
bool RequireToAddress(int sock, const address &addr) { #ifdef IPV6_PKTINFO if (addr.family() == AF_INET6) { int on = 1; return setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) == 0; } #endif return true; }
bool address::copy_address(const address &source) { if (family() != source.family()) return false; if (stor.ss_family == AF_INET6) v6()->sin6_addr = source.v6()->sin6_addr; else v4()->sin_addr = source.v4()->sin_addr; return true; }
address get_local_address_for(const address &remote) { int tmpSock = socket(remote.family(), SOCK_DGRAM, 0); if (tmpSock < 0) { perror("Failed to create socket to discover local addr"); exit(-1); } if (connect(tmpSock, remote.saddr(), remote.addrlen()) != 0) { perror("Failed to connect multicast socket"); exit(-1); } address result(remote.family()); if (result.fromsocket(tmpSock) < 0) { perror("getsockname"); exit(-1); } close(tmpSock); return result; }
int _McastListenOldAPI(int sock, const address &grpaddr) { if (grpaddr.family() == AF_INET6) { ipv6_mreq mreq; mreq.ipv6mr_interface = mcastInterface; mreq.ipv6mr_multiaddr = grpaddr.v6()->sin6_addr; return setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)); } else { ip_mreq mreq; memset(&mreq, 0, sizeof(mreq)); // Specifying the interface doesn't work, there's ip_mreqn in linux.. // but what about other OSs? -hugo mreq.imr_multiaddr = grpaddr.v4()->sin_addr; return setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); } }
int SetupSocket(const address &addr, bool shouldbind, bool ssm) { int af_family = addr.family(); int level = addr.optlevel(); int sock = socket(af_family, SOCK_DGRAM, 0); if (sock < 0) { perror("Failed to create multicast socket"); return -1; } int on = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) { perror("setsockopt"); return -1; } if (shouldbind) { if (bind(sock, addr.saddr(), addr.addrlen()) != 0) { perror("Failed to bind multicast socket"); return -1; } } #ifdef SO_TIMESTAMP if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) != 0) { perror("setsockopt(SO_TIMESTAMP)"); return -1; } #endif int type = level == IPPROTO_IPV6 ? #ifdef IPV6_RECVHOPLIMIT IPV6_RECVHOPLIMIT #else IPV6_HOPLIMIT #endif : #ifdef IP_RECVTTL IP_RECVTTL; #else IP_TTL; #endif if (setsockopt(sock, level, type, &on, sizeof(on)) != 0) { perror("receiving hop limit/ttl setsockopt()"); return -1; } if (!SetHops(sock, addr, defaultTTL)) { perror("SetHops"); return -1; } if (!ssm && addr.is_multicast()) { if (MulticastListen(sock, addr) != 0) { perror("Failed to join multicast group"); return -1; } } return sock; }
int main(int argc, char **argv) { int res; srand(time(NULL)); char tmp[256]; if (gethostname(tmp, sizeof(tmp)) != 0) { perror("Failed to get hostname"); return -1; } beaconName = tmp; parse_arguments(argc, argv); MulticastStartup(); if (beaconName.empty()) fatal("No name supplied, check `dbeacon -h`."); if (!probeAddrLiteral.empty()) { if (!probeAddr.parse(probeAddrLiteral.c_str(), true)) return -1; probeAddr.to_string(sessionName, sizeof(sessionName)); if (!probeAddr.is_multicast()) fatal("Specified probe addr (%s) is not of a multicast group.", sessionName); if (adminContact.empty()) fatal("No administration contact supplied, check `dbeacon -h`."); mcastListen.push_back(ContentDesc(probeAddr, false)); insert_event(SENDING_EVENT, 100); insert_event(REPORT_EVENT, 10000); insert_event(MAP_REPORT_EVENT, 30000); insert_event(WEBSITE_REPORT_EVENT, 120000); redist.push_back(probeAddr); if (useSSM) { if (probeSSMAddrLiteral.empty()) { int family = forceFamily; if (family == AF_UNSPEC) { family = probeAddr.family(); } if (family == AF_INET) { probeSSMAddrLiteral = defaultIPv4SSMChannel; } else { probeSSMAddrLiteral = defaultIPv6SSMChannel; } } if (!ssmProbeAddr.parse(probeSSMAddrLiteral.c_str(), true)) { fatal("Bad address format for SSM channel."); } else if (!ssmProbeAddr.is_unspecified()) { insert_event(SSM_SENDING_EVENT, 100); insert_event(SSM_REPORT_EVENT, 15000); if (listenForSSM) { mcastListen.push_back(ContentDesc(ssmProbeAddr, true)); } } } } else { if (mcastListen.empty()) fatal("Nothing to do, check `dbeacon -h`."); else strcpy(sessionName, beaconName.c_str()); } address local; local.set_family(probeAddr.family()); mcastSock = SetupSocket(local, false, false); if (mcastSock < 0) return -1; if (beaconUnicastAddr.is_unspecified()) beaconUnicastAddr = get_local_address_for(probeAddr); if (bind(mcastSock, beaconUnicastAddr.saddr(), beaconUnicastAddr.addrlen()) != 0) { perror("Failed to bind local socket"); return -1; } if (beaconUnicastAddr.fromsocket(mcastSock) < 0) { perror("getsockname"); return -1; } for (McastListen::const_iterator i = mcastListen.begin(); i != mcastListen.end(); ++i) { int sock = SetupSocket(i->first, true, i->second); if (sock < 0) return -1; if (i->second) { ListenTo(sock, handle_ssm); ssmMcastSock = sock; } else { ListenTo(sock, handle_asm); } } if (useSSMPing) { if (SetupSSMPing() < 0) d_log(LOG_ERR, "Failed to setup SSM Ping."); else flags |= SSMPING_CAPABLE; } if (IsSSMEnabled()) { flags |= SSM_CAPABLE; uint64_t now = get_timestamp(); for (vector<address>::const_iterator i = ssmBootstrap.begin(); i != ssmBootstrap.end(); ++i) getSource(*i, 0, now, 0, false); } else if (!ssmBootstrap.empty()) d_log(LOG_WARNING, "Tried to bootstrap using SSM when SSM is not enabled."); if (daemonize || use_syslog) { use_syslog = true; openlog("dbeacon", LOG_NDELAY | LOG_PID, LOG_DAEMON); } past_init = true; if (daemonize) { if (dbeacon_daemonize(pidfile)) { perror("Failed to daemon()ize."); return -1; } } // Init timer events insert_event(GARBAGE_COLLECT_EVENT, 30000); if (!dumpFile.empty()) insert_event(DUMP_EVENT, dumpInterval * 1000); insert_event(DUMP_BW_EVENT, 10000); if (dumpBwReport) insert_event(DUMP_BIG_BW_EVENT, 600000); info("Local name is `%s` [Beacon group: %s, Local address: %s]", beaconName.c_str(), sessionName, beaconUnicastAddr.to_string(tmp, sizeof(tmp), false)); send_report(WEBSITE_REPORT_EVENT); signal(SIGUSR1, dumpBigBwStats); signal(SIGINT, sendLeaveReport); signal(SIGTERM, sendLeaveReport); signal(SIGCHLD, waitForMe); // bloody fork, we dont want to wait for thee startTime = lastDumpBwTS = lastDumpDumpBwTS = get_timestamp(); while (1) { fd_set readset; timeval eventm; FD_ZERO(&readset); for (McastSocks::const_iterator i = mcastSocks.begin(); i != mcastSocks.end(); ++i) FD_SET(i->first, &readset); next_event(&eventm); res = select(mcastSocks.rbegin()->first + 1, &readset, 0, 0, &eventm); if (res < 0) { if (errno == EINTR) continue; fatal("Select failed: %s", strerror(errno)); } else { for (McastSocks::const_iterator i = mcastSocks.begin(); res > 0 && i != mcastSocks.end(); ++i) { if (FD_ISSET(i->first, &readset)) { handle_mcast(*i); res--; } } handle_event(); } } return 0; }