From: g0dil Date: Wed, 14 Feb 2007 21:03:09 +0000 (+0000) Subject: Implement INet6SocketAddress X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=cf4ebe486e7e0543ac8568d3043f43d95f197a96;p=senf.git Implement INet6SocketAddress git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@199 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Socket/GenericSockAddr.cci b/Socket/GenericSockAddr.cci index 81907cc..6bec2e2 100644 --- a/Socket/GenericSockAddr.cci +++ b/Socket/GenericSockAddr.cci @@ -1,8 +1,25 @@ -// $Id$ +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Stefan Bund // -// 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 diff --git a/Socket/INetAddressing.cc b/Socket/INetAddressing.cc index d96bd93..b1efabc 100644 --- a/Socket/INetAddressing.cc +++ b/Socket/INetAddressing.cc @@ -31,12 +31,18 @@ #include #include #include +#include #include +#include +#include //#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 separator; + typedef boost::tokenizer 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(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" diff --git a/Socket/INetAddressing.cci b/Socket/INetAddressing.cci index 688cbb5..f7e5b77 100644 --- a/Socket/INetAddressing.cci +++ b/Socket/INetAddressing.cci @@ -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(&sockaddr_); +} + +prefix_ struct sockaddr const * senf::INet6SocketAddress::sockaddr_p() + const +{ + return reinterpret_cast(&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_ diff --git a/Socket/INetAddressing.hh b/Socket/INetAddressing.hh index d87f71f..d97c83c 100644 --- a/Socket/INetAddressing.hh +++ b/Socket/INetAddressing.hh @@ -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 { - typedef INet6Address Address; + typedef INet6SocketAddress Address; + + using GenericAddressingPolicy::peer; + using GenericAddressingPolicy::local; + using GenericAddressingPolicy::connect; + using GenericAddressingPolicy::bind; }; /// @} diff --git a/Socket/INetAddressing.test.cc b/Socket/INetAddressing.test.cc index 04b6600..2b8f9d3 100644 --- a/Socket/INetAddressing.test.cc +++ b/Socket/INetAddressing.test.cc @@ -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(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(addr), "[12::21@lo]:12345" ); + } } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/run-test-gdb.sh b/run-test-gdb.sh index 34dc2ba..a540281 100755 --- a/run-test-gdb.sh +++ b/run-test-gdb.sh @@ -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 () { - if (/^$/) { - $_=; + if ($mode==0) { + if (/^$/) { + $mode=1; + } else { + print; + } + } + elsif ($mode==1) { if (/^Breakpoint 1, exception/) { + $mode=2; @l=(); - while () { - 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 +'