From 7dfd06d21f00b643f664bcf27029af9ff5ea6948 Mon Sep 17 00:00:00 2001
From: g0dil <g0dil@wiback.org>
Date: Mon, 11 Jun 2007 23:29:13 +0000
Subject: [PATCH] Several FIXME items: * Allow empty FileHandle/SocketHandle
 etc instances * Make ServerSocketHandle::listen depend on AddressingPolicy *
 Replace all occurences of inet_ntoa with inet_ntop (thread safety) * Fix
 handling of exceptions in ReadHelper/WriteHelper * Fix Scheduler ERR/HUP
 semantics

---
 Packets/DefaultBundle/IpV4Packet.cc   |  5 ++-
 Packets/Packet.cci                    |  5 +--
 Packets/ParseListS.ct                 |  9 ++--
 Scheduler/ReadHelper.ct               |  5 ++-
 Scheduler/Scheduler.cc                | 56 ++++++++++-------------
 Scheduler/Scheduler.hh                |  7 ++-
 Scheduler/Scheduler.test.cc           |  9 +---
 Scheduler/WriteHelper.ct              |  7 ++-
 Socket/ClientSocketHandle.cti         |  4 ++
 Socket/ClientSocketHandle.hh          | 36 +++++++--------
 Socket/CommunicationPolicy.cc         |  4 +-
 Socket/CommunicationPolicy.cti        |  8 ++++
 Socket/CommunicationPolicy.hh         | 11 +++--
 Socket/FileHandle.cci                 |  8 +++-
 Socket/FileHandle.hh                  | 65 +++++++++++----------------
 Socket/FileHandle.test.cc             |  7 ++-
 Socket/INetAddressing.cci             |  4 +-
 Socket/INetAddressing.hh              |  4 +-
 Socket/ProtocolClientSocketHandle.cti |  5 +++
 Socket/ProtocolClientSocketHandle.hh  | 12 +++++
 Socket/ProtocolServerSocketHandle.cti |  5 +++
 Socket/ProtocolServerSocketHandle.hh  | 11 +++++
 Socket/ServerSocketHandle.cti         |  4 ++
 Socket/ServerSocketHandle.hh          |  5 ++-
 Socket/SocketHandle.cti               |  4 ++
 Socket/SocketHandle.hh                |  4 ++
 26 files changed, 173 insertions(+), 131 deletions(-)

diff --git a/Packets/DefaultBundle/IpV4Packet.cc b/Packets/DefaultBundle/IpV4Packet.cc
index 8f7c06439..6b163a6d5 100644
--- a/Packets/DefaultBundle/IpV4Packet.cc
+++ b/Packets/DefaultBundle/IpV4Packet.cc
@@ -56,9 +56,10 @@ prefix_ void senf::IpV4Packet::v_dump(std::ostream & os)
 {
     struct in_addr in;
     in.s_addr = htonl(source());
-    std::string src (inet_ntoa(in));
+    char buffer[128];
+    std::string src (inet_ntop(AF_INET,&in,buffer,128));
     in.s_addr = htonl(destination());
-    std::string dst (inet_ntoa(in));
+    std::string dst (inet_ntop(AF_INET,&in,buffer,128));
     os << "Internet protocol Version 4:\n"
        << "  version       : " << version() << "\n"
        << "  IHL           : " << ihl() << "\n"
diff --git a/Packets/Packet.cci b/Packets/Packet.cci
index d9dcfc0fb..72f794364 100644
--- a/Packets/Packet.cci
+++ b/Packets/Packet.cci
@@ -154,9 +154,8 @@ prefix_ senf::Packet::ptr senf::Packet::head()
 
 prefix_  senf::Packet::~Packet()
 {
-    /** \fixme This is bad ... we cannot check this since this
-        assertion fails at the moment if the Packet constructor throws
-        ... hrmpf ... we really need to initialize refcount_ to 0 and
+    /** \todo This is sad ... we cannot check this since this assertion fails at the moment if the
+        Packet constructor throws ... hrmpf ... we really should initialize refcount_ to 0 and
         remove the 'false' argument to the ptr constructor in create */
     // BOOST_ASSERT( !this->refcount_  && !this->impl_ );
     SATCOM_PKF_REFC_MSG("] Packet::~Packet (" << this << ")\n");
diff --git a/Packets/ParseListS.ct b/Packets/ParseListS.ct
index ba893600b..1c010366e 100644
--- a/Packets/ParseListS.ct
+++ b/Packets/ParseListS.ct
@@ -80,9 +80,8 @@ template <class Parser, class Sentinel, class Container>
 template <class Value>
 prefix_ void
 senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::insert(iterator pos,
-                                                                    Value const & t)
+                                                             Value const & t)
 {
-    /** \fixme What, if pos == end() / default constructed iterator ? */
     size_type ix (pos.raw()-container_.begin());
     container_.insert(pos.raw(),t.bytes(),0);
     Parser(container_.begin()+ix).value(t);
@@ -92,7 +91,7 @@ template <class Parser, class Sentinel, class Container>
 template <class Value>
 prefix_ void
 senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::insert(iterator pos, size_type n,
-                                                                    Value const & t)
+                                                             Value const & t)
 {
     size_type ix (pos.raw()-container_.begin());
     container_.insert(pos.raw(),n*t.bytes(),0);
@@ -105,8 +104,8 @@ template <class Parser, class Sentinel, class Container>
 template <class InputIterator>
 prefix_ void
 senf::Parse_ListS_wrapper<Parser,Sentinel,Container>::insert(iterator pos,
-                                                                    InputIterator f,
-                                                                    InputIterator l)
+                                                             InputIterator f,
+                                                             InputIterator l)
 {
     /** \todo Optimize this for random-access and multi-pass iterators */
     for (;f!=l;++f,++pos) insert(pos,*f);
diff --git a/Scheduler/ReadHelper.ct b/Scheduler/ReadHelper.ct
index 3ac3df5f5..40ac19936 100644
--- a/Scheduler/ReadHelper.ct
+++ b/Scheduler/ReadHelper.ct
@@ -69,7 +69,6 @@ template <class Handle>
 prefix_ void senf::ReadHelper<Handle>::process(Handle handle,
                                                       senf::Scheduler::EventId event)
 {
-    /** \fixme Move the done() calls to outside the try/catch block */
     try {
         if (event != senf::Scheduler::EV_READ)
             throw SystemException(EPIPE);
@@ -82,13 +81,15 @@ prefix_ void senf::ReadHelper<Handle>::process(Handle handle,
                 tail_.assign(data_,n,std::string::npos);
                 data_.erase(n);
             }
-            done();
         }
     }
     catch (senf::SystemException const & ex) {
         errno_ = ex.err;
         done();
+        return;
     }
+    if (complete_)
+        done();
 }
 
 template <class Handle>
diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc
index f692402b2..e4bc1a09f 100644
--- a/Scheduler/Scheduler.cc
+++ b/Scheduler/Scheduler.cc
@@ -116,8 +116,6 @@ prefix_ void senf::Scheduler::do_add(int fd, SimpleCallback const & cb, int even
     if (eventMask & EV_READ)  i->second.cb_read = cb;
     if (eventMask & EV_PRIO)  i->second.cb_prio = cb;
     if (eventMask & EV_WRITE) i->second.cb_write = cb;
-    if (eventMask & EV_HUP)   i->second.cb_hup = cb;
-    if (eventMask & EV_ERR)   i->second.cb_err = cb;
 
     epoll_event ev;
     memset(&ev,0,sizeof(ev));
@@ -137,8 +135,6 @@ prefix_ void senf::Scheduler::do_remove(int fd, int eventMask)
     if (eventMask & EV_READ)  i->second.cb_read = 0;
     if (eventMask & EV_PRIO)  i->second.cb_prio = 0;
     if (eventMask & EV_WRITE) i->second.cb_write = 0;
-    if (eventMask & EV_HUP)   i->second.cb_hup = 0;
-    if (eventMask & EV_ERR)   i->second.cb_err = 0;
 
     epoll_event ev;
     memset(&ev,0,sizeof(ev));
@@ -163,8 +159,6 @@ prefix_ int senf::Scheduler::EventSpec::epollMask()
     if (cb_read)  mask |= EPOLLIN;
     if (cb_prio)  mask |= EPOLLPRI;
     if (cb_write) mask |= EPOLLOUT;
-    if (cb_hup)   mask |= EPOLLHUP;
-    if (cb_err)   mask |= EPOLLERR;
     return mask;
 }
 
@@ -185,50 +179,46 @@ prefix_ void senf::Scheduler::process()
         struct epoll_event ev;
         int events = epoll_wait(epollFd_, &ev, 1, timeout);
         if (events<0)
-            // Hmm ... man epoll says, it will NOT return with EINTR ??
+            // Hmm ... man epoll says, it will NOT return with EINTR. I hope, this is true :-)
             throw SystemException(errno);
         if (events==0)
-            // Timeout .. it will be run when reachiung the top of the loop
+            // Timeout .. the handler will be run when going back to the loop top
             continue;
 
         FdTable::iterator i = fdTable_.find(ev.data.fd);
         BOOST_ASSERT (i != fdTable_.end() );
-        EventSpec const & spec (i->second);
+        // \todo Make this more efficient. Instead of copying the event-spec it should be
+        // revalidated by monitoring add/remove calls
+        EventSpec spec (i->second);
+
+        unsigned extraFlags (0);
+        if (ev.events & EPOLLHUP) extraFlags |= EV_HUP;
+        if (ev.events & EPOLLERR) extraFlags |= EV_ERR;
 
         if (ev.events & EPOLLIN) {
             BOOST_ASSERT(spec.cb_read);
-            spec.cb_read(EV_READ);
+            spec.cb_read(EventId(EV_READ | extraFlags));
         }
         else if (ev.events & EPOLLPRI) {
             BOOST_ASSERT(spec.cb_prio);
-            spec.cb_prio(EV_PRIO);
+            spec.cb_prio(EventId(EV_PRIO | extraFlags));
         }
         else if (ev.events & EPOLLOUT) {
             BOOST_ASSERT(spec.cb_write);
-            spec.cb_write(EV_WRITE);
-        }
-
-        else if (ev.events & EPOLLHUP) {
-            if (spec.cb_hup)
-                spec.cb_hup(EV_HUP);
-            else if (ev.events & EPOLLERR) {
-                /** \fixme This is stupid, if cb_write and cb_read are
-                    the same. The same below. We really have to
-                    exactly define sane semantics of what to do on
-                    EPOLLHUP and EPOLLERR. */
-                if (spec.cb_write) spec.cb_write(EV_HUP);
-                if (spec.cb_read) spec.cb_read(EV_HUP);
-            }
+            spec.cb_write(EventId(EV_WRITE | extraFlags));
         }
-        else if (ev.events & EPOLLERR && ! ev.events & EPOLLHUP) {
-            if (spec.cb_err)
-                spec.cb_err(EV_ERR);
-            else {
-                if (spec.cb_write) spec.cb_write(EV_ERR);
-                if (spec.cb_read) spec.cb_read(EV_ERR);
-            }
+        else {
+            // This branch is only taken, if HUP or ERR is signaled but none of IN/OUT/PRI. 
+            // In this case we will signal all registered callbacks. The callbacks must be
+            // prepared to be called multiple times if they are registered to more than
+            // one event.
+            if (spec.cb_write) 
+                spec.cb_write(EventId(extraFlags));
+            if (spec.cb_prio) 
+                spec.cb_prio(EventId(extraFlags));
+            if (spec.cb_read) 
+                spec.cb_read(EventId(extraFlags));
         }
-
     }
 }
 
diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh
index 1887f5def..8fe4f152a 100644
--- a/Scheduler/Scheduler.hh
+++ b/Scheduler/Scheduler.hh
@@ -76,8 +76,9 @@ namespace senf {
 
         /// \brief Types of file descriptor events */
         enum EventId { EV_NONE=0,
-                       EV_READ=1, EV_PRIO=2, EV_WRITE=4, EV_HUP=8, EV_ERR=16,
-                       EV_ALL=31 };
+                       EV_READ=1, EV_PRIO=2, EV_WRITE=4, 
+                       EV_ALL=7,
+                       EV_HUP=8, EV_ERR=16 };
 
         /** \brief Template typedef for Callback type
 
@@ -180,8 +181,6 @@ namespace senf {
             SimpleCallback cb_read;
             SimpleCallback cb_prio;
             SimpleCallback cb_write;
-            SimpleCallback cb_hup;
-            SimpleCallback cb_err;
 
             int epollMask() const;
         };
diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc
index 78aaa4d29..104268b2f 100644
--- a/Scheduler/Scheduler.test.cc
+++ b/Scheduler/Scheduler.test.cc
@@ -143,7 +143,7 @@ namespace {
     void callback(int fd, Scheduler::EventId ev)
     {
         event = ev;
-        switch (event) {
+        switch (event & Scheduler::EV_ALL) {
         case Scheduler::EV_READ:
             size = recv(fd,buffer,1024,0);
             break;
@@ -155,11 +155,6 @@ namespace {
             size = write(fd,buffer,size);
             Scheduler::instance().terminate();
             break;
-        case Scheduler::EV_HUP:
-        case Scheduler::EV_ERR:
-        case Scheduler::EV_NONE:
-        case Scheduler::EV_ALL:
-            ;
         }
         Scheduler::instance().terminate();
     }
@@ -246,7 +241,7 @@ BOOST_AUTO_UNIT_TEST(scheduler)
     BOOST_CHECK_NO_THROW( Scheduler::instance().remove(handle,Scheduler::EV_WRITE) );
     event = Scheduler::EV_NONE;
     BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
-    BOOST_CHECK_EQUAL( event, Scheduler::EV_READ );
+    BOOST_CHECK_EQUAL( event, Scheduler::EventId(Scheduler::EV_READ|Scheduler::EV_HUP) );
     BOOST_REQUIRE_EQUAL( size, 2 );
     buffer[size]=0;
     BOOST_CHECK_EQUAL( buffer, "OK" );
diff --git a/Scheduler/WriteHelper.ct b/Scheduler/WriteHelper.ct
index 2fa26020a..9dfa74793 100644
--- a/Scheduler/WriteHelper.ct
+++ b/Scheduler/WriteHelper.ct
@@ -75,20 +75,23 @@ template <class Handle>
 prefix_ void senf::WriteHelper<Handle>::process(Handle handle,
                                                        senf::Scheduler::EventId event)
 {
-    /** \fixme Move the done() calls to outside the try/catch block */
+    bool complete_ (false);
     try {
         if (event != senf::Scheduler::EV_WRITE)
             throw senf::SystemException(EPIPE);
         offset_ += handle.write(data_.data()+offset_,data_.size()-offset_);
         if (offset_ >= data_.size()) {
             data_.erase();
-            done();
+            complete_ = true;
         }
     }
     catch (senf::SystemException const & ex) {
         errno_ = ex.err;
         done();
+        return;
     }
+    if (complete_)
+        done();
 }
 
 template <class Handle>
diff --git a/Socket/ClientSocketHandle.cti b/Socket/ClientSocketHandle.cti
index 859139948..d83682349 100644
--- a/Socket/ClientSocketHandle.cti
+++ b/Socket/ClientSocketHandle.cti
@@ -98,6 +98,10 @@ writeto(Handle & handle, ForwardReadableRange & range, typename Handle::Address
 ////////////////////////////////////////
 // structors
 
+template <class Policy>
+prefix_ senf::ClientSocketHandle<Policy>::ClientSocketHandle()
+{}
+
 template <class Policy>
 template <class OtherPolicy>
 prefix_ senf::ClientSocketHandle<Policy>::
diff --git a/Socket/ClientSocketHandle.hh b/Socket/ClientSocketHandle.hh
index 368e3cdb3..38e7ea038 100644
--- a/Socket/ClientSocketHandle.hh
+++ b/Socket/ClientSocketHandle.hh
@@ -79,13 +79,6 @@ namespace senf {
         typelist of Poclicy classes which can be accessed. You use protocol<ProtocolClass>() to
         access a protocol class. \c Policies can of course be underspecified or even empty.
 
-        \idea add more flexible read/write members for a) boost::arrays and arrays of other types b)
-        std::vector (which uses contiguous memory ..) c) other random-access containers (we should
-        use some configurable trait class to identify containers with contiguous storage). Probably
-        we should just use a generic Boost.Range interface. Here we again come to the point: make
-        all except the most basic members be non-member algorithms ? this would make the
-        configuration of such extenden members more flexible.
-
         \see \ref policy_group \n
              \ref protocol_group
       */
@@ -116,11 +109,14 @@ namespace senf {
         ///\name Structors and default members
         ///@{
 
-        // no default constructor
+        // default default constructor
         // default copy constructor
         // default copy assignment
         // default destructor
 
+        // here to implement
+        ClientSocketHandle();
+
         // conversion constructors
         template <class OtherPolicy>
         ClientSocketHandle(ClientSocketHandle<OtherPolicy> other,
@@ -181,14 +177,15 @@ namespace senf {
                                              \param[in/out] range Range to store data in 
                                              \returns past-the-end iterator pointer to after the
                                                  last read character 
-                                             \see \ref read() */
+                                             \see \ref read() \n
+                                                  <a href="http://www.boost.org/libs/range/index.html">Boost.Range</a> */
         template <class ForwardWritableRange>
         typename boost::range_iterator<ForwardWritableRange>::type
                      read         (ForwardWritableRange & range);
                                         ///< Read data into range
-                                        /**< \see 
-                                             read(ForwardWritableRange const &) \n
-                                             read() */
+                                        /**< \see read(ForwardWritableRange const &) \n
+                                                  read() \n
+                                                  <a href="http://www.boost.org/libs/range/index.html">Boost.Range</a>  */
         template <class Sequence>
         void         read         (Sequence & container, unsigned limit);
                                         ///< Read data into container
@@ -243,14 +240,15 @@ namespace senf {
                                                  received
                                              \returns past-the-end iterator pointer to after the
                                                  last read character 
-                                             \see \ref readfrom() */
+                                             \see \ref readfrom() \n
+                                                  <a href="http://www.boost.org/libs/range/index.html">Boost.Range</a>  */
         template <class ForwardWritableRange>
         typename boost::range_iterator<ForwardWritableRange>::type
                      readfrom     (ForwardWritableRange & range, Address & from);
                                         ///< Read data into range
-                                        /**< \see 
-                                             readfrom(ForwardWritableRange const&,Address&) \n
-                                             readfrom() */
+                                        /**< \see readfrom(ForwardWritableRange const&,Address&) \n
+                                                  readfrom()  \n
+                                                  <a href="http://www.boost.org/libs/range/index.html">Boost.Range</a> */
         template <class Sequence>
         void         readfrom     (Sequence & container, Address & from, unsigned limit);
                                         ///< Read data into container
@@ -303,7 +301,8 @@ namespace senf {
                                         /**< \param[in] start beginning of area to write
                                              \param[in] end past-the-end pointer to area to write
                                              \returns past-the-end pointer after last byte written
-                                             \see \ref write() */
+                                             \see \ref write() \n
+                                                  <a href="http://www.boost.org/libs/range/index.html">Boost.Range</a>  */
 
         /** \brief Write data to unconnected socket
 
@@ -332,7 +331,8 @@ namespace senf {
                                              \param[in] start address of buffer to write
                                              \param[in] end past-the-end pointer after data to write
                                              \returns past-the-end iterator after last byte written
-                                             \see \ref writeto() */
+                                             \see \ref writeto() \n
+                                                  <a href="http://www.boost.org/libs/range/index.html">Boost.Range</a>  */
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Addressing
diff --git a/Socket/CommunicationPolicy.cc b/Socket/CommunicationPolicy.cc
index b7ddb9f51..eedc8fb4e 100644
--- a/Socket/CommunicationPolicy.cc
+++ b/Socket/CommunicationPolicy.cc
@@ -38,8 +38,8 @@
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-prefix_ void senf::ConnectedCommunicationPolicy::listen(FileHandle handle,
-                                                               unsigned backlog)
+prefix_ void senf::ConnectedCommunicationPolicy::do_listen(FileHandle handle,
+                                                           unsigned backlog)
 {
     ::listen(handle.fd(),backlog);
 }
diff --git a/Socket/CommunicationPolicy.cti b/Socket/CommunicationPolicy.cti
index b801ae11f..233dc3bfb 100644
--- a/Socket/CommunicationPolicy.cti
+++ b/Socket/CommunicationPolicy.cti
@@ -31,6 +31,14 @@
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
+template <class Policy>
+prefix_ void senf::ConnectedCommunicationPolicy::
+listen(ServerSocketHandle<Policy> handle, unsigned backlog,
+       typename IfAddressingPolicyIsNot<Policy,NoAddressingPolicy>::type *)
+{
+    do_listen(handle, backlog);
+}
+
 template <class Policy>
 prefix_ int senf::ConnectedCommunicationPolicy::
 accept(ServerSocketHandle<Policy> handle,
diff --git a/Socket/CommunicationPolicy.hh b/Socket/CommunicationPolicy.hh
index fe899262f..9c0af83e8 100644
--- a/Socket/CommunicationPolicy.hh
+++ b/Socket/CommunicationPolicy.hh
@@ -51,14 +51,12 @@ namespace senf {
      */
     struct ConnectedCommunicationPolicy : public CommunicationPolicyBase
     {
-        static void listen(FileHandle handle, unsigned backlog);
+        template <class Policy>
+        static void listen(ServerSocketHandle<Policy> handle, unsigned backlog,
+                           typename IfAddressingPolicyIsNot<Policy,NoAddressingPolicy>::type * = 0);
                                         ///< Enable establishing new connections on the socket
                                         /**< \param[in] handle socket handle to enable reception on
-                                             \param[in] backlog size of backlog queue
-
-                                             \fixme listen probably makes no sense without accept,
-                                                 so listen() should depend on AddressingPolicy
-                                                 too. */
+                                             \param[in] backlog size of backlog queue */
         template <class Policy>
         static int accept(ServerSocketHandle<Policy> handle,
                           typename ServerSocketHandle<Policy>::Address & address,
@@ -74,6 +72,7 @@ namespace senf {
                                                  peer
                                              \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);
     };
 
diff --git a/Socket/FileHandle.cci b/Socket/FileHandle.cci
index a727beee0..37c269d6f 100644
--- a/Socket/FileHandle.cci
+++ b/Socket/FileHandle.cci
@@ -171,7 +171,7 @@ prefix_ bool senf::FileHandle::eof()
 prefix_ bool senf::FileHandle::valid()
     const
 {
-    return body().valid();
+    return body_ && body().valid();
 }
 
 prefix_ bool senf::FileHandle::boolean_test()
@@ -186,18 +186,24 @@ prefix_ int senf::FileHandle::fd()
     return body().fd();
 }
 
+prefix_ senf::FileHandle::FileHandle()
+    : body_(0)
+{}
+
 prefix_  senf::FileHandle::FileHandle(std::auto_ptr<FileBody> body)
     : body_(body.release())
 {}
 
 prefix_ senf::FileBody & senf::FileHandle::body()
 {
+    BOOST_ASSERT(body_);
     return *body_;
 }
 
 prefix_ senf::FileBody const & senf::FileHandle::body()
     const
 {
+    BOOST_ASSERT(body_);
     return *body_;
 }
 
diff --git a/Socket/FileHandle.hh b/Socket/FileHandle.hh
index 303916b53..86cb10f65 100644
--- a/Socket/FileHandle.hh
+++ b/Socket/FileHandle.hh
@@ -28,40 +28,30 @@
 
     \image html FhHierarchy.png
 
-    The senf::FileHandle class is the base of a hierarchy of socket
-    handle classes (realized as templates). These classes provide an
-    interface to the complete socket API. While going down the
-    inheritance hierarchy, the interface will be more and more
-    complete.
-
-    The most complete interface is provided by
-    senf::ProtocolClientSocketHandle and
-    senf::ProtocolServerSocketHandle. The template Arguments specifies
-    the Protocol class of the underlying socket type. These are the
-    \e only classes having public constructors and are therefore the
-    only classes, which may be created by the library user. You will
-    normally use these classes by naming a specific socket typedef
-    (e.g. senf::TCPv4ClientSocketHandle).
-
-    However, to aid writing flexible and generic code, the socket
-    library provides the senf::ClientSocketHandle and
-    senf::ServerSocketHandle class templates. These templates
-    implement a family of closely related classes based on the
-    specification of the socket policy. This policy specification may
-    be \e incomplete (see below). Instances of
-    senf::ClientSocketHandle/senf::ServerSocketHandle can be assigned
-    and converted to different ClientSocketHandle/ServerSocketHandle
-    types as long as the policy specifications are compatible.
-
-    \attention It is very important, to (almost) always pass the socket
-    handle <em>by value</em>. The socket handle is a very lightweight
-    class and designed to be used like an ordinary built-in type. This
-    is very important in combination with the policy interface.
-
-    \note The FileHandle hierarchy below the SocketHandle template is
-    \e not meant to be user extensible. To add new socket types, you
-    should introduce new protocol and/or policy classes, the
-    SocketHandle classes should not be changed.
+    The senf::FileHandle class is the base of a hierarchy of socket handle classes (realized as
+    templates). These classes provide an interface to the complete socket API. While going down the
+    inheritance hierarchy, the interface will be more and more complete.
+
+    The most complete interface is provided by senf::ProtocolClientSocketHandle and
+    senf::ProtocolServerSocketHandle. The template Arguments specifies the Protocol class of the
+    underlying socket type. These are the \e only classes having public constructors and are
+    therefore the only classes, which may be created by the library user. You will normally use
+    these classes by naming a specific socket typedef (e.g. senf::TCPv4ClientSocketHandle).
+
+    However, to aid writing flexible and generic code, the socket library provides the
+    senf::ClientSocketHandle and senf::ServerSocketHandle class templates. These templates implement
+    a family of closely related classes based on the specification of the socket policy. This policy
+    specification may be \e incomplete (see below). Instances of
+    senf::ClientSocketHandle/senf::ServerSocketHandle can be assigned and converted to different
+    ClientSocketHandle/ServerSocketHandle types as long as the policy specifications are compatible.
+
+    \attention It is very important, to (almost) always pass the socket handle <em>by
+    value</em>. The socket handle is a very lightweight class and designed to be used like an
+    ordinary built-in type. This is very important in combination with the policy interface.
+
+    \note The FileHandle hierarchy below the SocketHandle template is \e not meant to be user
+    extensible. To add new socket types, you should introduce new protocol and/or policy classes,
+    the SocketHandle classes should not be changed.
  */
 
 #ifndef HH_FileHandle_
@@ -108,9 +98,6 @@ namespace senf {
         will have to call the protected FileHandle constructor passing a new senf::FileBody
         instance. This instance may either be a simple senf::FileBody or a class derived from
         senf::FileBody.
-
-        \fixme Add public default constructor to allow declaration of (empty) senf::FileHandle
-        variables.
      */
     class FileHandle
         : public SafeBool<FileHandle>
@@ -123,7 +110,9 @@ namespace senf {
         ///\name Structors and default members
         ///@{
 
-        // protected default constructor
+        FileHandle();
+
+        // my default constructor
         // default copy constructor
         // default copy assignment
         // default destructor
diff --git a/Socket/FileHandle.test.cc b/Socket/FileHandle.test.cc
index 262bf0ce0..547bdbff7 100644
--- a/Socket/FileHandle.test.cc
+++ b/Socket/FileHandle.test.cc
@@ -41,7 +41,8 @@ namespace {
     class FHandle : public senf::FileHandle
     {
     public:
-        FHandle(int fd=-1)
+        FHandle() {}
+        FHandle(int fd)
             : senf::FileHandle(std::auto_ptr<senf::FileBody>(
                                           new senf::FileBody(fd))) {}
         FHandle(std::string name)
@@ -66,7 +67,9 @@ BOOST_AUTO_UNIT_TEST(fileHandle)
             BOOST_CHECK(fh);
             BOOST_CHECK(!!fh);
 
-            FHandle fh2(fh);
+            FHandle fh2;
+            BOOST_CHECK( ! fh2.valid() );
+            fh2 = fh;
             BOOST_CHECK_EQUAL(fh.fd(), fh2.fd());
 
             BOOST_CHECK(fh.writeable());
diff --git a/Socket/INetAddressing.cci b/Socket/INetAddressing.cci
index 8af052f7a..eb366ef39 100644
--- a/Socket/INetAddressing.cci
+++ b/Socket/INetAddressing.cci
@@ -58,8 +58,8 @@ prefix_ bool senf::INet4Address::operator==(INet4Address const & other)
 prefix_ std::string senf::INet4Address::host()
     const
 {
-    /** \fixme thread safety? */
-    return std::string(::inet_ntoa(addr_.sin_addr));
+    char buffer[128];
+    return std::string(::inet_ntop(AF_INET,&addr_.sin_addr,buffer,128));
 }
 
 prefix_ unsigned senf::INet4Address::port()
diff --git a/Socket/INetAddressing.hh b/Socket/INetAddressing.hh
index de661cbd1..db2be656d 100644
--- a/Socket/INetAddressing.hh
+++ b/Socket/INetAddressing.hh
@@ -59,9 +59,7 @@ namespace senf {
         INet4Address();
         INet4Address(char const * address); ///< Set address and port
                                         /**< See INet4Address(std::string)
-                                             \throws InvalidINetAddressException
-                                             \fixme Why do I need this version? Shouldn't the
-                                             std::string version be enough ? */
+                                             \throws InvalidINetAddressException */
         INet4Address(std::string address); ///< Set address and port
                                         /**< This constructor expects a string of the form
                                              'xxx.xxx.xxx.xxx:pppp'. The constructor will use this
diff --git a/Socket/ProtocolClientSocketHandle.cti b/Socket/ProtocolClientSocketHandle.cti
index a3e383ebd..2123198a4 100644
--- a/Socket/ProtocolClientSocketHandle.cti
+++ b/Socket/ProtocolClientSocketHandle.cti
@@ -34,6 +34,11 @@
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
+template <class SocketProtocol>
+prefix_ senf::ProtocolClientSocketHandle<SocketProtocol>::
+ProtocolClientSocketHandle(UninitializedType)
+{}
+
 template <class SocketProtocol>
 prefix_ senf::ProtocolClientSocketHandle<SocketProtocol>::ProtocolClientSocketHandle()
     : ClientSocketHandle<typename SocketProtocol::Policy>(
diff --git a/Socket/ProtocolClientSocketHandle.hh b/Socket/ProtocolClientSocketHandle.hh
index f9e456de0..375db13f1 100644
--- a/Socket/ProtocolClientSocketHandle.hh
+++ b/Socket/ProtocolClientSocketHandle.hh
@@ -65,6 +65,7 @@ namespace senf {
         // Types
 
         typedef SocketProtocol Protocol; ///< The sockets protocol
+        enum UninitializedType { Uninitialized }; ///< Flag to call 'uninitialized' constructor
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -84,6 +85,17 @@ namespace senf {
 #       define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 9, "Socket/ProtocolClientSocketHandle.mpp", 1))
 #       include BOOST_PP_ITERATE()
 
+        /** \brief Create uninitialized socket variable
+
+            This special constructor is called when passing
+            ProtocolClientSocketHandle::Uninitialized as only argument to the constructor. This will
+            create an in-\ref valid() socket handle which can however be assigned later with another
+            socket instance.
+
+            \implementation The socket handle will have no \c body allocated.
+         */
+        ProtocolClientSocketHandle(UninitializedType);
+
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
diff --git a/Socket/ProtocolServerSocketHandle.cti b/Socket/ProtocolServerSocketHandle.cti
index 9c7a44907..67abd4c8b 100644
--- a/Socket/ProtocolServerSocketHandle.cti
+++ b/Socket/ProtocolServerSocketHandle.cti
@@ -34,6 +34,11 @@
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
+template <class SocketProtocol>
+prefix_ senf::ProtocolServerSocketHandle<SocketProtocol>::
+ProtocolServerSocketHandle(UninitializedType)
+{}
+
 template <class SocketProtocol>
 prefix_ senf::ProtocolServerSocketHandle<SocketProtocol>::ProtocolServerSocketHandle()
     : ServerSocketHandle<typename SocketProtocol::Policy>(
diff --git a/Socket/ProtocolServerSocketHandle.hh b/Socket/ProtocolServerSocketHandle.hh
index c4bc01ace..af6db4780 100644
--- a/Socket/ProtocolServerSocketHandle.hh
+++ b/Socket/ProtocolServerSocketHandle.hh
@@ -69,6 +69,7 @@ namespace senf {
         // Types
 
         typedef SocketProtocol Protocol; ///< The socket protocol
+        enum UninitializedType { Uninitialized }; ///< Flag to call 'uninitialized' constructor
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -89,6 +90,16 @@ namespace senf {
 #       define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 9, "Socket/ProtocolServerSocketHandle.mpp", 1))
 #       include BOOST_PP_ITERATE()
 
+        /** \brief Create uninitialized socket variable
+
+            This special constructor is called when passing
+            ProtocolServerSocketHandle::Uninitialized as only argument to the constructor. This will
+            create an in-\ref valid() socket handle which can however be assigned later with another
+            socket instance.
+
+            \implementation The socket handle will have no \c body allocated.
+         */
+        ProtocolServerSocketHandle(UninitializedType);
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
diff --git a/Socket/ServerSocketHandle.cti b/Socket/ServerSocketHandle.cti
index 03764f369..1706074d3 100644
--- a/Socket/ServerSocketHandle.cti
+++ b/Socket/ServerSocketHandle.cti
@@ -34,6 +34,10 @@
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
+template <class Policy>
+prefix_ senf::ServerSocketHandle<Policy>::ServerSocketHandle()
+{}
+
 template <class SocketPolicy>
 template <class OtherPolicy>
 prefix_ senf::ServerSocketHandle<SocketPolicy>::
diff --git a/Socket/ServerSocketHandle.hh b/Socket/ServerSocketHandle.hh
index b0960362d..76b2510a3 100644
--- a/Socket/ServerSocketHandle.hh
+++ b/Socket/ServerSocketHandle.hh
@@ -96,11 +96,14 @@ namespace senf {
         ///\name Structors and default members
         ///@{
 
-        // no default constructor
+        // default default constructor
         // default copy constructor
         // default copy assignment
         // default destructor
 
+        // here to implement
+        ServerSocketHandle();
+
         // conversion constructors
         template <class OtherPolicy>
         ServerSocketHandle(ServerSocketHandle<OtherPolicy> other,
diff --git a/Socket/SocketHandle.cti b/Socket/SocketHandle.cti
index 56c147294..3df213cdb 100644
--- a/Socket/SocketHandle.cti
+++ b/Socket/SocketHandle.cti
@@ -34,6 +34,10 @@
 #define prefix_ inline
 ///////////////////////////////cti.p///////////////////////////////////////
 
+template <class SocketPolicy>
+prefix_ senf::SocketHandle<SocketPolicy>::SocketHandle()
+{}
+
 template <class SocketPolicy>
 template <class OtherPolicy>
 prefix_ senf::SocketHandle<SocketPolicy>::SocketHandle(SocketHandle<OtherPolicy> other,
diff --git a/Socket/SocketHandle.hh b/Socket/SocketHandle.hh
index 8cd567fd6..ce67d0e78 100644
--- a/Socket/SocketHandle.hh
+++ b/Socket/SocketHandle.hh
@@ -89,10 +89,14 @@ namespace senf {
         ///\name Structors and default members
         ///@{
 
+        // default default constructor
         // default copy constructor
         // default copy assignment
         // default destructor
 
+        // here to implement
+        SocketHandle();
+
         // conversion constructors
 
         template <class OtherPolicy>
-- 
GitLab