From: g0dil Date: Fri, 8 Jun 2007 12:31:06 +0000 (+0000) Subject: Ipmlemented more compatible, standards conformant and flexible ClientSocketHandle... X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=7a1872f6702d6206bf1d8364c4e894f98d1c64f0;p=senf.git Ipmlemented more compatible, standards conformant and flexible ClientSocketHandle::read() and readfrom() members git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@254 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Socket/ClientSocketHandle.ct b/Socket/ClientSocketHandle.ct index 17a518e..8e51c2b 100644 --- a/Socket/ClientSocketHandle.ct +++ b/Socket/ClientSocketHandle.ct @@ -24,13 +24,50 @@ \brief ClientSocketHandle non-inline template implementation */ -//#include "ClientSocketHandle.ih" +#include "ClientSocketHandle.ih" // Custom includes +#include +#include "Utils/Buffer.hh" #define prefix_ ///////////////////////////////ct.p//////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +// 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_size::type nread (boost::size(range)); + SENF_SCOPED_BUFFER(char, buffer, nread); + 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:: +readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr) +{ + typename boost::range_size::type nread (boost::size(range)); + SENF_SCOPED_BUFFER(char, buffer, nread); + return std::copy(buffer, handle.readfrom(buffer,buffer+nread,addr), boost::begin(range)); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::ClientSocketHandle + +//////////////////////////////////////// +// reading and writing + +// senf::ClientSocketHandle::read + template prefix_ std::string senf::ClientSocketHandle::read(unsigned limit) { @@ -40,40 +77,44 @@ prefix_ std::string senf::ClientSocketHandle::read(unsigned limit) } template -prefix_ void senf::ClientSocketHandle::read(std::string & buffer, unsigned limit) +template +prefix_ void senf::ClientSocketHandle::read(Sequence & container, unsigned limit) { - unsigned nread = available(); + unsigned nread (available()); if (limit>0 && nread>limit) nread = limit; - /** \fixme This is not necessary correct and more or less a hack ... */ - buffer.assign(nread,0); - unsigned rv = this->read(const_cast(buffer.data()),nread); - if (rv < nread) - buffer.erase(buffer.begin()+rv,buffer.end()); + container.resize(nread); + container.erase(read( std::make_pair(container.begin(), container.end()) ), + container.end()); } +// senf::ClientSocketHandle::readfrom + template prefix_ std::pair -senf::ClientSocketHandle::readfrom() +senf::ClientSocketHandle::readfrom(unsigned limit) { std::string rv; typename Policy::AddressingPolicy::Address addr; - this->readfrom(rv,addr); + this->readfrom(rv,addr,limit); return std::make_pair(rv,addr); } template -prefix_ void senf::ClientSocketHandle:: -readfrom(std::string & buffer, typename Policy::AddressingPolicy::Address & from) +template +prefix_ void senf::ClientSocketHandle::readfrom(Sequence & container, Address & from, + unsigned limit) { - unsigned nread = available(); - /** \fixme This is not necessary correct and more or less a hack ... */ - buffer.assign(nread,0); - unsigned rv = this->readfrom(const_cast(buffer.data()), nread, from); - if (rv < nread) - buffer.erase(buffer.begin()+rv,buffer.end()); + unsigned nread (available()); + if (limit>0 && nread>limit) + nread = limit; + container.resize(nread); + container.erase(readfrom( std::make_pair(container.begin(), container.end()), from ), + container.end()); } +// senf::ClientSocketHandle::write + template prefix_ unsigned senf::ClientSocketHandle::write(std::string const & data) { @@ -95,6 +136,11 @@ prefix_ unsigned senf::ClientSocketHandle::write(std::string const & dat return written; } +//////////////////////////////////////// +// private members + +// senf::ClientSocketHandle::available + template prefix_ unsigned senf::ClientSocketHandle::available() { diff --git a/Socket/ClientSocketHandle.cti b/Socket/ClientSocketHandle.cti index e328d9c..8ff3396 100644 --- a/Socket/ClientSocketHandle.cti +++ b/Socket/ClientSocketHandle.cti @@ -24,7 +24,7 @@ \brief ClientSocketHandle inline template implementation */ -//#include "ClientSocketHandle.ih" +#include "ClientSocketHandle.ih" // Custom includes #include @@ -32,24 +32,62 @@ #define prefix_ inline ///////////////////////////////cti.p/////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +// 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))); + 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))); + return i + (handle.readfrom( ic, + reinterpret_cast(storage_iterator(boost::end(range))), + addr ) + - ic); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::ClientSocketHandle + +//////////////////////////////////////// +// structors + template template prefix_ senf::ClientSocketHandle:: ClientSocketHandle(ClientSocketHandle other, typename SocketHandle::template IsCompatible::type *) - : SocketHandle(other,true) + : SocketHandle(other,true) {} template -prefix_ senf::ClientSocketHandle::ClientSocketHandle(FileHandle other, - bool isChecked) - : SocketHandle(other, isChecked) +prefix_ senf::ClientSocketHandle::ClientSocketHandle(FileHandle other, bool isChecked) + : SocketHandle(other, isChecked) {} template -prefix_ senf::ClientSocketHandle:: -ClientSocketHandle(std::auto_ptr protocol, int fd) - : SocketHandle(protocol,false) +prefix_ +senf::ClientSocketHandle::ClientSocketHandle(std::auto_ptr protocol, + int fd) + : SocketHandle(protocol,false) { this->body().fd(fd); } @@ -63,32 +101,93 @@ senf::ClientSocketHandle::operator=(ClientSocketHandle othe return *this; } -/////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// // reading and writing +// senf::ClientSocketHandle::read + template -prefix_ unsigned senf::ClientSocketHandle::read(char * buffer, - unsigned size) +template +prefix_ typename boost::range_iterator::type +senf::ClientSocketHandle::read(ForwardWritableRange const & range) { - return Policy::ReadPolicy::read(*this, buffer, size); + return detail::ReadRange< + ClientSocketHandle, + ForwardWritableRange const, + contiguous_storage_iterator< + typename boost::range_iterator::type + >::value && sizeof(typename boost::range_value::type)==sizeof(char) + >::read(*this, range); } template -prefix_ unsigned senf::ClientSocketHandle:: -readfrom(char * buffer, unsigned size, typename Policy::AddressingPolicy::Address & from) +template +prefix_ typename boost::range_iterator::type +senf::ClientSocketHandle::read(ForwardWritableRange & range) { - return Policy::ReadPolicy::readfrom(*this, buffer, size, from); + return detail::ReadRange< + ClientSocketHandle, + ForwardWritableRange, + contiguous_storage_iterator< + typename boost::range_iterator::type + >::value && sizeof(typename boost::range_value::type)==sizeof(char) + >::read(*this, range); } template +prefix_ char * senf::ClientSocketHandle::read(char * start, char * end) +{ + return start + Policy::ReadPolicy::read(*this, start, end-start); +} + +// senf::ClientSocketHandle::readfrom + +template +template +prefix_ typename boost::range_iterator::type +senf::ClientSocketHandle::readfrom(ForwardWritableRange const & range, Address & from) +{ + return detail::ReadRange< + ClientSocketHandle, + ForwardWritableRange const, + contiguous_storage_iterator< + typename boost::range_iterator::type + >::value && sizeof(typename boost::range_value::type)==sizeof(char) + >::readfrom(*this, range, from); +} + +template +template +prefix_ typename boost::range_iterator::type +senf::ClientSocketHandle::readfrom(ForwardWritableRange & range, Address & from) +{ + return detail::ReadRange< + ClientSocketHandle, + ForwardWritableRange, + contiguous_storage_iterator< + typename boost::range_iterator::type + >::value && sizeof(typename boost::range_value::type)==sizeof(char) + >::readfrom(*this, range, from); +} + +template +prefix_ char * senf::ClientSocketHandle::readfrom(char * start, char * end, + Address & from) +{ + return start + Policy::ReadPolicy::readfrom(*this, start, end-start, from); +} + +// senf::ClientSocketHandle::write + +template prefix_ unsigned senf::ClientSocketHandle::write(char const * buffer, unsigned size) { return Policy::WritePolicy::write(*this, buffer, size); } +// senf::ClientSocketHandle::writeto + template prefix_ unsigned senf::ClientSocketHandle:: writeto(typename boost::call_traits::param_type addr, @@ -105,9 +204,11 @@ writeto(typename boost::call_traits: return Policy::WritePolicy::writeto(*this, addr, buffer, size); } -/////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// // addressing +// senf::ClientSocketHandle::peer + template prefix_ typename Policy::AddressingPolicy::Address senf::ClientSocketHandle::peer() @@ -124,6 +225,8 @@ peer(typename Policy::AddressingPolicy::Address & addr) Policy::AddressingPolicy::peer(*this,addr); } +// senf::ClientSocketHandle::local + template prefix_ typename Policy::AddressingPolicy::Address senf::ClientSocketHandle::local() @@ -140,12 +243,16 @@ local(typename Policy::AddressingPolicy::Address & addr) Policy::AddressingPolicy::local(*this,addr); } +// senf::ClientSocketHandle::connect + template prefix_ void senf::ClientSocketHandle::connect(AddressParam addr) { Policy::AddressingPolicy::connect(*this,addr); } +// senf::ClientSocketHandle::bind + template prefix_ void senf::ClientSocketHandle:: bind(typename boost::call_traits::param_type addr) @@ -153,9 +260,11 @@ bind(typename boost::call_traits::pa Policy::AddressingPolicy::bind(*this,addr); } -/////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// // Buffering +// senf::ClientSocketHandle::rcvbuf + template prefix_ unsigned senf::ClientSocketHandle::rcvbuf() { @@ -168,6 +277,8 @@ prefix_ void senf::ClientSocketHandle::rcvbuf(unsigned size) Policy::BufferingPolicy::rcvbuf(*this,size); } +// senf::ClientSocketHandle::sndbuf + template prefix_ unsigned senf::ClientSocketHandle::sndbuf() { @@ -180,7 +291,8 @@ prefix_ void senf::ClientSocketHandle::sndbuf(unsigned size) Policy::BufferingPolicy::sndbuf(*this,size); } -/////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// +// Casting template prefix_ senf::ClientSocketHandle @@ -199,6 +311,9 @@ senf::ClientSocketHandle::cast_dynamic(FileHandle handle) return cast_static(handle); } +//////////////////////////////////////// +// State information + template prefix_ void senf::ClientSocketHandle::state(SocketStateMap & map, unsigned lod) { diff --git a/Socket/ClientSocketHandle.hh b/Socket/ClientSocketHandle.hh index 29f1903..e07dccf 100644 --- a/Socket/ClientSocketHandle.hh +++ b/Socket/ClientSocketHandle.hh @@ -29,6 +29,7 @@ // Custom includes #include +#include #include "SocketHandle.hh" //#include "ClientSocketHandle.mpp" @@ -139,27 +140,27 @@ namespace senf { /** \brief Read data from socket If the sockets \c FramingPolicy is \c DatagramFramingPolicy, every read() command will - return a single datagram. If the sockets FramingPolicy is StreamFraming, the operation will - return as much data as possible from the socket buffer. However it cannot be guaranteed, - that the socket buffer will be empty after read() returns. + return a single datagram. If the sockets FramingPolicy is StreamFraming, the operation + will return as much data as possible from the socket buffer. However it cannot be + guaranteed, that the socket buffer will be empty after read() returns. \attention If the space available for the data read is limited, the read will return no more than that amount of data. For a datagram socket, a full datagram is still dequeued from the socket buffer, the remainder of the datagram will be lost. - There are three variants of read which differ in how they return the read string. + There are several variants of read which differ in how they return the read string. - \throws senf::SystemException + If the further document doesn't tell something differently, on a blocking socket the + members will \e always return some data (as long as the socket has not been closed at + the other end) and will block, if no data is available now. If you do not want to block, + you \e must make the socket non-blocking (using FileHandle::blocking()). + + \throws senf::SystemException This variant will read up to \c limit bytes from the socket and return them as a \c std::string object. - On a blocking socket, this member will \e always return some data (as long as the socket - has not been closed at the other end) and will block, if no data is available now. If - you do not want to block, you \e must make the socket non-blocking (using - FileHandle::blocking()). - \param[in] limit Maximum number of bytes to read or 0 if unlimited. \returns data read @@ -167,55 +168,102 @@ namespace senf { \c recv. */ std::string read (unsigned limit=0); - void read (std::string & buffer, unsigned limit=0); - ///< Read data into string buffer - /**< On a blocking socket, this member will \e always return - some data (as long as the socket has not been closed at - the other end) and will block, if no data is available - now. If you do not want to block, you \e must make the - socket non-blocking (using FileHandle::blocking()). - \param[out] buffer data read - \param[in] limit Maximum number of bytes to read or 0 - if unlimited - \see \ref read() */ - unsigned read (char * buffer, unsigned size); + template + typename boost::range_iterator::type + read (ForwardWritableRange const & range); + ///< Read data into range + /**< Read data into the given range. At most + boost::size(range) characters are read. The + data read will start at the beginning of the + range. read returns a past-the-end iterator after the + last character read. This iterator will point to + somewhere within the input range. + \param[in/out] range Range to store data in + \returns past-the-end iterator pointer to after the + last read character + \see \ref read() */ + template + typename boost::range_iterator::type + read (ForwardWritableRange & range); + ///< Read data into range + /**< \see + read(ForwardWritableRange const &) \n + read() */ + template + void read (Sequence & container, unsigned limit); + ///< Read data into container + /**< The data read is written into the given container. Old + data in the container will be removed. For this to + work, the container must be a model of 'Sequence' as + defined in the STL documentation + \param[out] container Container to write data to + \param[in] limit Maximum number of characters to read + \see \ref read() */ + char * read (char * start, char * end); ///< Read data into memory area - /**< This variant will read data into the memory area at \c - buffer of size \c size. This is the most performant - version of read(). - \param[in] buffer address of buffer to store data at - \param[in] size size of memory buffer - \returns Number of bytes read - \see \ref read() */ + /**< This variant will read data into the memory area from + \a start to before \a end. This is guaranteed to be the + most efficient version of read(). + \param[in] start address of buffer to store data at + \param[in] end address one past the end of the buffer + \returns pointer past the end of the data read + \see \ref read() */ /** \brief Read data from unconnected socket returning address - This member behaves like read() but should only be available, if the sockets \c - CommunicationPolicy is \c UnconnectedCommunicationPolicy and the \c AddressingPolicy is - not \c NoAddressingPolicy. The readfrom() family will in addition to the data return the - address of the sender. + The readfrom() group of member behaves like \ref read() but should only be available, if + the sockets \c CommunicationPolicy is \c UnconnectedCommunicationPolicy and the \c + AddressingPolicy is not \c NoAddressingPolicy. readfrom() will in addition to the data + return the address of the sender. \throws senf::SystemException + This variant will return the data read and the address as a std::pair. \returns \c std::pair of data read (a string) and the peers address - \fixme Add \c limit argument - \implementation The readfrom() family of members will use \c recvfrom from the BSD socket API. */ std::pair - readfrom (); - void readfrom (std::string & buffer, Address & from); - ///< Read data into string buffer - /**< This variant will return the result in the locations - passed in - \param[out] buffer data read - \param[out] from peer address - \see \ref readfrom() */ - unsigned readfrom (char * buffer, unsigned size, Address & from); + readfrom (unsigned limit=0); + template + typename boost::range_iterator::type + readfrom (ForwardWritableRange const & range, Address & from); + ///< Read data into range + /**< Read data into the given range. At most + boost::size(range) characters are read. The + data read will start at the beginning of the + range. read returns a past-the-end iterator after the + last character read. This iterator will point to + somewhere within the input range. + \param[in/out] range Range to store data in + \param[out] from peers address from which the data was + received + \returns past-the-end iterator pointer to after the + last read character + \see \ref readfrom() */ + template + typename boost::range_iterator::type + readfrom (ForwardWritableRange & range, Address & from); + ///< Read data into range + /**< \see + readfrom(ForwardWritableRange const&,Address&) \n + readfrom() */ + template + void readfrom (Sequence & container, Address & from, unsigned limit); + ///< Read data into container + /**< The data read is written into the given container. Old + data in the container will be removed. For this to + work, the container must be a model of 'Sequence' as + defined in the STL documentation + \param[out] container Container to write data to + \param[in] limit Maximum number of characters to read + \param[out] from peers address from which the data was + received + \see \ref readfrom() */ + char * readfrom (char * start, char * end, Address & from); ///< Read data into memory buffer /**< This variant will read data into the memory area at \c buffer of size \c size. This is the most performant diff --git a/Socket/ClientSocketHandle.ih b/Socket/ClientSocketHandle.ih new file mode 100644 index 0000000..f3a9c4b --- /dev/null +++ b/Socket/ClientSocketHandle.ih @@ -0,0 +1,67 @@ +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Stefan Bund +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ClientSocketHandle internal header */ + +#ifndef IH_ClientSocketHandle_ +#define IH_ClientSocketHandle_ 1 + +// Custom includes +#include "Utils/IteratorTraits.hh" + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { +namespace detail { + + template + struct ReadRange + { + static typename boost::range_iterator::type + read(Handle & handle, ForwardWritableRange & range); + + static typename boost::range_iterator::type + readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr); + }; + + template + struct ReadRange + { + static typename boost::range_iterator::type + read(Handle & handle, ForwardWritableRange & range); + + static typename boost::range_iterator::type + readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr); + }; + +}} + +///////////////////////////////ih.e//////////////////////////////////////// +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// End: diff --git a/Socket/ClientSocketHandle.test.cc b/Socket/ClientSocketHandle.test.cc index 816573b..b303951 100644 --- a/Socket/ClientSocketHandle.test.cc +++ b/Socket/ClientSocketHandle.test.cc @@ -87,13 +87,13 @@ BOOST_AUTO_UNIT_TEST(clientSocketHandle) BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.read(), "TEST-READ" ) ); { std::string buf("FOO-BAR"); - BOOST_CHECK_NO_THROW( myh.read(buf) ); + BOOST_CHECK_NO_THROW( myh.read(buf,0) ); BOOST_CHECK_EQUAL( buf, "TEST-READ" ); } { char buf[11]; ::strcpy(buf,"0123456789"); - BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.read(buf,10), 9u ) ); + BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.read(buf,buf+10), buf+9u ) ); BOOST_CHECK_EQUAL( buf, "TEST-READ9" ); } @@ -101,14 +101,14 @@ BOOST_AUTO_UNIT_TEST(clientSocketHandle) { std::string buf("FOO-BAR"); unsigned addr; - BOOST_CHECK_NO_THROW( myh.readfrom(buf,addr) ); + BOOST_CHECK_NO_THROW( myh.readfrom(buf,addr,0) ); BOOST_CHECK_EQUAL( buf, "TEST-READ" ); } { char buf[11]; unsigned addr; ::strcpy(buf,"0123456789"); - BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.readfrom(buf,10,addr), 9u ) ); + BOOST_CHECK_NO_THROW( BOOST_CHECK_EQUAL( myh.readfrom(buf,buf+10,addr), buf+9u ) ); BOOST_CHECK_EQUAL( buf, "TEST-READ9" ); }