From: Tomek Mrugalski Date: Fri, 22 Jun 2012 13:36:27 +0000 (+0200) Subject: [1708] Data reception over many interfaces (IPv6) added X-Git-Tag: trac2351_base~65^2~34^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ed478d2878ef583a1f37da8a588f70f4bf47a9b9;p=thirdparty%2Fkea.git [1708] Data reception over many interfaces (IPv6) added --- diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec index 05c3529865..2a82a2d3a0 100644 --- a/src/bin/dhcp6/dhcp6.spec +++ b/src/bin/dhcp6/dhcp6.spec @@ -1,6 +1,6 @@ { "module_spec": { - "module_name": "dhcp6", + "module_name": "Dhcp6", "module_description": "DHCPv6 server daemon", "config_data": [ { "item_name": "interface", @@ -9,6 +9,18 @@ "item_default": "eth0" } ], - "commands": [] + "commands": [ + { + "command_name": "shutdown", + "command_description": "Shuts down DHCPv6 server.", + "command_args": [ + { + "item_name": "pid", + "item_type": "integer", + "item_optional": true + } + ] + } + ] } } diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 55a925c1ed..d28d9b7d21 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -79,9 +79,11 @@ void Dhcpv6Srv::shutdown() { bool Dhcpv6Srv::run() { while (!shutdown_) { + /// @todo: calculate actual timeout once we have lease database + int timeout = 1000; // client's message and server's response - Pkt6Ptr query = IfaceMgr::instance().receive6(); + Pkt6Ptr query = IfaceMgr::instance().receive6(timeout); Pkt6Ptr rsp; if (query) { diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 508413dfe8..3167ae039c 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -693,13 +693,12 @@ IfaceMgr::receive4(uint32_t timeout) { const SocketInfo* candidate = 0; IfaceCollection::const_iterator iface; - fd_set sockets; - FD_ZERO(&sockets); int maxfd = 0; - stringstream names; + FD_ZERO(&sockets); + /// @todo: marginal performance optimization. We could create the set once /// and then use its copy for select(). Please note that select() modifies /// provided set to indicated which sockets have something to read. @@ -858,9 +857,108 @@ IfaceMgr::receive4(uint32_t timeout) { return (pkt); } -Pkt6Ptr IfaceMgr::receive6() { - uint8_t buf[RCVBUFSIZE]; +Pkt6Ptr IfaceMgr::receive6(uint32_t timeout) { + + const SocketInfo* candidate = 0; + fd_set sockets; + int maxfd = 0; + stringstream names; + + FD_ZERO(&sockets); + + /// @todo: marginal performance optimization. We could create the set once + /// and then use its copy for select(). Please note that select() modifies + /// provided set to indicated which sockets have something to read. + IfaceCollection::const_iterator iface; + for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) { + + for (SocketCollection::const_iterator s = iface->sockets_.begin(); + s != iface->sockets_.end(); ++s) { + + // Only deal with IPv4 addresses. + if (s->addr_.getFamily() == AF_INET6) { + names << s->sockfd_ << "(" << iface->getName() << ") "; + + // Add this socket to listening set + FD_SET(s->sockfd_, &sockets); + if (maxfd < s->sockfd_) { + maxfd = s->sockfd_; + } + } + } + } + + // if there is session socket registered... + if (session_socket_ != INVALID_SOCKET) { + // at it to the set as well + FD_SET(session_socket_, &sockets); + if (maxfd < session_socket_) + maxfd = session_socket_; + names << session_socket_ << "(session)"; + } + + cout << "Trying to receive data on sockets:" << names.str() + << ".Timeout is " << timeout << " seconds." << endl; + + /// @todo: implement sub-second precision one day + struct timeval select_timeout; + select_timeout.tv_sec = timeout; + select_timeout.tv_usec = 0; + + int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout); + + if (result == 0) { + // nothing received and timeout has been reached + return (Pkt6Ptr()); // NULL + } else if (result < 0) { + cout << "Socket read error: " << strerror(errno) << endl; + + /// @todo: perhaps throw here? + return (Pkt6Ptr()); // NULL + } + + // Let's find out which socket has the data + if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) { + // something received over session socket + cout << "BIND10 command or config available over session socket." << endl; + + if (session_callback_) { + // in theory we could call io_service.run_one() here, instead of + // implementing callback mechanism, but that would introduce + // asiolink dependency to libdhcp++ and that is something we want + // to avoid (see CPE market and out long term plans for minimalistic + // implementations. + session_callback_(); + } + + return (Pkt6Ptr()); // NULL + } + + // Let's find out which interface/socket has the data + for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) { + for (SocketCollection::const_iterator s = iface->sockets_.begin(); + s != iface->sockets_.end(); ++s) { + if (FD_ISSET(s->sockfd_, &sockets)) { + candidate = &(*s); + break; + } + } + if (candidate) { + break; + } + } + if (!candidate) { + cout << "Received data over unknown socket." << endl; + return (Pkt6Ptr()); // NULL + } + + cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to " + << candidate->addr_.toText() << "/port=" << candidate->port_ << " on " + << iface->getFullName() << endl; + + // Now we have a socket, let's get some data from it! + uint8_t buf[RCVBUFSIZE]; memset(&control_buf_[0], 0, control_buf_len_); struct sockaddr_in6 from; memset(&from, 0, sizeof(from)); @@ -892,43 +990,7 @@ Pkt6Ptr IfaceMgr::receive6() { m.msg_control = &control_buf_[0]; m.msg_controllen = control_buf_len_; - /// TODO: Need to move to select() and pool over - /// all available sockets. For now, we just take the - /// first interface and use first socket from it. - IfaceCollection::const_iterator iface = ifaces_.begin(); - const SocketInfo* candidate = 0; - while (iface != ifaces_.end()) { - for (SocketCollection::const_iterator s = iface->sockets_.begin(); - s != iface->sockets_.end(); ++s) { - if (s->addr_.getFamily() != AF_INET6) { - continue; - } - if (s->addr_.getAddress().to_v6().is_multicast()) { - candidate = &(*s); - break; - } - if (!candidate) { - candidate = &(*s); // it's not multicast, but it's better than nothing - } - } - if (candidate) { - break; - } - ++iface; - } - if (iface == ifaces_.end()) { - isc_throw(Unexpected, "No suitable IPv6 interfaces detected. Can't receive anything."); - } - - if (!candidate) { - isc_throw(Unexpected, "Interface " << iface->getFullName() - << " does not have any sockets open."); - } - - cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to " - << candidate->addr_.toText() << "/port=" << candidate->port_ << " on " - << iface->getFullName() << endl; - int result = recvmsg(candidate->sockfd_, &m, 0); + result = recvmsg(candidate->sockfd_, &m, 0); struct in6_addr to_addr; memset(&to_addr, 0, sizeof(to_addr)); diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index 7fa2e855f4..48f43a6507 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -345,8 +345,10 @@ public: /// to not wait infinitely, but rather do something useful /// (e.g. remove expired leases) /// + /// @param timeout specifies timeout (in seconds) + /// /// @return Pkt6 object representing received packet (or NULL) - Pkt6Ptr receive6(); + Pkt6Ptr receive6(uint32_t timeout); /// @brief Tries to receive IPv4 packet over open IPv4 sockets. /// diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index e7ccb680ba..df74d93eba 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -309,7 +309,7 @@ TEST_F(IfaceMgrTest, sendReceive6) { EXPECT_EQ(true, ifacemgr->send(sendPkt)); - rcvPkt = ifacemgr->receive6(); + rcvPkt = ifacemgr->receive6(10); ASSERT_TRUE(rcvPkt); // received our own packet