ssocket.h

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /**
00020  * \file ssocket.h Interface for SSocket class
00021  */
00022 
00023 #ifndef __SSOCKET_H__
00024 #define __SSOCKET_H__
00025 
00026 #include <hn/scheduler.h>          // the scheduler itself
00027 #include <boost/bind.hpp>          // function object binding
00028 
00029 //! Socket types and protocols for easier SSocket class usage
00030 namespace Socket {
00031         class TCP;        //!< Protocol:  TCP
00032         class UDP;        //!< Protocol:  UDP
00033         class Client;     //!< Semantics: Client
00034         class Server;     //!< Semantics: Server
00035 }
00036 
00037 /**
00038  * Traits class for choosing the underlying implementation based on socket type
00039  * and protocol. The primary template of this class is not implemented. Instead,
00040  * one of the specializations are expected to be chosen, which define the actual
00041  * underlying implementation type. If no possible specialization could be found,
00042  * an undefined reference is generated during application linking.
00043  */
00044 template<typename Type, typename Proto>
00045 struct Implement;
00046 template<>
00047 struct Implement<Socket::Client, Socket::TCP> {
00048         typedef SocketClient Impl;
00049 };
00050 template<>
00051 struct Implement<Socket::Server, Socket::UDP> {
00052         typedef UDPSocket Impl;
00053 };
00054 template<>
00055 struct Implement<Socket::Server, Socket::TCP> {
00056         typedef SocketServer Impl;
00057 };
00058 
00059 /**
00060  * SSocket template represents a socket that can be serve as communication
00061  * medium between two remote parties. The exact implementation is chosen
00062  * based on the template parameters.
00063  *
00064  * @param Module        Required, the module governing this socket.
00065  * @param Type          Type of the socket. Can be either Client or Server
00066  * @param Protocol      Protocol to be used in the socket, e.g. TCP or UDP
00067  *
00068  * \note This class acts as a Facade for the Scheduler engine. All public
00069  *        member function calls of this class are forwarded to the respective
00070  *        underlying scheduler classes.
00071  */
00072 template<typename Module, typename Type, typename Protocol = Socket::TCP>
00073 class SSocket {
00074 public:
00075         typedef typename Implement<Type, Protocol>::Impl Impl;
00076         typedef typename Impl::PriorityType PriorityType;
00077         typedef typename Impl::EventType EventType;
00078         typedef Impl* ImplPtr;
00079         typedef boost::function<void (SSocket*, EventType)> HandlerFunc;
00080         typedef Scheduler<Impl> _Scheduler;
00081 
00082         /**
00083          * Construct and initialize, optionally setting event handler
00084          *
00085          * @param h      Optional event handler
00086          */
00087         SSocket(HandlerFunc h = 0) : m_impl(new Impl), m_handler(h) {
00088                 _Scheduler::template addSocket<Module>(
00089                         m_impl, boost::bind(&SSocket::onEvent, this, _1, _2)
00090                 );
00091         }
00092 
00093         /**
00094          * Convenience constructor - performs event handler functor binding
00095          * internally.
00096          *
00097          * @param obj      Object to receive event notifications
00098          * @param func     Function to receive event notifications
00099          */
00100         template<typename T>
00101         SSocket(T *obj, void (T::*func)(SSocket*, EventType))
00102         : m_impl(new Impl), m_handler(boost::bind(func, obj, _1, _2)) {
00103                 _Scheduler::template addSocket<Module>(
00104                         m_impl, boost::bind(&SSocket::onEvent, this, _1, _2)
00105                 );
00106         }
00107 
00108         /**
00109          * Constructer used only internally during incoming connections
00110          * accepting.
00111          *
00112          * @param s        New socket
00113          */
00114         SSocket(typename Impl::AcceptType *s) : m_impl(s) {
00115                 _Scheduler::template addSocket<Module>(
00116                         s, boost::bind(&SSocket::onEvent, this, _1, _2)
00117                 );
00118         }
00119 
00120         //! Destructor
00121         ~SSocket() {
00122                 _Scheduler::delSocket(m_impl);
00123                 m_impl->destroy();
00124         }
00125 
00126         /**
00127          * @name Input/Output
00128          */
00129         //@{
00130 
00131         /**
00132          * Write data into socket
00133          *
00134          * @param buf   Data to be written
00135          */
00136         void write(const std::string &buf) {
00137                 _Scheduler::template write<Module>(m_impl, buf);
00138         }
00139 
00140         /**
00141          * Read data from socket
00142          *
00143          * @param buf   Buffer to read data into. The data is appended to the
00144          *              specified string.
00145          */
00146         void read(std::string *buf) {
00147                 _Scheduler::template read<Module>(m_impl, buf);
00148         }
00149 
00150         /**
00151          * A more optimized version of read() method, this returns the incoming
00152          * data buffer directly. The different between getData() and read()
00153          * methods is that in case of read(), the data is appended to the
00154          * buffer, which means memcpy operation, however, with this method, only
00155          * std::string copy-constructor is called, and majority of
00156          * implementations have that optimized to avoid data copying. So this
00157          * method should be prefered over read() method.
00158          *
00159          * @return     All data that has been received thus far.
00160          *
00161          * \note If you ignore the return value, the data is effectivly lost,
00162          *       since scheduler removes the data from it's internal buffer.
00163          */
00164         std::string getData() {
00165                 return _Scheduler::template getData<Module>(m_impl);
00166         }
00167 
00168         /**
00169          * Perform an outgoing connection
00170          *
00171          * @param addr      Address to connect to
00172          * @param timeout   Optional timeout for connection attempt. Defaults
00173          *                  to 5 seconds.
00174          */
00175         void connect(IPV4Address addr, uint32_t timeout = 5000) {
00176                 _Scheduler::template connect<Module>(m_impl, addr, timeout);
00177         }
00178 
00179         /**
00180          * Disconnect a connected socket. If the socket is not connected, this
00181          * function does nothing. Note that sockets are automatically
00182          * disconnected when they are destroyed.
00183          *
00184          * @param lazy     If true, the actual disconnection is delayed until
00185          *                 pending data has been sent out.
00186          */
00187         void disconnect(bool lazy = true) {
00188                 _Scheduler::template disconnect<Module>(m_impl, lazy);
00189         }
00190 
00191         /**
00192          * Start a listener, waiting for incoming connections
00193          *
00194          * @param addr     Local address to listen on. If addr.ip is set to
00195          *                 0, connections are accepted from all networks,
00196          *                 otherwise connections are only accepted from the
00197          *                 designated net. For example, if ip is 127.0.0.1,
00198          *                 only loopback connections are accepted.
00199          */
00200         void listen(IPV4Address addr) {
00201                 m_impl->listen(addr);
00202         }
00203 
00204         /**
00205          * Convenience method - construct IPV4Address internally
00206          *
00207          * @param ip       Ip to listen on
00208          * @param port     Port to listen on
00209          */
00210         void listen(uint32_t ip, uint16_t port) {
00211                 listen(IPV4Address(ip, port));
00212         }
00213 
00214         /**
00215          * Accept an incoming connection.
00216          *
00217          * @return         New socket, which is in connected state, ready to
00218          *                 receive and transmit data. The return type depends
00219          *                 on the underlying implementation. The returned socket
00220          *                 is created in same module as the listening socket.
00221          *
00222          * \throws if there was no incoming connection pending at this moment.
00223          */
00224         SSocket<Module, Socket::Client, Protocol>* accept() {
00225                 return new SSocket<Module, Socket::Client, Protocol>(
00226                         _Scheduler::template accept<Module>(m_impl)
00227                 );
00228         }
00229 
00230         /**
00231          * Send data to specific address. This applies only to UDP sockets.
00232          *
00233          * @param to       Address to send data to
00234          * @param buf      Buffer containing the data to be sent
00235          */
00236         void send(IPV4Address to, const std::string &buf) {
00237                 _Scheduler::template send<Module>(to, buf);
00238         }
00239 
00240         /**
00241          * Receive data from designated address. This applies only to UDP type
00242          * sockets.
00243          *
00244          * @param buf       Buffer to write the retrieved data to. The data is
00245          *                  appended to the designated string.
00246          * @param from      Will receive the data source address
00247          */
00248         void recv(IPV4Address *from, std::string *buf) {
00249                 _Scheduler::template recv<Module>(from, buf);
00250         }
00251         //@}
00252 
00253         /**
00254          * Set socket timeout. If no events happen before the timeout is over,
00255          * the socket is closed and EVT_TIMEOUT posted.
00256          *
00257          * @param t   Timeout in milliseconds
00258          */
00259         void setTimeout(uint32_t t) {
00260                 m_impl->setTimeout(t);
00261         }
00262 
00263         /**
00264          * @name Event handling
00265          */
00266         //@{
00267         //! Set event handler, overwriting old handler
00268         void        setHandler(HandlerFunc handler) { m_handler = handler; }
00269         //! Set the event handler, performing functor binding internally
00270         template<typename T>
00271         void setHandler(T *obj, void (T::*func)(SSocket*, EventType)) {
00272                 m_handler = boost::bind(func, obj, _1, _2);
00273         }
00274         //! Retrieve the handler function object
00275         HandlerFunc getHandler() const              { return m_handler;    }
00276         //! Clear the existing event handler
00277         void        clearHandler()                  { m_handler.clear();   }
00278         //@}
00279 
00280         //! Set this sockets priority
00281         void setPriority(PriorityType prio) { m_impl->setPriority(prio); }
00282 
00283         /**
00284          * @name Queries
00285          */
00286         //@{
00287         bool isConnected()         const { return m_impl->isConnected();  }
00288         bool isOk()                const { return m_impl->isOk();         }
00289         bool isConnecting()        const { return m_impl->isConnecting(); }
00290         bool isWritable()          const { return m_impl->isWritable();   }
00291         bool isListening()         const { return m_impl->isListening();  }
00292         bool hasIncoming()         const { return m_impl->hasIncoming();  }
00293         IPV4Address getPeer()      const { return m_impl->getPeer();      }
00294         IPV4Address getAddr()      const { return m_impl->getAddr();      }
00295         PriorityType getPriority() const { return m_impl->getPriority();  }
00296         //@}
00297 private:
00298         SSocket(const SSocket&);             //!< Forbidden
00299         SSocket& operator=(const SSocket&);  //!< Forbidden
00300 
00301         ImplPtr     m_impl;           //!< Implementation object
00302         HandlerFunc m_handler;        //!< External event handler function
00303 
00304         /**
00305          * Internal event handler, called from scheduler. Forwards the event
00306          * to user-defined event handler (if present).
00307          *
00308          * @param ptr       Implementation pointer generating this event. Must
00309          *                  match m_impl member.
00310          * @param evt       The event itself
00311          */
00312         void onEvent(ImplPtr ptr, EventType evt) {
00313                 CHECK_THROW(ptr == m_impl);
00314                 if (m_handler) {
00315                         m_handler(this, evt);
00316                 }
00317         }
00318 
00319         friend SSocket& operator<<(SSocket &s, const std::string &data) {
00320                 s.write(data);
00321                 return s;
00322         }
00323         friend SSocket& operator>>(SSocket &s, std::string &data) {
00324                 s.read(&data);
00325                 return s;
00326         }
00327 };
00328 
00329 #endif // !__SSOCKET_H__