From: g0dil Date: Wed, 29 Aug 2007 16:21:55 +0000 (+0000) Subject: Socket: Make 'ServerSocketHandle::accept()' callable with undefined AddressingPolicy X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=821f1bf89a0e3ef83469c56e4a9a21c39b956cb4;p=senf.git Socket: Make 'ServerSocketHandle::accept()' callable with undefined AddressingPolicy Socket/Protocols/Inet: Remove not implemented async resolv constructors (in favor of a later non-member implementation) Socket/Protocols/Inet: More detailed exceptions thrown by INet4Address / INet6Address git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@416 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/PPI/Mainpage.dox b/PPI/Mainpage.dox index f84ded6..2219cde 100644 --- a/PPI/Mainpage.dox +++ b/PPI/Mainpage.dox @@ -402,10 +402,6 @@ \section class_diagram Class Diagram \image html classes.png - - \fixme Implement Spliters: PassiveSplitter, PrioritySplitter, CloneSplitter - \fixme Implement DiscardSink, CloneSource - \fixme Implement ThrottleBarrier */ diff --git a/PPI/Module.hh b/PPI/Module.hh index aac6bfa..7e6e21e 100644 --- a/PPI/Module.hh +++ b/PPI/Module.hh @@ -59,6 +59,8 @@ namespace module { \li \ref sourcesink_modules generate or absorb packets internally \li \ref routing_modules forward packets within the network \li \ref adapter_modules are used to connect incompatible connectors to each other + + \todo Implement Spliters: PassiveSplitter, PrioritySplitter, CloneSplitter */ /** \defgroup io_modules Input/Output Modules diff --git a/Socket/CommunicationPolicy.cc b/Socket/CommunicationPolicy.cc index d67a923..0a1fb73 100644 --- a/Socket/CommunicationPolicy.cc +++ b/Socket/CommunicationPolicy.cc @@ -45,8 +45,8 @@ prefix_ void senf::ConnectedCommunicationPolicy::do_listen(FileHandle handle, } prefix_ int senf::ConnectedCommunicationPolicy::do_accept(FileHandle handle, - struct sockaddr * addr, - unsigned len) + struct sockaddr * addr, + unsigned len) { int rv = -1; do { diff --git a/Socket/CommunicationPolicy.cci b/Socket/CommunicationPolicy.cci new file mode 100644 index 0000000..a0f2d41 --- /dev/null +++ b/Socket/CommunicationPolicy.cci @@ -0,0 +1,48 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Stefan Bund +// +// 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. + +/** \file + \brief CommunicationPolicy inline non-template implementation */ + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +prefix_ int senf::ConnectedCommunicationPolicy::accept(FileHandle handle) +{ + return do_accept(handle, 0, 0); +} + +///////////////////////////////cci.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Socket/CommunicationPolicy.hh b/Socket/CommunicationPolicy.hh index 0da9930..2f2911e 100644 --- a/Socket/CommunicationPolicy.hh +++ b/Socket/CommunicationPolicy.hh @@ -84,6 +84,16 @@ namespace senf { \returns file descriptor of new client socket */ # endif + static int accept(FileHandle handle); + ///< accept a new connection on the socket. + /**< The accept() member will return a new client file + descriptor. This file descriptor will be used by the + ServerSocketHandle implementation to build a new + ClientSocketHandle for the new connection. + + \param[in] handle socket handle to accept connection on + \returns file descriptor of new client socket */ + private: static void do_listen(FileHandle handle, unsigned backlog); static int do_accept(FileHandle handle, struct sockaddr * addr, unsigned len); @@ -105,7 +115,7 @@ namespace senf { ///////////////////////////////hh.e//////////////////////////////////////// -//#include "CommunicationPolicy.cci" +#include "CommunicationPolicy.cci" //#include "CommunicationPolicy.ct" #include "CommunicationPolicy.cti" #endif diff --git a/Socket/Protocols/INet/INet4Address.cc b/Socket/Protocols/INet/INet4Address.cc index f6b5362..bd9bd68 100644 --- a/Socket/Protocols/INet/INet4Address.cc +++ b/Socket/Protocols/INet/INet4Address.cc @@ -52,6 +52,10 @@ prefix_ senf::INet4Address senf::INet4Address::from_string(std::string const & s struct in_addr ina; if (::inet_pton(AF_INET,s.c_str(),&ina) > 0) return senf::INet4Address::from_inaddr(ina.s_addr); + + if (s.empty()) + throw SyntaxException(); + int herr (0); // If available, we use the reentrant GNU variant. This has the additional advantage, that we @@ -76,10 +80,9 @@ prefix_ senf::INet4Address senf::INet4Address::from_string(std::string const & s # endif // __GLIBC__ if (!ent) - ///\fixme Need to give better exception here - throw SyntaxException(); + throw UnknownHostnameException(); if (ent->h_addrtype != AF_INET) - throw SyntaxException(); + throw UnknownHostnameException(); // We are only interested in the first address ... return senf::INet4Address::from_inaddr( diff --git a/Socket/Protocols/INet/INet4Address.hh b/Socket/Protocols/INet/INet4Address.hh index b638448..1c46498 100644 --- a/Socket/Protocols/INet/INet4Address.hh +++ b/Socket/Protocols/INet/INet4Address.hh @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include "Utils/SafeBool.hh" @@ -53,7 +52,6 @@ namespace senf { therefore not be distinguished from initialization with a string literal. Therefore we need to disambiguate using the named constructors. - \todo Add additional classes for CIDR addresses and networks and network math. \ingroup addr_group */ class INet4Address @@ -66,8 +64,6 @@ namespace senf { typedef uint32_t address_type; ///< Address representation as number in host byte order typedef uint32_t inaddr_type; ///< Legacy address representation in network byte order - typedef boost::function Callback; - ///< Callback for asynchronous from_string call static INet4Address const None; ///< The empty (0) address static INet4Address const Loopback; ///< The loopback (127.0.0.1) address @@ -96,20 +92,6 @@ namespace senf { converted for some reason \param[in] s Address literal or hostname */ - static void from_string(std::string const & s, Callback const & cb); - ///< Convert string to address (async/non-blocking) - /**< This member works like - from_string(std::string const &). However unlike - from_string(std::string const &), this call will not - block. Instead it will call \a cb passing the - INet4Address instance as soon as the address has been - resolved (which may be immediate if the address - represents an IP literal). \par - On error, the address passed to \a cb will be empty. - \param[in] s Address literal or hostname - \param[in] cb Callback to pass the address to - \fixme Implement */ - template static INet4Address from_data(InputIterator i); ///< Construct address from 4 bytes of raw data @@ -150,9 +132,19 @@ namespace senf { ////@} - struct SyntaxException : public std::exception - { virtual char const * what() const throw() { return "invalid INet4 address syntax"; } }; + /** \brief Base-class for INet4Address exceptions */ + struct AddressException : public std::exception {}; + + /** \brief Invalid INet4 address syntax */ + struct SyntaxException : public AddressException + { virtual char const * what() const throw() + { return "invalid INet4 address syntax"; } }; + /** \brief Resolver failure */ + struct UnknownHostnameException : public AddressException + { virtual char const * what() const throw() + { return "failed to resolve INet4 hostname"; } }; + private: enum InAddr_t { IsInAddr }; INet4Address(inaddr_type addr, InAddr_t); diff --git a/Socket/Protocols/INet/INet6Address.cc b/Socket/Protocols/INet/INet6Address.cc index 8ece248..d330aba 100644 --- a/Socket/Protocols/INet/INet6Address.cc +++ b/Socket/Protocols/INet/INet6Address.cc @@ -47,6 +47,10 @@ prefix_ senf::INet6Address senf::INet6Address::from_string(std::string const & s struct in6_addr ina; if (::inet_pton(AF_INET6,s.c_str(),&ina) > 0) return senf::INet6Address::from_data(&ina.s6_addr[0]); + + if (s.empty()) + throw SyntaxException(); + int herr (0); // If available, we use the reentrant GNU variant. This has the additional advantage, that we @@ -75,16 +79,16 @@ prefix_ senf::INet6Address senf::INet6Address::from_string(std::string const & s return senf::INet6Address::from_data( &reinterpret_cast(*(ent->h_addr_list))->s6_addr[0]); - ///\todo Throw better exceptions here ? - if (resolve == ResolveINet4) try { return from_inet4address(INet4Address::from_string(s)); } catch (INet4Address::SyntaxException const & ex) { throw SyntaxException(); + } catch (INet4Address::UnknownHostnameException const & ex) { + throw UnknownHostnameException(); } else - throw SyntaxException(); + throw UnknownHostnameException(); } prefix_ std::ostream & senf::operator<<(std::ostream & os, INet6Address const & addr) diff --git a/Socket/Protocols/INet/INet6Address.hh b/Socket/Protocols/INet/INet6Address.hh index 2032aff..f982016 100644 --- a/Socket/Protocols/INet/INet6Address.hh +++ b/Socket/Protocols/INet/INet6Address.hh @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include "Utils/SafeBool.hh" @@ -104,9 +103,6 @@ namespace senf { /////////////////////////////////////////////////////////////////////////// // Types - typedef boost::function Callback; - ///< Callback for asynchronous from_string call - static INet6Address const None; ///< The empty (::0) address static INet6Address const Loopback; ///< The loopback (::1) address static INet6Address const AllNodes; ///< The 'all nodes' link-local multicast address @@ -161,26 +157,6 @@ namespace senf { found. The address will be returned as mapped IpV6 address. */ - static void from_string(std::string const & s, Callback const & cb, - Resolve_t resolve = ResolveINet6); - ///< Convert string to address (async/non-blocking) - /**< This member works like - from_string(std::string const &). However unlike - from_string(std::string const &), this call will not - block. Instead it will call \a cb passing the - INet6Address instance as soon as the address has been - resolved (which may be immediate if the address - represents an IP literal). \par - On error, the address passed to \a cb will be empty. - \param[in] s Address literal or hostname - \param[in] cb Callback to pass the address to - \param[in] resolve If this is set to \c ResolveINet4, - the call will additionally try to interpret \a s as - an IpV4 address if no valid IpV6 address is - found. The address will be returned as mapped IpV6 - address. - \fixme Implement */ - template static INet6Address from_data(InputIterator i); ///< Construct address from 16 bytes of raw data @@ -260,9 +236,18 @@ namespace senf { ///@} - /** \brief Invalid IpV6 address syntax */ - struct SyntaxException : public std::exception - { virtual char const * what() const throw() { return "Invalid IpV6 address syntax"; } }; + /** \brief Base-class for INet6Address exceptions */ + struct AddressException : public std::exception {}; + + /** \brief Invalid INet4 address syntax */ + struct SyntaxException : public AddressException + { virtual char const * what() const throw() + { return "invalid INet6 address syntax"; } }; + + /** \brief Resolver failure */ + struct UnknownHostnameException : public AddressException + { virtual char const * what() const throw() + { return "failed to resolve INet6 hostname"; } }; }; /** \brief Output INet6Address instance as it's string representation diff --git a/Socket/Protocols/INet/INet6Address.test.cc b/Socket/Protocols/INet/INet6Address.test.cc index 253c214..2fae5a0 100644 --- a/Socket/Protocols/INet/INet6Address.test.cc +++ b/Socket/Protocols/INet/INet6Address.test.cc @@ -77,7 +77,7 @@ BOOST_AUTO_UNIT_TEST(inet6Address) BOOST_CHECK_EQUAL( INet6Address::from_inet4address(INet4Address(0x01020304)), INet6Address::from_string("::ffff:1.2.3.4") ); - BOOST_CHECK_THROW( INet6Address::from_string("1.2.3.4"), INet6Address::SyntaxException ); + BOOST_CHECK_THROW( INet6Address::from_string("1.2.3.4"), INet6Address::UnknownHostnameException ); BOOST_CHECK_EQUAL( INet6Address::from_string("1.2.3.4", INet6Address::ResolveINet4), INet6Address::from_string("::ffff:1.2.3.4") ); } diff --git a/Socket/Protocols/INet/INetAddressing.cc b/Socket/Protocols/INet/INetAddressing.cc index 88f8f5b..bcca6d5 100644 --- a/Socket/Protocols/INet/INetAddressing.cc +++ b/Socket/Protocols/INet/INetAddressing.cc @@ -48,13 +48,18 @@ prefix_ senf::INet4SocketAddress::INet4SocketAddress(std::string const & addr) unsigned i = addr.find(':'); if (i == std::string::npos) throw SyntaxException(); - address(INet4Address::from_string(std::string(addr,0,i))); try { port(boost::lexical_cast< ::u_int16_t >(std::string(addr,i+1))); } catch (boost::bad_lexical_cast const &) { throw SyntaxException(); } + try { + address(INet4Address::from_string(std::string(addr,0,i))); + } + catch (INet4Address::SyntaxException const &) { + throw SyntaxException(); + } } prefix_ senf::INet4SocketAddress::INet4SocketAddress(INet4Address const & addr, unsigned p) @@ -92,15 +97,19 @@ prefix_ senf::INet6SocketAddress::INet6SocketAddress(std::string const & addr, if (! regex_match(addr, match, addressRx)) throw SyntaxException(); - INet6Address a (INet6Address::from_string( - match[NumericAddr].matched ? match[NumericAddr] : match[Hostname], - resolve)); - std::copy(a.begin(), a.end(), &sockaddr_.sin6_addr.s6_addr[0]); - if (match[ZoneId].matched) assignIface(match[ZoneId]); sockaddr_.sin6_port = htons(boost::lexical_cast(match[Port])); + + try { + INet6Address a (INet6Address::from_string( + match[NumericAddr].matched ? match[NumericAddr] : match[Hostname], + resolve)); + std::copy(a.begin(), a.end(), &sockaddr_.sin6_addr.s6_addr[0]); + } catch (INet6Address::SyntaxException const &) { + throw SyntaxException(); + } } prefix_ bool senf::INet6SocketAddress::operator==(INet6SocketAddress const & other) diff --git a/Socket/Protocols/INet/INetAddressing.hh b/Socket/Protocols/INet/INetAddressing.hh index 5389b65..40f0a7a 100644 --- a/Socket/Protocols/INet/INetAddressing.hh +++ b/Socket/Protocols/INet/INetAddressing.hh @@ -60,16 +60,16 @@ namespace senf { { public: INet4SocketAddress(); - explicit INet4SocketAddress(std::string const & address); ///< Set address and port + explicit INet4SocketAddress(std::string const & addr); ///< Set address and port /**< This constructor expects a string of the form 'host:port'. The constructor will use this value to initialize the host and port members. Since it uses the INet4Address::from_string constructor, this call may block while waiting for the resolver. - \throws SyntaxException if the 'host:port' syntax is - not obeyed. - \throws INet4Address::SyntaxException if the host part - cannot be converted to an IP address. */ + \throws SyntaxException if the address syntax is + invalid + \throws INet4Address::UnknownHostnameException if the + address cannot be resolved. */ INet4SocketAddress(INet4Address const & addr, unsigned port); ///< Set address and port explicitly @@ -157,9 +157,13 @@ namespace senf { explicit INet6SocketAddress(std::string const & addr, INet6Address::Resolve_t resolve = INet6Address::ResolveINet6); ///< Initialize/convert from string representation - /**< \param[in] addr Address to parse + /**< \throws SyntaxException if the address syntax is + invalid + \throws INet6Address::UnknownHostnameException if the + address cannot be resolved. + \param[in] addr Address to parse \param[in] resolve If this is - INet6Address::ResolveINet4, support also IpV4 + INet6Address::ResolveINet4, support IpV4 addresses. See INet6Address. */ INet6SocketAddress(INet6Address const & addr, unsigned port); ///< Initialize from address and port diff --git a/Socket/Protocols/INet/INetAddressing.test.cc b/Socket/Protocols/INet/INetAddressing.test.cc index 61cc302..c4d392f 100644 --- a/Socket/Protocols/INet/INetAddressing.test.cc +++ b/Socket/Protocols/INet/INetAddressing.test.cc @@ -57,7 +57,8 @@ BOOST_AUTO_UNIT_TEST(inet4SocketAddress) INet4SocketAddress(INet4Address::Loopback,12345) ); BOOST_CHECK_THROW( INet4SocketAddress("127.0.0.1"), INet4SocketAddress::SyntaxException ); - BOOST_CHECK_THROW( INet4SocketAddress("foo@bar:12345"), INet4Address::SyntaxException ); + BOOST_CHECK_THROW( INet4SocketAddress("foo:bar"), INet4SocketAddress::SyntaxException ); + BOOST_CHECK_THROW( INet4SocketAddress(":12345"), INet4SocketAddress::SyntaxException ); BOOST_CHECK_THROW( INet4SocketAddress("127.0.0.1:1234a"), INet4SocketAddress::SyntaxException ); BOOST_CHECK_EQUAL( INet4SocketAddress("127.0.0.1:12345").address(), INet4Address::Loopback ); diff --git a/Socket/ServerSocketHandle.cti b/Socket/ServerSocketHandle.cti index 715a9a6..6fcb4cd 100644 --- a/Socket/ServerSocketHandle.cti +++ b/Socket/ServerSocketHandle.cti @@ -95,8 +95,8 @@ template prefix_ typename senf::ServerSocketHandle::ClientSocketHandle senf::ServerSocketHandle::accept() { - Address address; - return acceptfrom(address); + return ClientSocketHandle(this->protocol().clone(), + Policy::CommunicationPolicy::accept(*this)); } template @@ -106,7 +106,7 @@ senf::ServerSocketHandle::acceptfrom() { Address address; - ClientSocketHandle handle = accept(address); + ClientSocketHandle handle = acceptfrom(address); return std::make_pair(handle,address); } diff --git a/Socket/ServerSocketHandle.hh b/Socket/ServerSocketHandle.hh index bb97b2d..2607cd0 100644 --- a/Socket/ServerSocketHandle.hh +++ b/Socket/ServerSocketHandle.hh @@ -170,8 +170,6 @@ namespace senf { This variant ... \returns handle of new client connection - - \fixme Make this accept()-variant work with unspecified addressing policy */ ClientSocketHandle accept (); diff --git a/Socket/SocketPolicy.hh b/Socket/SocketPolicy.hh index 324d07c..e4cf253 100644 --- a/Socket/SocketPolicy.hh +++ b/Socket/SocketPolicy.hh @@ -332,13 +332,12 @@ namespace senf { +
method void listen(FileHandle, unsigned backlog) Switch socket into listening state
method int accept(FileHandle, Address &) Accept a new connection
method int accept(FileHandle) Accept a new connection
The \c listen member is straight forward. The \c accept() member must return a new file descriptor (which will be used to create a new SocketHandle of the correct - type). Additionally, accept() should only be defined, if the Addressing policy is not \c - NoAddressingPolicy (which together with ConnectedCommunicationPolicy would identify a - point-to-point link with fixed communication partners). + type). \note This Policy only has two meaningful states: ConnectedCommunicationPolicy and UnconnectedCommunicationPolicy. It is probably not sensible to define a new diff --git a/Socket/SocketPolicy.test.hh b/Socket/SocketPolicy.test.hh index 065ec46..263c837 100644 --- a/Socket/SocketPolicy.test.hh +++ b/Socket/SocketPolicy.test.hh @@ -55,6 +55,8 @@ namespace test { { static int accept(FileHandle handle, unsigned & addr) { addr = 3; return -1; } + static int accept(FileHandle handle) + { return -1; } }; struct SomeReadPolicy : public senf::ReadPolicyBase diff --git a/run-test-gdb.sh b/run-test-gdb.sh index 3cd2bd1..8d87f2a 100755 --- a/run-test-gdb.sh +++ b/run-test-gdb.sh @@ -62,6 +62,8 @@ gdb -batch -x .run-test-gdb.cmd ./.test.bin 2>/dev/null | perl -e ' if (/^(#?[0-9]| )/) { push @l,$_ if /^#/; $l[$#l] .= $_ if @l && /^ /; + } elsif (/^Current language: auto;/) { + ; } else { $mode=0; if (/: fatal error in /) {