Implement more compatible and flexible ClientSocketHandle::write() and writeto()...
g0dil [Fri, 8 Jun 2007 22:56:24 +0000 (22:56 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@255 270642c3-0616-0410-b53a-bc976706d245

Socket/ClientSocketHandle.ct
Socket/ClientSocketHandle.cti
Socket/ClientSocketHandle.hh
Socket/ClientSocketHandle.ih
Socket/ClientSocketHandle.test.cc
Socket/ReadWritePolicy.hh
Socket/UDPSocketHandle.test.cc

index 8e51c2b..5e3a150 100644 (file)
@@ -36,8 +36,6 @@
 ///////////////////////////////////////////////////////////////////////////
 // senf::detail::ReadRange<Handle,ForwardWritableRange,IsContiguous>
 
-// senf::detail::ReadRange<Handle,ForwardWritableRange,IsContiguous>::read
-
 template <class Handle, class ForwardWritableRange, bool IsContiguous>
 prefix_ typename boost::range_iterator<ForwardWritableRange>::type
 senf::detail::ReadRange<Handle,ForwardWritableRange,IsContiguous>::
@@ -48,8 +46,6 @@ read(Handle & handle, ForwardWritableRange & range)
     return std::copy(buffer, handle.read(buffer,buffer+nread), boost::begin(range));
 }
 
-// senf::detail::ReadRange<Handle,ForwardWritableRange,IsContiguous>::readfrom
-
 template <class Handle, class ForwardWritableRange, bool IsContiguous>
 prefix_ typename boost::range_iterator<ForwardWritableRange>::type
 senf::detail::ReadRange<Handle,ForwardWritableRange,IsContiguous>::
@@ -61,6 +57,31 @@ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::detail::WriteRange<Handle,ForwardReadableRange,IsContiguous>
+
+template <class Handle, class ForwardReadableRange, bool IsContiguous>
+prefix_ typename boost::range_iterator<ForwardReadableRange>::type
+senf::detail::WriteRange<Handle,ForwardReadableRange,IsContiguous>::
+write(Handle & handle, ForwardReadableRange & range)
+{
+    typename boost::range_size<ForwardReadableRange>::type nwrite (boost::size(range));
+    SENF_SCOPED_BUFFER(char, buffer, nwrite);
+    std::copy(boost::begin(range), boost::end(range), buffer);
+    return handle.write(std::make_pair(buffer, buffer+nwrite));
+}
+
+template <class Handle, class ForwardReadableRange, bool IsContiguous>
+prefix_ typename boost::range_iterator<ForwardReadableRange>::type
+senf::detail::WriteRange<Handle,ForwardReadableRange,IsContiguous>::
+writeto(Handle & handle, ForwardReadableRange & range, typename Handle::Address const & addr)
+{
+    typename boost::range_size<ForwardReadableRange>::type nwrite (boost::size(range));
+    SENF_SCOPED_BUFFER(char, buffer, nwrite);
+    std::copy(boost::begin(range), boost::end(range), buffer);
+    return handle.writeto(std::make_pair(buffer, buffer+nwrite), addr);
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::ClientSocketHandle<Policy>
 
 ////////////////////////////////////////
@@ -113,29 +134,6 @@ prefix_ void senf::ClientSocketHandle<Policy>::readfrom(Sequence & container, Ad
                     container.end());
 }
 
-// senf::ClientSocketHandle<Policy>::write
-
-template <class Policy>
-prefix_ unsigned senf::ClientSocketHandle<Policy>::write(std::string const & data)
-{
-    unsigned written = this->write(data.data(),data.size());
-    if (written == 0)
-        throw SystemException(EPIPE);
-    // This implementation ensures, we only call blocking() when
-    // necessary (since it incurs a system call overhead ...)
-    if (written < data.size() && this->blocking())
-        // We need to enforce in the WritePolicy implementation, that
-        // DatagramFramingPolicy sockets will ALWAYS either write the
-        // complete datagram or nothing at all
-        while (written < data.size()) {
-            unsigned n = this->write(data.data()+written,data.size()-written);
-            if (n == 0)
-                throw SystemException(EPIPE);
-            written += n;
-        }
-    return written;
-}
-
 ////////////////////////////////////////
 // private members
 
index 8ff3396..8591399 100644 (file)
 ///////////////////////////////////////////////////////////////////////////
 // senf::detail::ReadRange<Policy,ForwardWritableRange,true>
 
-// senf::detail::ReadRange<Policy,ForwardWritableRange,true>::read
-
 template <class Handle, class ForwardWritableRange>
 prefix_ typename boost::range_iterator<ForwardWritableRange>::type
 senf::detail::ReadRange<Handle,ForwardWritableRange,true>::read(Handle & handle,
                                                                 ForwardWritableRange & range)
 {
-    typename boost::range_iterator<ForwardWritableRange>::type i (boost::begin(range));
-    char * ic (reinterpret_cast<char*>(storage_iterator(i)));
+    typename boost::range_iterator<ForwardWritableRange>::type const i (boost::begin(range));
+    char * const ic (reinterpret_cast<char*>(storage_iterator(i)));
     return i + (handle.read( ic, 
                              reinterpret_cast<char*>(storage_iterator(boost::end(range))) )
                 - ic);
 }
 
-// senf::detail::ReadRange<Policy,ForwardWritableRange,true>::readfrom
-
 template <class Handle, class ForwardWritableRange>
 prefix_ typename boost::range_iterator<ForwardWritableRange>::type
 senf::detail::ReadRange<Handle,ForwardWritableRange,true>::
 readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr)
 {
-    typename boost::range_iterator<ForwardWritableRange>::type i (boost::begin(range));
-    char * ic (reinterpret_cast<char*>(storage_iterator(i)));
+    typename boost::range_iterator<ForwardWritableRange>::type const i (boost::begin(range));
+    char * const ic (reinterpret_cast<char*>(storage_iterator(i)));
     return i + (handle.readfrom( ic, 
                                  reinterpret_cast<char*>(storage_iterator(boost::end(range))),
                                  addr )
@@ -65,6 +61,38 @@ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::detail::WriteRange<Handle, ForwardReadableRange, true>
+
+template <class Handle, class ForwardReadableRange>
+prefix_ typename boost::range_const_iterator<ForwardReadableRange>::type
+senf::detail::WriteRange<Handle, ForwardReadableRange, true>::
+write(Handle & handle, ForwardReadableRange & range)
+{
+    typename boost::range_const_iterator<ForwardReadableRange>::type const i 
+        (boost::const_begin(range));
+    char const * const ic (reinterpret_cast<char const *>(storage_iterator(i)));
+    return i + (handle.write(ic,
+                             reinterpret_cast<char const *>(
+                                 storage_iterator(boost::const_end(range))))
+                - ic);
+}
+
+template <class Handle, class ForwardReadableRange>
+prefix_ typename boost::range_const_iterator<ForwardReadableRange>::type
+senf::detail::WriteRange<Handle, ForwardReadableRange, true>::
+writeto(Handle & handle, ForwardReadableRange & range, typename Handle::Address const & addr)
+{
+    typename boost::range_const_iterator<ForwardReadableRange>::type const i 
+        (boost::const_begin(range));
+    char const * const ic (reinterpret_cast<char const *>(storage_iterator(i)));
+    return i + (handle.writeto(addr,
+                               ic,
+                               reinterpret_cast<char const *>(
+                                   storage_iterator(boost::const_end(range))))
+                - ic);
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::ClientSocketHandle<Policy>
 
 ////////////////////////////////////////
@@ -144,7 +172,7 @@ prefix_ char * senf::ClientSocketHandle<Policy>::read(char * start, char * end)
 
 template <class Policy>
 template <class ForwardWritableRange>
-prefix_ typename boost::range_iterator<ForwardWritableRange>::type
+prefix_ typename boost::range_iterator<ForwardWritableRange const>::type
 senf::ClientSocketHandle<Policy>::readfrom(ForwardWritableRange const & range, Address & from)
 {
     return detail::ReadRange< 
@@ -180,28 +208,47 @@ prefix_ char * senf::ClientSocketHandle<Policy>::readfrom(char * start, char * e
 // senf::ClientSocketHandle<Policy>::write
 
 template <class Policy>
-prefix_ unsigned senf::ClientSocketHandle<Policy>::write(char const * buffer,
-                                                                unsigned size)
+template <class ForwardReadableRange>
+prefix_ typename boost::range_const_iterator<ForwardReadableRange const>::type
+senf::ClientSocketHandle<Policy>::write(ForwardReadableRange const & range)
 {
-    return Policy::WritePolicy::write(*this, buffer, size);
+    return detail::WriteRange<
+        ClientSocketHandle<Policy>,
+        ForwardReadableRange const,
+        contiguous_storage_iterator<
+            typename boost::range_iterator<ForwardReadableRange>::type
+        >::value && sizeof(typename boost::range_value<ForwardReadableRange>::type)==sizeof(char)
+        >::write(*this, range);
+}
+
+template <class Policy>
+prefix_ char const * senf::ClientSocketHandle<Policy>::write(char const * start, char const * end)
+{
+    return start + Policy::WritePolicy::write(*this, start, end-start);
 }
 
 // senf::ClientSocketHandle<Policy>::writeto
 
 template <class Policy>
-prefix_ unsigned senf::ClientSocketHandle<Policy>::
-writeto(typename boost::call_traits<typename Policy::AddressingPolicy::Address>::param_type addr,
-        std::string const & data)
+template <class ForwardReadableRange>
+prefix_ typename boost::range_const_iterator<ForwardReadableRange const>::type
+senf::ClientSocketHandle<Policy>::writeto(AddressParam addr, ForwardReadableRange const & range)
 {
-    return this->writeto(addr, data.data(), data.size());
+    return detail::WriteRange<
+        ClientSocketHandle<Policy>,
+        ForwardReadableRange const,
+        contiguous_storage_iterator<
+            typename boost::range_iterator<ForwardReadableRange>::type
+        >::value && sizeof(typename boost::range_value<ForwardReadableRange>::type)==sizeof(char)
+        >::writeto(*this, range, addr);
 }
 
 template <class Policy>
-prefix_ unsigned senf::ClientSocketHandle<Policy>::
-writeto(typename boost::call_traits<typename Policy::AddressingPolicy::Address>::param_type addr,
-        char const * buffer, unsigned size)
+prefix_ char const * senf::ClientSocketHandle<Policy>::writeto(AddressParam addr,
+                                                               char const * start,
+                                                               char const * end)
 {
-    return Policy::WritePolicy::writeto(*this, addr, buffer, size);
+    return start + Policy::WritePolicy::writeto(*this, addr, start, end-start);
 }
 
 ////////////////////////////////////////
index e07dccf..368e3cd 100644 (file)
@@ -229,7 +229,7 @@ namespace senf {
         std::pair<std::string, Address>
                      readfrom     (unsigned limit=0);
         template <class ForwardWritableRange>
-        typename boost::range_iterator<ForwardWritableRange>::type
+        typename boost::range_iterator<ForwardWritableRange const>::type
                      readfrom     (ForwardWritableRange const & range, Address & from);
                                         ///< Read data into range
                                         /**< Read data into the given range. At most
@@ -288,20 +288,22 @@ namespace senf {
             \throws senf::SystemException
 
 
-            This variant will write out the string \c data.
+            This variant will write out the range \c data.
 
-            \param[in] data Data to write
-            \returns number of bytes written
+            \param[in] range Data to write
+            \returns past-the-end iterator after last element written
             \implementation The write() family of members will use POSIX \c write calls, not \c
                 send.
          */
-        unsigned     write        (std::string const & data);
-        unsigned     write        (char const * buffer, unsigned size);
+        template <class ForwardReadableRange>
+        typename boost::range_const_iterator<ForwardReadableRange const>::type
+                     write        (ForwardReadableRange const & range);
+        char const * write        (char const * start, char const * end);
                                         ///< Write data to socket from memory buffer
-                                        /**< \param[in] buffer address of buffer to write
-                                           \param[in] size amount of data to write
-                                           \returns Number of bytes written
-                                           \see \ref write() */
+                                        /**< \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() */
 
         /** \brief Write data to unconnected socket
 
@@ -315,20 +317,22 @@ namespace senf {
             \throw senf::SystemException
 
 
-            This variant will send the string \c data to the peer \c addr.
+            This variant will send the range \c range to peer \c addr.
 
             \param[in] addr Address of peer to send data to
-            \param[in] data data to send
+            \param[in] range data to send
             \returns Number of bytes written
          */
-        unsigned     writeto      (AddressParam addr, std::string const & data);
-        unsigned     writeto      (AddressParam addr, char const * buffer, unsigned size);
+        template <class ForwardReadableRange>
+        typename boost::range_const_iterator<ForwardReadableRange const>::type
+                     writeto      (AddressParam addr, ForwardReadableRange const & range);
+        char const * writeto      (AddressParam addr, char const * start, char const * end);
                                         ///< Write data from memory buffer to unconnected socket
                                         /**< \param[in] addr Address of peer to send data to
-                                           \param[in] buffer address of buffer to write
-                                           \param[in] size amount of data to write
-                                           \returns Number of bytes written
-                                           \see \ref writeto() */
+                                             \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() */
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Addressing
index f3a9c4b..6a08543 100644 (file)
@@ -32,6 +32,9 @@
 namespace senf {
 namespace detail {
 
+    ///////////////////////////////////////////////////////////////////////
+    // senf::detail::ReadRange
+
     template <class Handle, class ForwardWritableRange, bool IsContiguous>
     struct ReadRange 
     {
@@ -43,7 +46,7 @@ namespace detail {
     };
 
     template <class Handle, class ForwardWritableRange>
-    struct ReadRange<Handle,ForwardWritableRange,true>
+    struct ReadRange<Handle, ForwardWritableRange, true>
     {
         static typename boost::range_iterator<ForwardWritableRange>::type
         read(Handle & handle, ForwardWritableRange & range);
@@ -52,6 +55,31 @@ namespace detail {
         readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr);
     };
 
+    ///////////////////////////////////////////////////////////////////////
+    // senf::detail::WriteRange
+
+    template <class Handle, class ForwardReadableRange, bool IsContiguous>
+    struct WriteRange
+    {
+        static typename boost::range_iterator<ForwardReadableRange>::type
+        write(Handle & handle, ForwardReadableRange & range);
+        
+        static typename boost::range_iterator<ForwardReadableRange>::type
+        writeto(Handle & handle, ForwardReadableRange & range,
+                typename Handle::Address const & addr);
+    };
+
+    template <class Handle, class ForwardReadableRange>
+    struct WriteRange<Handle, ForwardReadableRange, true>
+    {
+        static typename boost::range_const_iterator<ForwardReadableRange>::type
+        write(Handle & handle, ForwardReadableRange & range);
+        
+        static typename boost::range_const_iterator<ForwardReadableRange>::type
+        writeto(Handle & handle, ForwardReadableRange & range,
+                typename Handle::Address const & addr);
+    };
+
 }}
 
 ///////////////////////////////ih.e////////////////////////////////////////
index b303951..ce68451 100644 (file)
@@ -93,7 +93,7 @@ BOOST_AUTO_UNIT_TEST(clientSocketHandle)
     {
         char buf[11];
         ::strcpy(buf,"0123456789");
-        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.read(buf,buf+10), buf+9u ) );
+        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.read(buf,buf+10), buf+9 ) );
         BOOST_CHECK_EQUAL( buf, "TEST-READ9" );
     }
 
@@ -108,15 +108,23 @@ BOOST_AUTO_UNIT_TEST(clientSocketHandle)
         char buf[11];
         unsigned addr;
         ::strcpy(buf,"0123456789");
-        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.readfrom(buf,buf+10,addr), buf+9u ) );
+        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.readfrom(buf,buf+10,addr), buf+9 ) );
         BOOST_CHECK_EQUAL( buf, "TEST-READ9" );
     }
 
-    BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.write("TEST-WRITE"), 10u ) );
-    BOOST_CHECK_THROW( myh.write("TEST"),senf::SystemException );
-    BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.write("TEST-WRITE9",10), 10u ) );
-    BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.writeto(0,"TEST-WRITE"), 10u ) );
-    BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.writeto(0,"TEST-WRITE9",10), 10u ) );
+    {
+        std::string s ("TEST-WRITE");
+        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.write(s)-s.begin(), 10 ) );
+        s = "TEST";
+        // This simulates a closed file in this test policy. However, we
+        // have changed the semantics so this will not work anymore.
+        // BOOST_CHECK_THROW( myh.write(s),senf::SystemException );
+        char const * const s1 = "TEST-WRITE9";
+        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.write(s1,s1+10), s1+10u ) );
+        s = "TEST-WRITE";
+        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.writeto(0,s)-s.begin(), 10 ) );
+        BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.writeto(0,s1,s1+10), s1+10 ) );
+    }
 
     BOOST_CHECK_NO_THROW( myh.connect(0) );
     BOOST_CHECK_NO_THROW( myh.bind(0) );
index 3cb6495..3ab6635 100644 (file)
@@ -61,7 +61,8 @@ namespace senf {
         template <class Policy>
         static unsigned readfrom(ClientSocketHandle<Policy> handle, char * buffer, unsigned size,
                                  typename Policy::AddressingPolicy::Address & address,
-                                 typename IfCommunicationPolicyIs<Policy,UnconnectedCommunicationPolicy>::type * = 0);
+                                 typename IfCommunicationPolicyIs<
+                                     Policy,UnconnectedCommunicationPolicy>::type * = 0);
                                         ///< read data from socket returning peer address
                                         /**< \param[in] handle socket handle to read from
                                              \param[in] buffer address of buffer to write data to
@@ -92,7 +93,8 @@ namespace senf {
     {
         template <class Policy>
         static unsigned write(ClientSocketHandle<Policy> handle, char const * buffer, unsigned size,
-                              typename IfCommunicationPolicyIs<Policy,ConnectedCommunicationPolicy>::type * = 0);
+                              typename IfCommunicationPolicyIs<
+                                  Policy,ConnectedCommunicationPolicy>::type * = 0);
                                         ///< write data to socket
                                         /**< This member is only enabled if the socket uses
                                              connected communication. Otherwise the communication
@@ -105,9 +107,11 @@ namespace senf {
                                              \returns number of bytes written */
         template <class Policy>
         static unsigned writeto(ClientSocketHandle<Policy> handle,
-                                typename boost::call_traits<typename Policy::AddressingPolicy::Address>::param_type addr,
+                                typename boost::call_traits<
+                                    typename Policy::AddressingPolicy::Address>::param_type addr,
                                 char const * buffer, unsigned size,
-                                typename IfCommunicationPolicyIs<Policy,UnconnectedCommunicationPolicy>::type * = 0);
+                                typename IfCommunicationPolicyIs<
+                                    Policy,UnconnectedCommunicationPolicy>::type * = 0);
                                         ///< write data to socket sending to given peer
                                         /**< This member is only enabled if the socket uses
                                              unconnected communication. Otherwise no target may be
index 3102685..be023d0 100644 (file)
@@ -148,7 +148,7 @@ BOOST_AUTO_UNIT_TEST(udpv4ClientSocketHandle)
         BOOST_CHECK_EQUAL( sock.rcvbuf(), 2048u );
         BOOST_CHECK_NO_THROW( sock.sndbuf(2048) );
         BOOST_CHECK_EQUAL( sock.sndbuf(), 2048u );
-        BOOST_CHECK_NO_THROW( sock.writeto("127.0.0.1:12345","TEST-WRITE") );
+        BOOST_CHECK_NO_THROW( sock.writeto("127.0.0.1:12345", std::string("TEST-WRITE")) );
         BOOST_CHECK_EQUAL( sock.read(), "TEST-WRITE" );
         BOOST_CHECK_NO_THROW( sock.protocol().timestamp() );
         sock.writeto("127.0.0.1:12345","QUIT");