Browse Source

[1239] OpenSockets4() and receive4() implemented in IfaceMgr.

Tomek Mrugalski 13 years ago
parent
commit
084c9790ef
5 changed files with 207 additions and 15 deletions
  1. 6 3
      src/bin/dhcp4/dhcp4_srv.cc
  2. 1 1
      src/bin/dhcp6/dhcp6_srv.cc
  3. 185 7
      src/lib/dhcp/iface_mgr.cc
  4. 13 2
      src/lib/dhcp/iface_mgr.h
  5. 2 2
      src/lib/dhcp/pkt4.cc

+ 6 - 3
src/bin/dhcp4/dhcp4_srv.cc

@@ -31,6 +31,9 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
     IfaceMgr::instance();
 
     /// @todo: instantiate LeaseMgr here once it is imlpemented.
+    IfaceMgr::instance().printIfaces();
+
+    IfaceMgr::instance().openSockets4();
 
     setServerID();
 
@@ -47,7 +50,7 @@ Dhcpv4Srv::run() {
         boost::shared_ptr<Pkt4> query; // client's message
         boost::shared_ptr<Pkt4> rsp;   // server's response
 
-#if 0
+#if 1
         // uncomment this once ticket 1239 is merged.
         query = IfaceMgr::instance().receive4();
 #endif
@@ -99,9 +102,9 @@ Dhcpv4Srv::run() {
                 if (rsp->pack()) {
                     cout << "Packet assembled correctly." << endl;
                 }
-#if 0
+#if 1
                 // uncomment this once ticket 1240 is merged.
-                IfaceMgr::instance().send4(rsp);
+                IfaceMgr::instance().send(rsp);
 #endif
             }
         }

+ 1 - 1
src/bin/dhcp6/dhcp6_srv.cc

@@ -36,7 +36,7 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
     IfaceMgr::instance();
 
     // Now try to open IPv6 sockets on detected interfaces.
-    IfaceMgr::instance().openSockets(port);
+    IfaceMgr::instance().openSockets6(port);
 
     /// @todo: instantiate LeaseMgr here once it is imlpemented.
 

+ 185 - 7
src/lib/dhcp/iface_mgr.cc

@@ -18,6 +18,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include <dhcp/dhcp4.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
@@ -191,9 +192,52 @@ IfaceMgr::detectIfaces() {
     }
 }
 
-void
-IfaceMgr::openSockets(uint16_t port) {
+bool IfaceMgr::openSockets4(uint16_t port) {
+    int sock;
+    int count = 0;
+
+    for (IfaceCollection::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+
+        cout << "Trying interface " << iface->getFullName() << endl;
+
+#if 0
+        // uncomment when trac1237 (interface detection) is merged
+        if (iface->flag_loopback_ ||
+            !iface->flag_up_ ||
+            !iface->flag_running_) {
+            continue;
+        }
+#endif
+
+        AddressCollection addrs = iface->getAddresses();
+
+        for (AddressCollection::iterator addr= addrs.begin();
+             addr != addrs.end();
+             ++addr) {
+
+            // skip IPv4 addresses
+            if (addr->getFamily() != AF_INET) {
+                continue;
+            }
+
+            sock = openSocket(iface->getName(), *addr, port);
+            if (sock<0) {
+                cout << "Failed to open unicast socket." << endl;
+                return (false);
+            }
+
+            count++;
+        }
+    }
+    return (count > 0);
+
+}
+
+bool IfaceMgr::openSockets6(uint16_t port) {
     int sock1, sock2;
+    int count = 0;
 
     for (IfaceCollection::iterator iface = ifaces_.begin();
          iface != ifaces_.end(); ++iface) {
@@ -228,6 +272,8 @@ IfaceMgr::openSockets(uint16_t port) {
             }
         }
     }
+
+    return (count > 0);
 }
 
 void
@@ -514,10 +560,138 @@ IfaceMgr::send(boost::shared_ptr<Pkt4>& )
 
 boost::shared_ptr<Pkt4>
 IfaceMgr::receive4() {
-    isc_throw(NotImplemented, "Pkt4 reception not implemented yet.");
 
-    // TODO: To be implemented (ticket #1239)
-    return (boost::shared_ptr<Pkt4>()); // NULL
+    const SocketInfo* candidate = 0;
+    IfaceCollection::const_iterator iface;
+    for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
+
+#if 0
+        // uncomment when trac1237 (interface detection) is merged
+        // Let's skip loopback and downed interfaces.
+        if (iface->flag_loopback_ ||
+            !iface->flag_up_ ||
+            !iface->flag_running_) {
+            continue;
+        }
+#endif
+
+        SocketCollection::const_iterator s = iface->sockets_.begin();
+        while (s != iface->sockets_.end()) {
+
+            // We don't want IPv6 addresses here.
+            if (s->addr_.getFamily() != AF_INET) {
+                ++s;
+                continue;
+            }
+
+            // This address looks good.
+            if (!candidate) {
+                candidate = &(*s);
+                break;
+            }
+
+            ++s;
+        }
+
+        if (candidate) {
+            break;
+        }
+    }
+
+    if (!candidate) {
+        isc_throw(Unexpected, "Failed to find any suitable sockets on all interfaces.");
+    }
+
+    cout << "Trying to receive over UDP4 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!
+
+    struct msghdr m;
+    struct iovec v;
+    int result;
+    struct cmsghdr* cmsg;
+    struct in_pktinfo* pktinfo;
+    struct sockaddr_in from_addr;
+    struct in_addr to_addr;
+    unsigned int ifindex = 0;
+    boost::shared_ptr<Pkt4> pkt;
+    const uint32_t RCVBUFSIZE = 1500;
+    uint8_t buf[RCVBUFSIZE];
+
+    memset(&control_buf_[0], 0, control_buf_len_);
+    memset(&from_addr, 0, sizeof(from_addr));
+    memset(&to_addr, 0, sizeof(to_addr));
+
+    // Initialize our message header structure.
+    memset(&m, 0, sizeof(m));
+
+    // Point so we can get the from address.
+    m.msg_name = &from_addr;
+    m.msg_namelen = sizeof(from_addr);
+
+    v.iov_base = (void*)buf;
+    v.iov_len = RCVBUFSIZE;
+    m.msg_iov = &v;
+    m.msg_iovlen = 1;
+
+    /*
+     * Getting the interface is a bit more involved.
+     *
+     * We set up some space for a "control message". We have
+     * previously asked the kernel to give us packet
+     * information (when we initialized the interface), so we
+     * should get the destination address from that.
+     */
+    m.msg_control = &control_buf_[0];
+    m.msg_controllen = control_buf_len_;
+
+    result = recvmsg(candidate->sockfd_, &m, 0);
+
+    if (result < 0) {
+        cout << "Failed to receive UDP4 data." << endl;
+        return (boost::shared_ptr<Pkt4>()); // NULL
+    }
+
+    int found_pktinfo = 0;
+    cmsg = CMSG_FIRSTHDR(&m);
+    while (cmsg != NULL) {
+        if ((cmsg->cmsg_level == IPPROTO_IP) &&
+            (cmsg->cmsg_type == IP_PKTINFO)) {
+            pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+
+            ifindex = pktinfo->ipi_ifindex;
+            to_addr = pktinfo->ipi_addr;
+            // to_addr = pktinfo->ipi_spec_dst;
+            found_pktinfo = 1;
+        }
+        cmsg = CMSG_NXTHDR(&m, cmsg);
+    }
+    if (!found_pktinfo) {
+        cout << "Unable to find pktinfo" << endl;
+        return (boost::shared_ptr<Pkt4>()); // NULL
+    }
+
+    IOAddress to(htonl(to_addr.s_addr));
+    IOAddress from(htonl(from_addr.sin_addr.s_addr));
+    uint16_t from_port = htons(from_addr.sin_port);
+
+    cout << "Received " << result << " bytes from " << from.toText()
+         << "/port=" << from_port
+         << " sent to " << to.toText() << " over interface "
+         << iface->getFullName() << endl;
+
+    // we have all data let's create Pkt4 object
+    pkt = boost::shared_ptr<Pkt4>(new Pkt4(buf, result));
+
+
+    pkt->setLocalAddr(to);
+    pkt->setRemotePort(from_port);
+    pkt->setLocalPort(candidate->port_);
+    // pkt->setRemoteAddr(from);
+
+    return (pkt);
 }
 
 boost::shared_ptr<Pkt6>
@@ -585,12 +759,16 @@ IfaceMgr::receive6() {
     SocketCollection::const_iterator s = iface->sockets_.begin();
     const SocketInfo* candidate = 0;
     while (s != iface->sockets_.end()) {
+        if (s->addr_.getFamily() != AF_INET6) {
+            ++s;
+            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 none
+            candidate = &(*s); // it's not multicast, but it's better than nothing
         }
         ++s;
     }
@@ -599,7 +777,7 @@ IfaceMgr::receive6() {
                   << " does not have any sockets open.");
     }
 
-    cout << "Trying to receive over socket " << candidate->sockfd_ << " bound to "
+    cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to "
          << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
          << iface->getFullName() << endl;
     result = recvmsg(candidate->sockfd_, &m, 0);

+ 13 - 2
src/lib/dhcp/iface_mgr.h

@@ -20,6 +20,8 @@
 #include <boost/scoped_array.hpp>
 #include <boost/noncopyable.hpp>
 #include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt6.h>
 
@@ -299,13 +301,22 @@ public:
     /// Will throw exception if socket creation fails.
     ///
     /// @param port specifies port number (usually DHCP6_SERVER_PORT)
-    void openSockets(uint16_t port);
-
+    ///
+    /// @return true if any sockets were open
+    bool openSockets6(uint16_t port = DHCP6_SERVER_PORT);
 
     /// @brief Closes all open sockets.
     /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
     void closeSockets();
 
+    /// Opens IPv4 sockets on detected interfaces.
+    /// Will throw exception if socket creation fails.
+    ///
+    /// @param port specifies port number (usually DHCP6_SERVER_PORT)
+    ///
+    /// @return true if any sockets were open
+    bool openSockets4(uint16_t port = DHCP4_SERVER_PORT);
+
     // don't use private, we need derived classes in tests
 protected:
 

+ 2 - 2
src/lib/dhcp/pkt4.cc

@@ -77,8 +77,8 @@ Pkt4::Pkt4(const uint8_t* data, size_t len)
 {
     if (len < DHCPV4_PKT_HDR_LEN) {
         isc_throw(OutOfRange, "Truncated DHCPv4 packet (len=" << len
-                  << " received, at least " << DHCPV4_PKT_HDR_LEN
-                  << "is expected");
+                  << ") received, at least " << DHCPV4_PKT_HDR_LEN
+                  << " is expected.");
     }
 
     data_.resize(len);