From: g0dil Date: Fri, 8 Jun 2007 22:56:24 +0000 (+0000) Subject: Implement more compatible and flexible ClientSocketHandle::write() and writeto()... X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=11e54a3241bf7c58b4b418a24abea04d12a683aa;p=senf.git Implement more compatible and flexible ClientSocketHandle::write() and writeto() members git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@255 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Socket/ClientSocketHandle.ct b/Socket/ClientSocketHandle.ct index 8e51c2b..5e3a150 100644 --- a/Socket/ClientSocketHandle.ct +++ b/Socket/ClientSocketHandle.ct @@ -36,8 +36,6 @@ /////////////////////////////////////////////////////////////////////////// // senf::detail::ReadRange -// senf::detail::ReadRange::read - template prefix_ typename boost::range_iterator::type senf::detail::ReadRange:: @@ -48,8 +46,6 @@ read(Handle & handle, ForwardWritableRange & range) return std::copy(buffer, handle.read(buffer,buffer+nread), boost::begin(range)); } -// senf::detail::ReadRange::readfrom - template prefix_ typename boost::range_iterator::type senf::detail::ReadRange:: @@ -61,6 +57,31 @@ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address } /////////////////////////////////////////////////////////////////////////// +// senf::detail::WriteRange + +template +prefix_ typename boost::range_iterator::type +senf::detail::WriteRange:: +write(Handle & handle, ForwardReadableRange & range) +{ + typename boost::range_size::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 +prefix_ typename boost::range_iterator::type +senf::detail::WriteRange:: +writeto(Handle & handle, ForwardReadableRange & range, typename Handle::Address const & addr) +{ + typename boost::range_size::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 //////////////////////////////////////// @@ -113,29 +134,6 @@ prefix_ void senf::ClientSocketHandle::readfrom(Sequence & container, Ad container.end()); } -// senf::ClientSocketHandle::write - -template -prefix_ unsigned senf::ClientSocketHandle::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 8ff3396..8591399 100644 --- a/Socket/ClientSocketHandle.cti +++ b/Socket/ClientSocketHandle.cti @@ -35,29 +35,25 @@ /////////////////////////////////////////////////////////////////////////// // senf::detail::ReadRange -// senf::detail::ReadRange::read - template prefix_ typename boost::range_iterator::type senf::detail::ReadRange::read(Handle & handle, ForwardWritableRange & range) { - typename boost::range_iterator::type i (boost::begin(range)); - char * ic (reinterpret_cast(storage_iterator(i))); + typename boost::range_iterator::type const i (boost::begin(range)); + char * const ic (reinterpret_cast(storage_iterator(i))); return i + (handle.read( ic, reinterpret_cast(storage_iterator(boost::end(range))) ) - ic); } -// senf::detail::ReadRange::readfrom - template prefix_ typename boost::range_iterator::type senf::detail::ReadRange:: readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr) { - typename boost::range_iterator::type i (boost::begin(range)); - char * ic (reinterpret_cast(storage_iterator(i))); + typename boost::range_iterator::type const i (boost::begin(range)); + char * const ic (reinterpret_cast(storage_iterator(i))); return i + (handle.readfrom( ic, reinterpret_cast(storage_iterator(boost::end(range))), addr ) @@ -65,6 +61,38 @@ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address } /////////////////////////////////////////////////////////////////////////// +// senf::detail::WriteRange + +template +prefix_ typename boost::range_const_iterator::type +senf::detail::WriteRange:: +write(Handle & handle, ForwardReadableRange & range) +{ + typename boost::range_const_iterator::type const i + (boost::const_begin(range)); + char const * const ic (reinterpret_cast(storage_iterator(i))); + return i + (handle.write(ic, + reinterpret_cast( + storage_iterator(boost::const_end(range)))) + - ic); +} + +template +prefix_ typename boost::range_const_iterator::type +senf::detail::WriteRange:: +writeto(Handle & handle, ForwardReadableRange & range, typename Handle::Address const & addr) +{ + typename boost::range_const_iterator::type const i + (boost::const_begin(range)); + char const * const ic (reinterpret_cast(storage_iterator(i))); + return i + (handle.writeto(addr, + ic, + reinterpret_cast( + storage_iterator(boost::const_end(range)))) + - ic); +} + +/////////////////////////////////////////////////////////////////////////// // senf::ClientSocketHandle //////////////////////////////////////// @@ -144,7 +172,7 @@ prefix_ char * senf::ClientSocketHandle::read(char * start, char * end) template template -prefix_ typename boost::range_iterator::type +prefix_ typename boost::range_iterator::type senf::ClientSocketHandle::readfrom(ForwardWritableRange const & range, Address & from) { return detail::ReadRange< @@ -180,28 +208,47 @@ prefix_ char * senf::ClientSocketHandle::readfrom(char * start, char * e // senf::ClientSocketHandle::write template -prefix_ unsigned senf::ClientSocketHandle::write(char const * buffer, - unsigned size) +template +prefix_ typename boost::range_const_iterator::type +senf::ClientSocketHandle::write(ForwardReadableRange const & range) { - return Policy::WritePolicy::write(*this, buffer, size); + return detail::WriteRange< + ClientSocketHandle, + ForwardReadableRange const, + contiguous_storage_iterator< + typename boost::range_iterator::type + >::value && sizeof(typename boost::range_value::type)==sizeof(char) + >::write(*this, range); +} + +template +prefix_ char const * senf::ClientSocketHandle::write(char const * start, char const * end) +{ + return start + Policy::WritePolicy::write(*this, start, end-start); } // senf::ClientSocketHandle::writeto template -prefix_ unsigned senf::ClientSocketHandle:: -writeto(typename boost::call_traits::param_type addr, - std::string const & data) +template +prefix_ typename boost::range_const_iterator::type +senf::ClientSocketHandle::writeto(AddressParam addr, ForwardReadableRange const & range) { - return this->writeto(addr, data.data(), data.size()); + return detail::WriteRange< + ClientSocketHandle, + ForwardReadableRange const, + contiguous_storage_iterator< + typename boost::range_iterator::type + >::value && sizeof(typename boost::range_value::type)==sizeof(char) + >::writeto(*this, range, addr); } template -prefix_ unsigned senf::ClientSocketHandle:: -writeto(typename boost::call_traits::param_type addr, - char const * buffer, unsigned size) +prefix_ char const * senf::ClientSocketHandle::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 e07dccf..368e3cd 100644 --- a/Socket/ClientSocketHandle.hh +++ b/Socket/ClientSocketHandle.hh @@ -229,7 +229,7 @@ namespace senf { std::pair readfrom (unsigned limit=0); template - typename boost::range_iterator::type + typename boost::range_iterator::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 + typename boost::range_const_iterator::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 + typename boost::range_const_iterator::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 f3a9c4b..6a08543 100644 --- a/Socket/ClientSocketHandle.ih +++ b/Socket/ClientSocketHandle.ih @@ -32,6 +32,9 @@ namespace senf { namespace detail { + /////////////////////////////////////////////////////////////////////// + // senf::detail::ReadRange + template struct ReadRange { @@ -43,7 +46,7 @@ namespace detail { }; template - struct ReadRange + struct ReadRange { static typename boost::range_iterator::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 + struct WriteRange + { + static typename boost::range_iterator::type + write(Handle & handle, ForwardReadableRange & range); + + static typename boost::range_iterator::type + writeto(Handle & handle, ForwardReadableRange & range, + typename Handle::Address const & addr); + }; + + template + struct WriteRange + { + static typename boost::range_const_iterator::type + write(Handle & handle, ForwardReadableRange & range); + + static typename boost::range_const_iterator::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 b303951..ce68451 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 3cb6495..3ab6635 100644 --- a/Socket/ReadWritePolicy.hh +++ b/Socket/ReadWritePolicy.hh @@ -61,7 +61,8 @@ namespace senf { template static unsigned readfrom(ClientSocketHandle handle, char * buffer, unsigned size, typename Policy::AddressingPolicy::Address & address, - typename IfCommunicationPolicyIs::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 static unsigned write(ClientSocketHandle handle, char const * buffer, unsigned size, - typename IfCommunicationPolicyIs::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 static unsigned writeto(ClientSocketHandle handle, - typename boost::call_traits::param_type addr, + typename boost::call_traits< + typename Policy::AddressingPolicy::Address>::param_type addr, char const * buffer, unsigned size, - typename IfCommunicationPolicyIs::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 3102685..be023d0 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");