From 46180a6ba259948d3ef993b47615274e6d8ddce7 Mon Sep 17 00:00:00 2001 From: g0dil <g0dil@wiback.org> Date: Fri, 8 Jun 2007 22:56:24 +0000 Subject: [PATCH] Implement more compatible and flexible ClientSocketHandle::write() and writeto() members --- Socket/ClientSocketHandle.ct | 52 +++++++++--------- Socket/ClientSocketHandle.cti | 87 ++++++++++++++++++++++++------- Socket/ClientSocketHandle.hh | 40 +++++++------- Socket/ClientSocketHandle.ih | 30 ++++++++++- Socket/ClientSocketHandle.test.cc | 22 +++++--- Socket/ReadWritePolicy.hh | 12 +++-- Socket/UDPSocketHandle.test.cc | 2 +- 7 files changed, 167 insertions(+), 78 deletions(-) diff --git a/Socket/ClientSocketHandle.ct b/Socket/ClientSocketHandle.ct index 8e51c2bfd..5e3a15005 100644 --- a/Socket/ClientSocketHandle.ct +++ b/Socket/ClientSocketHandle.ct @@ -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>:: @@ -60,6 +56,31 @@ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address return std::copy(buffer, handle.readfrom(buffer,buffer+nread,addr), boost::begin(range)); } +/////////////////////////////////////////////////////////////////////////// +// 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 diff --git a/Socket/ClientSocketHandle.cti b/Socket/ClientSocketHandle.cti index 8ff3396f0..859139948 100644 --- a/Socket/ClientSocketHandle.cti +++ b/Socket/ClientSocketHandle.cti @@ -35,35 +35,63 @@ /////////////////////////////////////////////////////////////////////////// // 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 ) - ic); } +/////////////////////////////////////////////////////////////////////////// +// 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); } //////////////////////////////////////// diff --git a/Socket/ClientSocketHandle.hh b/Socket/ClientSocketHandle.hh index e07dccf99..368e3cdb3 100644 --- a/Socket/ClientSocketHandle.hh +++ b/Socket/ClientSocketHandle.hh @@ -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 diff --git a/Socket/ClientSocketHandle.ih b/Socket/ClientSocketHandle.ih index f3a9c4bb1..6a08543bc 100644 --- a/Socket/ClientSocketHandle.ih +++ b/Socket/ClientSocketHandle.ih @@ -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//////////////////////////////////////// diff --git a/Socket/ClientSocketHandle.test.cc b/Socket/ClientSocketHandle.test.cc index b30395174..ce68451b1 100644 --- a/Socket/ClientSocketHandle.test.cc +++ b/Socket/ClientSocketHandle.test.cc @@ -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) ); diff --git a/Socket/ReadWritePolicy.hh b/Socket/ReadWritePolicy.hh index 3cb649541..3ab6635f3 100644 --- a/Socket/ReadWritePolicy.hh +++ b/Socket/ReadWritePolicy.hh @@ -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 diff --git a/Socket/UDPSocketHandle.test.cc b/Socket/UDPSocketHandle.test.cc index 310268584..be023d0c4 100644 --- a/Socket/UDPSocketHandle.test.cc +++ b/Socket/UDPSocketHandle.test.cc @@ -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"); -- GitLab