Browse Source

[trac999] a prerequisite for resolver ACL: adding a new getSockAddr() method
to IOEndpoint for getting the address information of an endpoint efficiently.

JINMEI Tatuya 14 years ago
parent
commit
42177c3c2d

+ 44 - 0
src/lib/asiolink/io_endpoint.h

@@ -20,6 +20,8 @@
 // See the description of the namespace below.
 #include <unistd.h>             // for some network system calls
 
+#include <sys/socket.h>         // for sockaddr
+
 #include <functional>
 #include <string>
 
@@ -90,6 +92,44 @@ public:
     /// \brief Returns the address family of the endpoint.
     virtual short getFamily() const = 0;
 
+    /// \brief Returns the address of the endpoint in the form of sockaddr
+    /// structure.
+    ///
+    /// The actual instance referenced by the returned value of this method
+    /// is of per address family structure: For IPv4 (AF_INET), it's
+    /// \c sockaddr_in; for IPv6 (AF_INET6), it's \c sockaddr_in6.
+    /// The corresponding port and address members of the underlying structure
+    /// will be set in the network byte order.
+    ///
+    /// This method is "redundant" in that all information to construct the
+    /// \c sockaddr is available via the other "get" methods.
+    /// It is still defined for performance sensitive applications that need
+    /// to get the address information, such as for address based access
+    /// control at a high throughput.  Internally it is implemented with
+    /// minimum overhead such as data copy (this is another reason why this
+    /// method returns a reference).
+    ///
+    /// As a tradeoff, this method is more fragile; it assumes that the
+    /// underlying ASIO implementation stores the address information in
+    /// the form of \c sockaddr and it can be accessed in an efficient way.
+    /// This is the case as of this writing, but if the underlying
+    /// implementation changes this method may become much slower or its
+    /// interface may have to be changed, too.
+    ///
+    /// It is therefore discouraged for normal applications to use this
+    /// method.  Unless the application is very performance sensitive, it
+    /// should use the other "get" method to retrieve specific information
+    /// of the endpoint.
+    ///
+    /// The returned reference is only valid while the corresponding
+    /// \c IOEndpoint is valid.  Once it's destructed the reference will
+    /// become invalid.
+    ///
+    /// \exception None
+    /// \return Reference to a \c sockaddr structure corresponding to the
+    /// endpoint.
+    virtual const struct sockaddr& getSockAddr() const = 0;
+
     bool operator==(const IOEndpoint& other) const;
     bool operator!=(const IOEndpoint& other) const;
 
@@ -121,3 +161,7 @@ public:
 } // namespace asiolink
 } // namespace isc
 #endif // __IO_ENDPOINT_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 8 - 0
src/lib/asiolink/tcp_endpoint.h

@@ -84,6 +84,10 @@ public:
         return (asio_endpoint_.address());
     }
 
+    virtual const struct sockaddr& getSockAddr() const {
+        return (*asio_endpoint_.data());
+    }
+
     virtual uint16_t getPort() const {
         return (asio_endpoint_.port());
     }
@@ -113,3 +117,7 @@ private:
 } // namespace asiolink
 } // namespace isc
 #endif // __TCP_ENDPOINT_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 47 - 0
src/lib/asiolink/tests/io_endpoint_unittest.cc

@@ -15,6 +15,11 @@
 #include <config.h>
 #include <gtest/gtest.h>
 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+
 #include <boost/shared_ptr.hpp>
 
 #include <asiolink/io_endpoint.h>
@@ -194,4 +199,46 @@ TEST(IOEndpointTest, createIPProto) {
                  IOError);
 }
 
+void
+sockAddrMatch(const struct sockaddr& actual_sa,
+              const char* const expected_addr_text,
+              const char* const expected_port_text)
+{
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_DGRAM; // this shouldn't matter
+    hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+    struct addrinfo* res;
+    ASSERT_EQ(0, getaddrinfo(expected_addr_text, expected_port_text, &hints,
+                             &res));
+    EXPECT_EQ(res->ai_family, actual_sa.sa_family);
+#ifdef HAVE_SA_LEN
+    // ASIO doesn't seem to set sa_len, so we set it to the expected value
+    res->ai_addr->sa_len = actual_sa.sa_len;
+#endif
+    EXPECT_EQ(0, memcmp(res->ai_addr, &actual_sa, res->ai_addrlen));
+    free(res);
+}
+
+TEST(IOEndpointTest, getSockAddr) {
+    // UDP/IPv4
+    ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_UDP,
+                                             IOAddress("192.0.2.1"), 53210));
+    sockAddrMatch(ep->getSockAddr(), "192.0.2.1", "53210");
+
+    // UDP/IPv6
+    ep.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::53"), 53));
+    sockAddrMatch(ep->getSockAddr(), "2001:db8::53", "53");
+
+    // TCP/IPv4
+    ep.reset(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 53211));
+    sockAddrMatch(ep->getSockAddr(), "192.0.2.2", "53211");
+
+    // TCP/IPv6
+    ep.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::5300"), 35));
+    sockAddrMatch(ep->getSockAddr(), "2001:db8::5300", "35");
+}
+
 }

+ 8 - 0
src/lib/asiolink/udp_endpoint.h

@@ -84,6 +84,10 @@ public:
         return (asio_endpoint_.address());
     }
 
+    virtual const struct sockaddr& getSockAddr() const {
+        return (*asio_endpoint_.data());
+    }
+
     virtual uint16_t getPort() const {
         return (asio_endpoint_.port());
     }
@@ -113,3 +117,7 @@ private:
 } // namespace asiolink
 } // namespace isc
 #endif // __UDP_ENDPOINT_H
+
+// Local Variables:
+// mode: c++
+// End: