\brief ClientSocketHandle non-inline template implementation
*/
-//#include "ClientSocketHandle.ih"
+#include "ClientSocketHandle.ih"
// Custom includes
+#include <algorithm>
+#include "Utils/Buffer.hh"
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// 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>::
+read(Handle & handle, ForwardWritableRange & range)
+{
+ typename boost::range_size<ForwardWritableRange>::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<Handle,ForwardWritableRange,IsContiguous>::readfrom
+
+template <class Handle, class ForwardWritableRange, bool IsContiguous>
+prefix_ typename boost::range_iterator<ForwardWritableRange>::type
+senf::detail::ReadRange<Handle,ForwardWritableRange,IsContiguous>::
+readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr)
+{
+ typename boost::range_size<ForwardWritableRange>::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<Policy>
+
+////////////////////////////////////////
+// reading and writing
+
+// senf::ClientSocketHandle<Policy>::read
+
template <class Policy>
prefix_ std::string senf::ClientSocketHandle<Policy>::read(unsigned limit)
{
}
template <class Policy>
-prefix_ void senf::ClientSocketHandle<Policy>::read(std::string & buffer, unsigned limit)
+template <class Sequence>
+prefix_ void senf::ClientSocketHandle<Policy>::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<char *>(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<Policy>::readfrom
+
template <class Policy>
prefix_ std::pair<std::string, typename Policy::AddressingPolicy::Address>
-senf::ClientSocketHandle<Policy>::readfrom()
+senf::ClientSocketHandle<Policy>::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 <class Policy>
-prefix_ void senf::ClientSocketHandle<Policy>::
-readfrom(std::string & buffer, typename Policy::AddressingPolicy::Address & from)
+template <class Sequence>
+prefix_ void senf::ClientSocketHandle<Policy>::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<char *>(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<Policy>::write
+
template <class Policy>
prefix_ unsigned senf::ClientSocketHandle<Policy>::write(std::string const & data)
{
return written;
}
+////////////////////////////////////////
+// private members
+
+// senf::ClientSocketHandle<Policy>::available
+
template <class Policy>
prefix_ unsigned senf::ClientSocketHandle<Policy>::available()
{
\brief ClientSocketHandle inline template implementation
*/
-//#include "ClientSocketHandle.ih"
+#include "ClientSocketHandle.ih"
// Custom includes
#include <typeinfo>
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// 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)));
+ 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)));
+ return i + (handle.readfrom( ic,
+ reinterpret_cast<char*>(storage_iterator(boost::end(range))),
+ addr )
+ - ic);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::ClientSocketHandle<Policy>
+
+////////////////////////////////////////
+// structors
+
template <class Policy>
template <class OtherPolicy>
prefix_ senf::ClientSocketHandle<Policy>::
ClientSocketHandle(ClientSocketHandle<OtherPolicy> other,
typename SocketHandle<Policy>::template IsCompatible<OtherPolicy>::type *)
- : SocketHandle<Policy>(other,true)
+ : SocketHandle<Policy>(other,true)
{}
template <class Policy>
-prefix_ senf::ClientSocketHandle<Policy>::ClientSocketHandle(FileHandle other,
- bool isChecked)
- : SocketHandle<Policy>(other, isChecked)
+prefix_ senf::ClientSocketHandle<Policy>::ClientSocketHandle(FileHandle other, bool isChecked)
+ : SocketHandle<Policy>(other, isChecked)
{}
template <class Policy>
-prefix_ senf::ClientSocketHandle<Policy>::
-ClientSocketHandle(std::auto_ptr<SocketProtocol> protocol, int fd)
- : SocketHandle<Policy>(protocol,false)
+prefix_
+senf::ClientSocketHandle<Policy>::ClientSocketHandle(std::auto_ptr<SocketProtocol> protocol,
+ int fd)
+ : SocketHandle<Policy>(protocol,false)
{
this->body().fd(fd);
}
return *this;
}
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////
// reading and writing
+// senf::ClientSocketHandle<Policy>::read
+
template <class Policy>
-prefix_ unsigned senf::ClientSocketHandle<Policy>::read(char * buffer,
- unsigned size)
+template <class ForwardWritableRange>
+prefix_ typename boost::range_iterator<ForwardWritableRange>::type
+senf::ClientSocketHandle<Policy>::read(ForwardWritableRange const & range)
{
- return Policy::ReadPolicy::read(*this, buffer, size);
+ return detail::ReadRange<
+ ClientSocketHandle<Policy>,
+ ForwardWritableRange const,
+ contiguous_storage_iterator<
+ typename boost::range_iterator<ForwardWritableRange>::type
+ >::value && sizeof(typename boost::range_value<ForwardWritableRange>::type)==sizeof(char)
+ >::read(*this, range);
}
template <class Policy>
-prefix_ unsigned senf::ClientSocketHandle<Policy>::
-readfrom(char * buffer, unsigned size, typename Policy::AddressingPolicy::Address & from)
+template <class ForwardWritableRange>
+prefix_ typename boost::range_iterator<ForwardWritableRange>::type
+senf::ClientSocketHandle<Policy>::read(ForwardWritableRange & range)
{
- return Policy::ReadPolicy::readfrom(*this, buffer, size, from);
+ return detail::ReadRange<
+ ClientSocketHandle<Policy>,
+ ForwardWritableRange,
+ contiguous_storage_iterator<
+ typename boost::range_iterator<ForwardWritableRange>::type
+ >::value && sizeof(typename boost::range_value<ForwardWritableRange>::type)==sizeof(char)
+ >::read(*this, range);
}
template <class Policy>
+prefix_ char * senf::ClientSocketHandle<Policy>::read(char * start, char * end)
+{
+ return start + Policy::ReadPolicy::read(*this, start, end-start);
+}
+
+// senf::ClientSocketHandle<Policy>::readfrom
+
+template <class Policy>
+template <class ForwardWritableRange>
+prefix_ typename boost::range_iterator<ForwardWritableRange>::type
+senf::ClientSocketHandle<Policy>::readfrom(ForwardWritableRange const & range, Address & from)
+{
+ return detail::ReadRange<
+ ClientSocketHandle<Policy>,
+ ForwardWritableRange const,
+ contiguous_storage_iterator<
+ typename boost::range_iterator<ForwardWritableRange>::type
+ >::value && sizeof(typename boost::range_value<ForwardWritableRange>::type)==sizeof(char)
+ >::readfrom(*this, range, from);
+}
+
+template <class Policy>
+template <class ForwardWritableRange>
+prefix_ typename boost::range_iterator<ForwardWritableRange>::type
+senf::ClientSocketHandle<Policy>::readfrom(ForwardWritableRange & range, Address & from)
+{
+ return detail::ReadRange<
+ ClientSocketHandle<Policy>,
+ ForwardWritableRange,
+ contiguous_storage_iterator<
+ typename boost::range_iterator<ForwardWritableRange>::type
+ >::value && sizeof(typename boost::range_value<ForwardWritableRange>::type)==sizeof(char)
+ >::readfrom(*this, range, from);
+}
+
+template <class Policy>
+prefix_ char * senf::ClientSocketHandle<Policy>::readfrom(char * start, char * end,
+ Address & from)
+{
+ return start + Policy::ReadPolicy::readfrom(*this, start, end-start, from);
+}
+
+// senf::ClientSocketHandle<Policy>::write
+
+template <class Policy>
prefix_ unsigned senf::ClientSocketHandle<Policy>::write(char const * buffer,
unsigned size)
{
return Policy::WritePolicy::write(*this, buffer, size);
}
+// senf::ClientSocketHandle<Policy>::writeto
+
template <class Policy>
prefix_ unsigned senf::ClientSocketHandle<Policy>::
writeto(typename boost::call_traits<typename Policy::AddressingPolicy::Address>::param_type addr,
return Policy::WritePolicy::writeto(*this, addr, buffer, size);
}
-///////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////
// addressing
+// senf::ClientSocketHandle<Policy>::peer
+
template <class Policy>
prefix_ typename Policy::AddressingPolicy::Address
senf::ClientSocketHandle<Policy>::peer()
Policy::AddressingPolicy::peer(*this,addr);
}
+// senf::ClientSocketHandle<Policy>::local
+
template <class Policy>
prefix_ typename Policy::AddressingPolicy::Address
senf::ClientSocketHandle<Policy>::local()
Policy::AddressingPolicy::local(*this,addr);
}
+// senf::ClientSocketHandle<Policy>::connect
+
template <class Policy>
prefix_ void senf::ClientSocketHandle<Policy>::connect(AddressParam addr)
{
Policy::AddressingPolicy::connect(*this,addr);
}
+// senf::ClientSocketHandle<Policy>::bind
+
template <class Policy>
prefix_ void senf::ClientSocketHandle<Policy>::
bind(typename boost::call_traits<typename Policy::AddressingPolicy::Address>::param_type addr)
Policy::AddressingPolicy::bind(*this,addr);
}
-///////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////
// Buffering
+// senf::ClientSocketHandle<Policy>::rcvbuf
+
template <class Policy>
prefix_ unsigned senf::ClientSocketHandle<Policy>::rcvbuf()
{
Policy::BufferingPolicy::rcvbuf(*this,size);
}
+// senf::ClientSocketHandle<Policy>::sndbuf
+
template <class Policy>
prefix_ unsigned senf::ClientSocketHandle<Policy>::sndbuf()
{
Policy::BufferingPolicy::sndbuf(*this,size);
}
-///////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////
+// Casting
template <class Policy>
prefix_ senf::ClientSocketHandle<Policy>
return cast_static(handle);
}
+////////////////////////////////////////
+// State information
+
template <class Policy>
prefix_ void senf::ClientSocketHandle<Policy>::state(SocketStateMap & map, unsigned lod)
{
// Custom includes
#include <boost/call_traits.hpp>
+#include <boost/range.hpp>
#include "SocketHandle.hh"
//#include "ClientSocketHandle.mpp"
/** \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
\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 <class ForwardWritableRange>
+ typename boost::range_iterator<ForwardWritableRange>::type
+ read (ForwardWritableRange const & range);
+ ///< Read data into range
+ /**< Read data into the given range. At most
+ <tt>boost::size(range)</tt> 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 <class ForwardWritableRange>
+ typename boost::range_iterator<ForwardWritableRange>::type
+ read (ForwardWritableRange & range);
+ ///< Read data into range
+ /**< \see
+ read(ForwardWritableRange const &) \n
+ read() */
+ template <class Sequence>
+ 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<std::string, Address>
- 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 <class ForwardWritableRange>
+ typename boost::range_iterator<ForwardWritableRange>::type
+ readfrom (ForwardWritableRange const & range, Address & from);
+ ///< Read data into range
+ /**< Read data into the given range. At most
+ <tt>boost::size(range)</tt> 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 <class ForwardWritableRange>
+ typename boost::range_iterator<ForwardWritableRange>::type
+ readfrom (ForwardWritableRange & range, Address & from);
+ ///< Read data into range
+ /**< \see
+ readfrom(ForwardWritableRange const&,Address&) \n
+ readfrom() */
+ template <class Sequence>
+ 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
--- /dev/null
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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 <class Handle, class ForwardWritableRange, bool IsContiguous>
+ struct ReadRange
+ {
+ static typename boost::range_iterator<ForwardWritableRange>::type
+ read(Handle & handle, ForwardWritableRange & range);
+
+ static typename boost::range_iterator<ForwardWritableRange>::type
+ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr);
+ };
+
+ template <class Handle, class ForwardWritableRange>
+ struct ReadRange<Handle,ForwardWritableRange,true>
+ {
+ static typename boost::range_iterator<ForwardWritableRange>::type
+ read(Handle & handle, ForwardWritableRange & range);
+
+ static typename boost::range_iterator<ForwardWritableRange>::type
+ readfrom(Handle & handle, ForwardWritableRange & range, typename Handle::Address & addr);
+ };
+
+}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// End:
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" );
}
{
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" );
}