Implement INet6SocketAddress
g0dil [Wed, 14 Feb 2007 21:03:09 +0000 (21:03 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@199 270642c3-0616-0410-b53a-bc976706d245

Socket/GenericSockAddr.cci
Socket/INetAddressing.cc
Socket/INetAddressing.cci
Socket/INetAddressing.hh
Socket/INetAddressing.test.cc
run-test-gdb.sh

index 81907cc..6bec2e2 100644 (file)
@@ -1,8 +1,25 @@
-// $Id$
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
 //
-// Copyright (C) 2006 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-// Definition of inline non-template functions
+/** \file
+    \brief GenericSockAddr inline non-template implementation */
 
 // Custom includes
 
index d96bd93..b1efabc 100644 (file)
 #include <sstream>
 #include <string.h>
 #include <sys/socket.h>
+#include <net/if.h>
 #include <boost/lexical_cast.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/range.hpp>
 
 //#include "INetAddressing.mpp"
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
+///////////////////////////////////////////////////////////////////////////
+// senf::INet4Address
+
 prefix_ senf::INet4Address::INet4Address(std::string host, unsigned port)
 {
     clear();
@@ -79,6 +85,149 @@ prefix_ void senf::INet4Address::assignString(std::string address)
     }
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::INet6Address
+
+prefix_ senf::INet6Address::INet6Address(std::string const & addr)
+{
+    if (inet_pton(AF_INET6,addr.c_str(),&addr_) <= 0)
+       throw InvalidINetAddressException();
+}
+
+prefix_ senf::INet6Address::INet6Address(char const * addr)
+{
+    if (inet_pton(AF_INET6,addr,&addr_) <= 0)
+       throw InvalidINetAddressException();
+}
+
+prefix_ void senf::INet6Address::clear()
+{
+    ::memset(&addr_,0,sizeof(addr_));
+}
+
+prefix_ std::string senf::INet6Address::address()
+    const
+{
+    char buffer[8*5];
+    BOOST_ASSERT( inet_ntop(AF_INET6, &addr_, buffer, sizeof(buffer)) );
+    return std::string(buffer);
+}
+
+prefix_ bool senf::INet6Address::operator==(INet6Address const & other)
+    const
+{
+    return ::memcmp(&addr_,&other.addr_,sizeof(addr_))==0;
+}
+
+prefix_ bool senf::INet6Address::operator!=(INet6Address const & other)
+    const
+{
+    return !operator==(other);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::INet6SocketAddress
+
+prefix_ bool senf::INet6SocketAddress::operator==(INet6SocketAddress const & other)
+    const
+{
+    return ::memcmp(&sockaddr_.sin6_addr, &other.sockaddr_.sin6_addr, sizeof(sockaddr_.sin6_addr))==0 &&
+       sockaddr_.sin6_port == other.sockaddr_.sin6_port && 
+       sockaddr_.sin6_scope_id == other.sockaddr_.sin6_scope_id;
+}
+
+prefix_ bool senf::INet6SocketAddress::operator!=(INet6SocketAddress const & other)
+    const
+{
+    return ! operator==(other);
+}
+
+prefix_ void senf::INet6SocketAddress::clear()
+{
+    ::memset(&sockaddr_,0,sizeof(sockaddr_));
+    sockaddr_.sin6_family = AF_INET6;
+}
+
+prefix_ void senf::INet6SocketAddress::address(std::string const & addr)
+{
+    if (addr[0]=='[')
+       assignAddr(addr);
+    else
+       host(addr);
+}
+
+prefix_ std::string senf::INet6SocketAddress::address()
+    const
+{
+    std::stringstream ss;
+    ss << '[' << host();
+    if (sockaddr_.sin6_scope_id != 0)
+       ss << '@' << iface()
+    << "]:" << port();
+    return ss.str();
+}
+
+prefix_ std::string senf::INet6SocketAddress::iface()
+    const
+{
+    if (sockaddr_.sin6_scope_id == 0)
+       return "";
+    char buffer[IFNAMSIZ];
+    BOOST_ASSERT( if_indextoname(sockaddr_.sin6_scope_id,buffer) );
+    return std::string(buffer);
+}
+
+prefix_ void senf::INet6SocketAddress::assignAddr(std::string const & addr)
+{
+    // Format of addr: "[" address [ "@" interface ] "]" ":" port
+    typedef boost::char_separator<char> separator;
+    typedef boost::tokenizer<separator> tokenizer;
+    // we don't add ':' to the list of separators since that would give as the IPv6 address
+    // as a list of tokens. We just strip the : from the port number manually
+    separator sep ("", "@[]"); 
+    tokenizer tokens (addr, sep);
+    tokenizer::iterator token (tokens.begin());
+    if (token == tokens.end() 
+       || *token != "["
+       || ++token == tokens.end()
+       || inet_pton(AF_INET6, std::string(boost::begin(*token),boost::end(*token)).c_str(), 
+                    &sockaddr_.sin6_addr) <= 0
+       || ++token == tokens.end())
+       throw InvalidINetAddressException();
+    if (*token == "@") {
+       if (++token == tokens.end())
+           throw InvalidINetAddressException();
+       assignIface(std::string(boost::begin(*token),boost::end(*token)));
+       if (++token == tokens.end()
+           || *token != "]")
+           throw InvalidINetAddressException();
+    } else if (*token != "]")
+       throw InvalidINetAddressException();
+    if (++token == tokens.end()
+       || *boost::begin(*token) != ':')
+       throw InvalidINetAddressException();
+    try {
+       sockaddr_.sin6_port = htons(
+           boost::lexical_cast<unsigned>(std::string(boost::next(boost::begin(*token)),
+                                                     boost::end(*token))));
+    } catch(boost::bad_lexical_cast const &) {
+       throw InvalidINetAddressException();
+    }
+    if (++token != tokens.end())
+       throw InvalidINetAddressException();
+}
+
+prefix_ void senf::INet6SocketAddress::assignIface(std::string const & iface)
+{
+    if (iface.empty())
+       sockaddr_.sin6_scope_id = 0;
+    else {
+       sockaddr_.sin6_scope_id = if_nametoindex(iface.c_str());
+       if (sockaddr_.sin6_scope_id == 0)
+           throw InvalidINetAddressException();
+    }
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "INetAddressing.mpp"
index 688cbb5..f7e5b77 100644 (file)
@@ -30,6 +30,9 @@
 #define prefix_ inline
 ///////////////////////////////cci.p///////////////////////////////////////
 
+///////////////////////////////////////////////////////////////////////////
+// senf::INet4Address
+
 prefix_ senf::INet4Address::INet4Address()
 {
     clear();
@@ -88,6 +91,147 @@ prefix_ std::ostream & senf::operator<<(std::ostream & os, INet4Address const &
     return os;
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::INet6Address
+
+prefix_ senf::INet6Address::INet6Address()
+{
+    clear();
+}
+
+prefix_ senf::INet6Address::INet6Address(struct in6_addr const & addr)
+{
+    addr_ = addr;
+}
+
+prefix_ struct in6_addr & senf::INet6Address::addr()
+{
+    return addr_;
+}
+
+prefix_ struct in6_addr const & senf::INet6Address::addr()
+    const
+{
+    return addr_;
+}
+
+prefix_ struct in6_addr * senf::INet6Address::addr_p()
+{
+    return & addr_;
+}
+
+prefix_ struct in6_addr const * senf::INet6Address::addr_p()
+    const
+{
+    return & addr_;
+}
+
+prefix_ unsigned senf::INet6Address::addr_len()
+    const
+{
+    return sizeof(addr_);
+}
+
+prefix_ std::ostream & senf::operator<<(std::ostream & os, INet6Address const & addr)
+{
+    os << addr.address();
+    return os;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::INet6SocketAddress
+
+prefix_ senf::INet6SocketAddress::INet6SocketAddress()
+{
+    clear();
+}
+
+prefix_ senf::INet6SocketAddress::INet6SocketAddress(std::string const & addr)
+{
+    clear();
+    assignAddr(addr);
+}
+
+prefix_ senf::INet6SocketAddress::INet6SocketAddress(char const * addr)
+{
+    clear();
+    assignAddr(addr);
+}
+
+prefix_ senf::INet6SocketAddress::INet6SocketAddress(INet6Address const & addr, unsigned port)
+{
+    clear();
+    sockaddr_.sin6_addr = addr.addr();
+    sockaddr_.sin6_port = htons(port);
+}
+
+prefix_ senf::INet6SocketAddress::INet6SocketAddress(INet6Address const & addr, unsigned port,
+                                                     std::string const & iface)
+{
+    clear();
+    sockaddr_.sin6_addr = addr.addr();
+    sockaddr_.sin6_port = htons(port);
+    assignIface(iface);
+}
+
+prefix_ senf::INet6SocketAddress::INet6SocketAddress(std::string const & addr,
+                                                     std::string const & iface)
+{
+    clear();
+    assignAddr(addr);
+    assignIface(iface);
+}
+
+prefix_ senf::INet6Address senf::INet6SocketAddress::host()
+    const
+{
+    return INet6Address(sockaddr_.sin6_addr);
+}
+
+prefix_ void senf::INet6SocketAddress::host(INet6Address const & addr)
+{
+    sockaddr_.sin6_addr = addr.addr();
+}
+
+prefix_ unsigned senf::INet6SocketAddress::port()
+    const
+{
+    return ntohs(sockaddr_.sin6_port);
+}
+
+prefix_ void senf::INet6SocketAddress::port(unsigned port)
+{
+    sockaddr_.sin6_port = htons(port);
+}
+
+prefix_ void senf::INet6SocketAddress::iface(std::string const & iface)
+{
+    assignIface(iface);
+}
+
+prefix_ struct sockaddr * senf::INet6SocketAddress::sockaddr_p()
+{
+    return reinterpret_cast<struct sockaddr *>(&sockaddr_);
+}
+
+prefix_ struct sockaddr const * senf::INet6SocketAddress::sockaddr_p()
+    const
+{
+    return reinterpret_cast<struct sockaddr const *>(&sockaddr_);
+}
+
+prefix_ unsigned senf::INet6SocketAddress::sockaddr_len()
+    const
+{
+    return sizeof(sockaddr_);
+}
+
+prefix_ std::ostream & senf::operator<<(std::ostream & os, INet6SocketAddress const & addr)
+{
+    os << addr.address();
+    return os;
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
index d87f71f..d97c83c 100644 (file)
@@ -105,14 +105,118 @@ namespace senf {
      */
     std::ostream & operator<<(std::ostream & os, INet4Address const & addr);
 
-    /** \brief IPv6 socket address
+    /** \brief IPv6 network address
 
        \todo Implement
      */
     class INet6Address
     {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        INet6Address();
+        INet6Address(std::string const & addr);
+       INet6Address(char const * addr);
+       INet6Address(struct in6_addr const & addr);
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+       void clear();
+       std::string address() const;
+
+       bool operator==(INet6Address const & other) const;
+       bool operator!=(INet6Address const & other) const;
+
+       struct in6_addr & addr();
+       struct in6_addr const & addr() const;
+       struct in6_addr * addr_p();
+       struct in6_addr const * addr_p() const;
+       unsigned addr_len() const;
+
+    protected:
+
+    private:
+       struct in6_addr addr_;
+    };
+
+    std::ostream & operator<<(std::ostream & os, INet6Address const & addr);
+
+    /** \brief IPv6 socket address
+
+       \implementation The sockaddr_in6 structure has an sin6_flowinfo member. However RFC3493 does
+       not give the use of this field and specifies, that the field should be ignored ... so that's
+       what we do. Furthermore, the GNU libc reference states, that this field is not implemented
+       in the library.
+
+       \idea Implement a INet6Address_ref class which has an interface identical to INet6Address
+       and is convertible to INet6Address (the latter has a conversion constructor taking the
+       former as arg). This class however references an external in6_addr instead of containing one
+       itself. This can be used in INet6SocketAddress to increase the performance of some
+       operations.
+     */
+    class INet6SocketAddress
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        INet6SocketAddress();
+        INet6SocketAddress(std::string const & addr);
+        INet6SocketAddress(char const * addr);
+       INet6SocketAddress(INet6Address const & addr, unsigned port);
+       INet6SocketAddress(INet6Address const & addr, unsigned port, std::string const & iface);
+       INet6SocketAddress(std::string const & addr, std::string const & iface);
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+       bool operator==(INet6SocketAddress const & other) const;
+       bool operator!=(INet6SocketAddress const & other) const;
+
+       void clear();
+
+       std::string address() const;
+       void address(std::string const & addr);
+
+       INet6Address host() const;
+       void host(INet6Address const & addr);
+       
+       unsigned port() const;
+       void port(unsigned poirt);
+       
+       std::string iface() const;
+       void iface(std::string const & iface);
+       
+        ///\name Generic SocketAddress interface
+        ///@{
+
+        struct sockaddr * sockaddr_p();
+        struct sockaddr const * sockaddr_p() const;
+        unsigned sockaddr_len() const;
+
+        ///@}
+
+    protected:
+
+    private:
+       void assignAddr(std::string const & addr);
+       void assignIface(std::string const & iface);
+
+       struct sockaddr_in6 sockaddr_;
     };
 
+    std::ostream & operator<<(std::ostream & os, INet6SocketAddress const & addr);
+
     /** \brief Signal invalid INet address syntax
 
        \related INet4Address
@@ -164,9 +268,16 @@ namespace senf {
 
        \todo implement
      */
-    struct INet6AddressingPolicy : public AddressingPolicyBase
+    struct INet6AddressingPolicy
+        : public AddressingPolicyBase,
+          private GenericAddressingPolicy<INet6SocketAddress>
     {
-        typedef INet6Address Address;
+        typedef INet6SocketAddress Address;
+
+        using GenericAddressingPolicy<INet6SocketAddress>::peer;
+        using GenericAddressingPolicy<INet6SocketAddress>::local;
+        using GenericAddressingPolicy<INet6SocketAddress>::connect;
+        using GenericAddressingPolicy<INet6SocketAddress>::bind;
     };
 
     /// @}
index 04b6600..2b8f9d3 100644 (file)
@@ -77,6 +77,80 @@ BOOST_AUTO_UNIT_TEST(inet4Address)
 
 BOOST_AUTO_UNIT_TEST(inet6Address)
 {
+    using senf::INet6Address;
+    using senf::INet6SocketAddress;
+    using senf::InvalidINetAddressException;
+
+    {
+       INet6Address addr1 ("0102:0304:0506:0708:090A:0B0C:0D0E:0F00");
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[0], 1 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[1], 2 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[2], 3 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[3], 4 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[4], 5 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[5], 6 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[6], 7 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[7], 8 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[8], 9 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[9], 10 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[10], 11 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[11], 12 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[12], 13 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[13], 14 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[14], 15 );
+       BOOST_CHECK_EQUAL( addr1.addr().s6_addr[15], 0 );
+       INet6Address addr2;
+       BOOST_CHECK_EQUAL( addr2, "::" );
+       addr2 = "::1";
+       BOOST_CHECK( addr1 != addr2 );
+       addr1 ="::1";
+       BOOST_CHECK_EQUAL( addr1, addr2 );
+       BOOST_CHECK_EQUAL( addr1.address(),"::1" );
+       addr1.clear();
+       addr2 = "::";
+       BOOST_CHECK_EQUAL( addr1, addr2 );
+       BOOST_CHECK_THROW( addr1 = "", InvalidINetAddressException );
+       BOOST_CHECK_EQUAL( boost::lexical_cast<std::string>(addr1), "::" );
+    }
+
+    {
+       INet6SocketAddress addr;
+       BOOST_CHECK_EQUAL( addr.host(), "::" );
+       BOOST_CHECK_EQUAL( addr.port(), 0u );
+       BOOST_CHECK_EQUAL( addr.iface(), "" );
+       addr = "[12::21]:12345";
+       BOOST_CHECK_EQUAL( addr.host(), "12::21" );
+       BOOST_CHECK_EQUAL( addr.port(), 12345u );
+       BOOST_CHECK_EQUAL( addr.iface(), "" );
+       BOOST_CHECK_EQUAL( addr, INet6SocketAddress("[12::21]:12345") );
+    }
+    
+    {
+       INet6SocketAddress addr ("::1", 1);
+       BOOST_CHECK_EQUAL( addr, "[::1]:1" );
+       BOOST_CHECK_EQUAL( addr.iface(), "" );
+    }
+
+    {
+       INet6SocketAddress addr ("::1", 1, "lo");
+       BOOST_CHECK_EQUAL( addr, "[::1@lo]:1" );
+       BOOST_CHECK_EQUAL( addr.iface(), "lo" );
+       addr.iface("");
+       BOOST_CHECK_EQUAL( addr.iface(), "" );
+       addr.port(100u);
+       BOOST_CHECK_EQUAL( addr.port(), 100u );
+       addr.host("::2");
+       BOOST_CHECK_EQUAL( addr.host(), "::2" );
+       BOOST_CHECK_THROW( addr.address(""), InvalidINetAddressException );
+       BOOST_CHECK_THROW( addr.address("[::1]"), InvalidINetAddressException );
+       BOOST_CHECK_THROW( addr.address("[::1]1234"), InvalidINetAddressException );
+       addr.address("[12::21@lo]:12345");
+       BOOST_CHECK_EQUAL( addr.address(), "[12::21@lo]:12345" );
+       BOOST_CHECK_EQUAL( addr.host(), "12::21" );
+       BOOST_CHECK_EQUAL( addr.port(), 12345u );
+       BOOST_CHECK_EQUAL( addr.iface(), "lo" );
+       BOOST_CHECK_EQUAL( boost::lexical_cast<std::string>(addr), "[12::21@lo]:12345" );
+    }
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 34dc2ba..a540281 100755 (executable)
@@ -39,25 +39,41 @@ EOF
 # also truncate the backtrace at the first stackframe within the unit
 # test subsystem since we are only interested in the user code.
 gdb -batch -x .run-test-gdb.cmd ./.test.bin 2>/dev/null | perl -e '
+  $mode=0;
   while (<STDIN>) {
-    if (/^$/) { 
-      $_=<STDIN>; 
+    if ($mode==0) {
+      if (/^$/) { 
+        $mode=1;
+      } else {
+        print;
+      }
+    }
+    elsif ($mode==1) {
       if (/^Breakpoint 1, exception/) {
+        $mode=2;
         @l=();
-        while (<STDIN>) {
-          last unless /^#?[0-9]|^ /;
-          push @l,$_ if /^#/;
-         $l[$#l] .= $_ if /^ /;
-        }
+      } else {
+        print "\n";
+        print;
+        $mode=0;
+      }
+    }
+    elsif ($mode==2) {
+      if (/^(#?[0-9]| )/) {
+        push @l,$_ if /^#/;
+        $l[$#l] .= $_ if /^ /;
+      } else {
+        $mode=0;
         if (/: fatal error in /) {
           for (@l[1..$#l]) {
-             last if /^#[0-9]+ +0x[0-9a-f]+ in boost::unit_test/;
+             last if /^#[0-9]+ +0x[0-9a-f]+ in boost::unit_test::ut_detail::invoker/;
              print;
           }
+          print;
+        } else {
+          redo;
         }
       }
-      else { print "\n"; }
     }
-    print;
   }
-'
\ No newline at end of file
+'