Socket: Make 'ServerSocketHandle::accept()' callable with undefined AddressingPolicy
g0dil [Wed, 29 Aug 2007 16:21:55 +0000 (16:21 +0000)]
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

18 files changed:
PPI/Mainpage.dox
PPI/Module.hh
Socket/CommunicationPolicy.cc
Socket/CommunicationPolicy.cci [new file with mode: 0644]
Socket/CommunicationPolicy.hh
Socket/Protocols/INet/INet4Address.cc
Socket/Protocols/INet/INet4Address.hh
Socket/Protocols/INet/INet6Address.cc
Socket/Protocols/INet/INet6Address.hh
Socket/Protocols/INet/INet6Address.test.cc
Socket/Protocols/INet/INetAddressing.cc
Socket/Protocols/INet/INetAddressing.hh
Socket/Protocols/INet/INetAddressing.test.cc
Socket/ServerSocketHandle.cti
Socket/ServerSocketHandle.hh
Socket/SocketPolicy.hh
Socket/SocketPolicy.test.hh
run-test-gdb.sh

index f84ded6..2219cde 100644 (file)
     \section class_diagram Class Diagram
 
     \image html classes.png
-
-    \fixme Implement Spliters: PassiveSplitter, PrioritySplitter, CloneSplitter
-    \fixme Implement DiscardSink, CloneSource
-    \fixme Implement ThrottleBarrier
  */
 
 \f
index aac6bfa..7e6e21e 100644 (file)
@@ -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
index d67a923..0a1fb73 100644 (file)
@@ -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 (file)
index 0000000..a0f2d41
--- /dev/null
@@ -0,0 +1,48 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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_
+
+\f
+// 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:
index 0da9930..2f2911e 100644 (file)
@@ -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
index f6b5362..bd9bd68 100644 (file)
@@ -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(
index b638448..1c46498 100644 (file)
@@ -30,7 +30,6 @@
 #include <iostream>
 #include <string>
 #include <boost/cstdint.hpp>
-#include <boost/function.hpp>
 #include <boost/array.hpp>
 #include <boost/operators.hpp>
 #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<void (INet4Address const &)> 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 <class InputIterator> 
         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);
index 8ece248..d330aba 100644 (file)
@@ -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<in6_addr*>(*(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)
index 2032aff..f982016 100644 (file)
@@ -30,7 +30,6 @@
 #include <iostream>
 #include <string>
 #include <boost/cstdint.hpp>
-#include <boost/function.hpp>
 #include <boost/array.hpp>
 #include <boost/operators.hpp>
 #include "Utils/SafeBool.hh"
@@ -104,9 +103,6 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
-        typedef boost::function<void (INet6Address const &)> 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 <class InputIterator> 
         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
index 253c214..2fae5a0 100644 (file)
@@ -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") );
     }
index 88f8f5b..bcca6d5 100644 (file)
@@ -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<boost::uint16_t>(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)
index 5389b65..40f0a7a 100644 (file)
@@ -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
index 61cc302..c4d392f 100644 (file)
@@ -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 );
index 715a9a6..6fcb4cd 100644 (file)
@@ -95,8 +95,8 @@ template <class Policy>
 prefix_ typename senf::ServerSocketHandle<Policy>::ClientSocketHandle
 senf::ServerSocketHandle<Policy>::accept()
 {
-    Address address;
-    return acceptfrom(address);
+    return ClientSocketHandle(this->protocol().clone(),
+                              Policy::CommunicationPolicy::accept(*this));
 }
 
 template <class Policy>
@@ -106,7 +106,7 @@ senf::ServerSocketHandle<Policy>::acceptfrom()
 {
 
     Address address;
-    ClientSocketHandle handle = accept(address);
+    ClientSocketHandle handle = acceptfrom(address);
     return std::make_pair(handle,address);
 }
 
index bb97b2d..2607cd0 100644 (file)
@@ -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       ();
index 324d07c..e4cf253 100644 (file)
@@ -332,13 +332,12 @@ namespace senf {
         <table class="senf">
         <tr><td>method</td> <td><tt>void listen(FileHandle, unsigned backlog)</tt></td> <td>Switch socket into listening state</td></tr>
         <tr><td>method</td> <td><tt>int accept(FileHandle, Address &)</tt></td>         <td>Accept a new connection</td></tr>
+        <tr><td>method</td> <td><tt>int accept(FileHandle)</tt></td>                    <td>Accept a new connection</td></tr>
         </table>
 
         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
index 065ec46..263c837 100644 (file)
@@ -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
index 3cd2bd1..8d87f2a 100755 (executable)
@@ -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 /) {