Browse Source

[1539] supported operator<< for IOEndpoint for unified logging format.

the formatEndpoint() function locally defined in auth_srv was essentially
moved there.  also added the test of the operator.
JINMEI Tatuya 13 years ago
parent
commit
3aa296cf17

+ 2 - 21
src/bin/auth/auth_srv.cc

@@ -17,6 +17,7 @@
 #include <util/io/socketsession.h>
 
 #include <asiolink/asiolink.h>
+#include <asiolink/io_endpoint.h>
 
 #include <config/ccsession.h>
 
@@ -112,8 +113,6 @@ private:
     MessageRenderer& renderer_;
 };
 
-string formatEndpoint(const IOEndpoint& ep); // forward declaration to keep the diff minimum.
-
 // A helper container of socket session forwarder.
 //
 // This class provides a simple wrapper interface to SocketSessionForwarder
@@ -177,8 +176,7 @@ public:
                             io_message.getData(), io_message.getDataSize());
         } catch (const SocketSessionError& ex) {
             LOG_ERROR(auth_logger, AUTH_MESSAGE_FORWARD_ERROR).
-                arg(message_name_).arg(formatEndpoint(remote_ep)).
-                arg(ex.what());
+                arg(message_name_).arg(remote_ep).arg(ex.what());
             close();
             throw;
         }
@@ -215,23 +213,6 @@ private:
         }
     }
 };
-
-// A helper function to log an address/port in the form of IOEndpoint
-// in our preferred format: [<ipv6_addr>]:port or <ipv4_addr>:port
-string
-formatEndpoint(const IOEndpoint& ep) {
-    string addr_port;
-    if (ep.getFamily() == AF_INET6) {
-        addr_port = "[" + ep.getAddress().toText() + "]";
-    } else if (ep.getFamily() == AF_INET) {
-        addr_port = ep.getAddress().toText();
-    } else {
-        addr_port = "(unknown address)";
-    }
-    addr_port += ":" + boost::lexical_cast<string>(ep.getPort());
-
-    return (addr_port);
-}
 }
 
 class AuthSrvImpl {

+ 20 - 4
src/lib/asiolink/io_endpoint.cc

@@ -14,10 +14,6 @@
 
 #include <config.h>
 
-#include <unistd.h>             // for some IPC/network system calls
-#include <sys/socket.h>
-#include <netinet/in.h>
-
 #include <asio.hpp>
 
 #include <asiolink/io_address.h>
@@ -26,6 +22,13 @@
 #include <asiolink/tcp_endpoint.h>
 #include <asiolink/udp_endpoint.h>
 
+#include <boost/lexical_cast.hpp>
+
+#include <cassert>
+#include <unistd.h>             // for some IPC/network system calls
+#include <sys/socket.h>
+#include <netinet/in.h>
+
 using namespace std;
 
 namespace isc {
@@ -58,5 +61,18 @@ IOEndpoint::operator!=(const IOEndpoint& other) const {
     return (!operator==(other));
 }
 
+ostream&
+operator<<(ostream& os, const IOEndpoint& endpoint) {
+    if (endpoint.getFamily() == AF_INET6) {
+        os << "[" << endpoint.getAddress().toText() << "]";
+    } else {
+        // In practice this should be AF_INET, but it's not guaranteed by
+        // the interface.  We'll use the result of textual address
+        // representation opaquely.
+        os << endpoint.getAddress().toText();
+    }
+    os << ":" << boost::lexical_cast<string>(endpoint.getPort());
+    return (os);
+}
 } // namespace asiolink
 } // namespace isc

+ 27 - 3
src/lib/asiolink/io_endpoint.h

@@ -18,9 +18,6 @@
 // IMPORTANT NOTE: only very few ASIO headers files can be included in
 // this file.  In particular, asio.hpp should never be included here.
 // 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>
@@ -28,6 +25,12 @@
 #include <exceptions/exceptions.h>
 #include <asiolink/io_address.h>
 
+# include <ostream>
+
+#include <unistd.h>             // for some network system calls
+
+#include <sys/socket.h>         // for sockaddr
+
 namespace isc {
 namespace asiolink {
 
@@ -158,6 +161,27 @@ public:
                                     const unsigned short port);
 };
 
+/// \brief Insert the \c IOEndpoint as a string into stream.
+///
+/// This method converts \c endpoint into a string and inserts it into the
+/// output stream \c os.
+///
+/// This method converts the address and port of the endpoint in the textual
+/// format that other BIND 10 modules would use in logging, i.e.,
+/// - For IPv6 address: [<address>]:port (e.g., [2001:db8::5300]:53)
+/// - For IPv4 address: <address>:port (e.g., 192.0.2.53:5300)
+///
+/// If it's neither IPv6 nor IPv4, it converts the endpoint into text in the
+/// same format as that for IPv4, although in practice such a case is not
+/// really expected.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param endpoint A reference to an \c IOEndpoint object output by the
+/// operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const IOEndpoint& endpoint);
 } // namespace asiolink
 } // namespace isc
 #endif // __IO_ENDPOINT_H

+ 53 - 5
src/lib/asiolink/tests/io_endpoint_unittest.cc

@@ -13,18 +13,22 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config.h>
+
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_error.h>
+
 #include <gtest/gtest.h>
 
+#include <boost/shared_ptr.hpp>
+
+#include <sstream>
+#include <string>
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <string.h>
 
-#include <boost/shared_ptr.hpp>
-
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_error.h>
-
 using namespace isc::asiolink;
 
 namespace {
@@ -240,4 +244,48 @@ TEST(IOEndpointTest, getSockAddr) {
     sockAddrMatch(ep->getSockAddr(), "2001:db8::5300", "35");
 }
 
+// A faked IOEndpoint for an uncommon address family.  It wouldn't be possible
+// to create via the normal factory, so we define a special derived class
+// for it.
+class TestIOEndpoint : public IOEndpoint {
+    virtual IOAddress getAddress() const {
+        return IOAddress("2001:db8::bad:add");
+    }
+    virtual uint16_t getPort() const { return (42); }
+    virtual short getProtocol() const { return (IPPROTO_UDP); }
+    virtual short getFamily() const { return (AF_UNSPEC); }
+    virtual const struct sockaddr& getSockAddr() const {
+        static struct sockaddr sa_placeholder;
+        return (sa_placeholder);
+    }
+};
+
+void
+checkEndpointText(const std::string& expected, const IOEndpoint& ep) {
+    std::ostringstream oss;
+    oss << ep;
+    EXPECT_EQ(expected, oss.str());
+}
+
+// test operator<<.  We simply confirm it appends the result of toText().
+TEST(IOEndpointTest, LeftShiftOperator) {
+    // UDP/IPv4
+    ConstIOEndpointPtr ep(IOEndpoint::create(IPPROTO_UDP,
+                                             IOAddress("192.0.2.1"), 53210));
+    checkEndpointText("192.0.2.1:53210", *ep);
+
+    // UDP/IPv6
+    ep.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::53"), 53));
+    checkEndpointText("[2001:db8::53]:53", *ep);
+
+    // Same for TCP: shouldn't be different
+    ep.reset(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 53210));
+    checkEndpointText("192.0.2.1:53210", *ep);
+    ep.reset(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::53"), 53));
+    checkEndpointText("[2001:db8::53]:53", *ep);
+
+    // Uncommon address family.  The actual behavior doesn't matter much
+    // in practice, but we check such input doesn't make it crash.
+    checkEndpointText("2001:db8::bad:add:42", TestIOEndpoint());
+}
 }