# router.h

Go to the documentation of this file.

    00001 ///
    00002 /// \file       router.h
    00003 ///             Support classes for the pluggable socket routing system.
    00004 ///
    00005
    00006 /*
    00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
    00008
    00009     This program is free software; you can redistribute it and/or modify
    00010     it under the terms of the GNU General Public License as published by
    00011     the Free Software Foundation; either version 2 of the License, or
    00012     (at your option) any later version.
    00013
    00014     This program is distributed in the hope that it will be useful,
    00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00017
    00018     See the GNU General Public License in the COPYING file at the
    00019     root directory of this project for more details.
    00020 */
    00021
    00022 #ifndef __BARRY_ROUTER_H__
    00023 #define __BARRY_ROUTER_H__
    00024
    00025 #include "dll.h"
    00026 #include <stdint.h>
    00027 #include <map>
    00028 #include <tr1/memory>
    00029 #include <stdexcept>
    00030 #include <pthread.h>
    00031 #include "dataqueue.h"
    00032 #include "error.h"
    00033 #include "usbwrap.h"
    00034
    00035 namespace Barry {
    00036
    00037 class DataHandle;
    00038
    00039 class BXEXPORT SocketRoutingQueue
    00040 {
    00041         friend class DataHandle;
    00042
    00043 public:
    00044         // Interface class for socket data callbacks
    00045         // See RegisterInterest() for more information.
    00046         class BXEXPORT SocketDataHandler
    00047         {
    00048         public:
    00049                 // Called when data is received on the socket
    00050                 // for which interest has been registered.
    00051                 //
    00052                 // The lifetime of the data parameter is only valid
    00053                 // for the duration of this method call.
    00054                 virtual void DataReceived(Data& data) = 0;
    00055
    00056                 // Called when an error has occured on the socket
    00057                 // for which interest has been registered.
    00058                 //
    00059                 // The lifetime of the error parameter is only valid
    00060                 // for the lifetime of this method call.
    00061                 virtual void Error(Barry::Error &error);
    00062
    00063                 virtual ~SocketDataHandler();
    00064         };
    00065
    00066         typedef std::tr1::shared_ptr<SocketDataHandler> SocketDataHandlerPtr;
    00067
    00068         // Simple wrapper template class for SocketDataHandler which provides a basic data recieved callback
    00069         template<typename T> class SimpleSocketDataHandler : public SocketDataHandler
    00070         {
    00071                 void (*m_callback)(T&, Data*);
    00072                 T& m_context;
    00073         public:
    00074                 SimpleSocketDataHandler<T>(T& context, void (*callback)(T& context, Data* data))
    00075                         : m_callback(callback)
    00076                         , m_context(context)
    00077                 {}
    00078                 virtual void DataReceived(Data& data)
    00079                 {
    00080                         m_callback(m_context, &data);
    00081                 }
    00082         };
    00083
    00084         struct QueueEntry
    00085         {
    00086                 SocketDataHandlerPtr m_handler;
    00087                 DataQueue m_queue;
    00088
    00089                 QueueEntry(SocketDataHandlerPtr h)
    00090                         : m_handler(h)
    00091                         {}
    00092         };
    00093         typedef std::tr1::shared_ptr<QueueEntry>        QueueEntryPtr;
    00094         typedef uint16_t                                SocketId;
    00095         typedef std::map<SocketId, QueueEntryPtr>       SocketQueueMap;
    00096
    00097 private:
    00098         Usb::Device * volatile m_dev;
    00099         volatile int m_writeEp, m_readEp;
    00100
    00101         volatile bool m_interest; // true if at least one socket has an interest.
    00102                                 // used to optimize the reading
    00103
    00104         mutable pthread_mutex_t m_mutex;// controls access to local data, but not
    00105                                 // DataQueues, as they have their own
    00106                                 // locking per queue
    00107
    00108         pthread_mutex_t m_readwaitMutex;
    00109         pthread_cond_t m_readwaitCond;
    00110         bool m_seen_usb_error;
    00111         SocketDataHandlerPtr m_usb_error_dev_callback;
    00112
    00113         DataQueue m_free;
    00114         DataQueue m_default;
    00115         SocketQueueMap m_socketQueues;
    00116
    00117         int m_timeout;
    00118
    00119         // thread state
    00120         pthread_t m_usb_read_thread;
    00121         volatile bool m_continue_reading;// set to true when the thread is created,
    00122                                 // then set to false in the destructor
    00123                                 // to signal the end of the thread
    00124                                 // and handle the join
    00125
    00126 protected:
    00127         // Provides a method of returning a buffer to the free queue
    00128         // after processing.  The DataHandle class calls this automatically
    00129         // from its destructor.
    00130         void ReturnBuffer(Data *buf);
    00131
    00132         // Thread function for the simple read behaviour... thread is
    00133         // created in the SpinoffSimpleReadThread() member below.
    00134         static void *SimpleReadThread(void *userptr);
    00135
    00136 public:
    00137         SocketRoutingQueue(int prealloc_buffer_count = 4,
    00138                 int default_read_timeout = USBWRAP_DEFAULT_TIMEOUT);
    00139         ~SocketRoutingQueue();
    00140
    00141         //
    00142         // data access
    00143         //
    00144         int GetWriteEp() const { return m_writeEp; }
    00145         int GetReadEp() const { return m_readEp; }
    00146
    00147
    00148         // These functions connect the router to an external Usb::Device
    00149         // object.  Normally this is handled automatically by the
    00150         // Controller class, but are public here in case they are needed.
    00151         //
    00152         // If DoRead encounters an error, it sets a flag and stops
    00153         // reading.  To recover, you should handle the Error() call in
    00154         // the callback, fix the USB device, and then call
    00155         // ClearUsbError() to clear the flag.
    00156         //
    00157         void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp,
    00158                 SocketDataHandlerPtr callback = SocketDataHandlerPtr());
    00159         void ClearUsbDevice();
    00160         bool UsbDeviceReady();
    00161         Usb::Device* GetUsbDevice() { return m_dev; }
    00162         void ClearUsbError();
    00163
    00164
    00165         // This class starts out with no buffers, and will grow one buffer
    00166         // at a time if needed.  Call this to allocate count buffers
    00167         // all at once and place them on the free queue.
    00168         void AllocateBuffers(int count);
    00169
    00170         // Returns the data for the next unregistered socket.
    00171         // Blocks until timeout or data is available.
    00172         // Returns false (or null pointer) on timeout and no data.
    00173         // With the return version of the function, there is no
    00174         // copying performed.
    00175         //
    00176         // Timeout is in milliseconds.  Default timeout set by constructor
    00177         // is used if set to -1.
    00178         bool DefaultRead(Data &receive, int timeout = -1);
    00179         DataHandle DefaultRead(int timeout = -1);
    00180
    00181         // Register an interest in data from a certain socket.  To read
    00182         // from that socket, use the SocketRead() function from then on.
    00183         // Any non-registered socket goes in the default queue
    00184         // and must be read by DefaultRead()
    00185         // If not null, handler is called when new data is read.  It will
    00186         // be called in the same thread instance that DoRead() is called from.
    00187         // Handler is passed the DataQueue Data object, and so no
    00188         // copying is done.  Once the handler returns, the data is
    00189         // considered processed and not added to the interested queue,
    00190         // but instead returned to m_free.
    00191         void RegisterInterest(SocketId socket, SocketDataHandlerPtr handler);
    00192
    00193         // Unregisters interest in data from the given socket, and discards
    00194         // any existing data in its interest queue.  Any new incoming data
    00195         // for this socket will be placed in the default queue.
    00196         void UnregisterInterest(SocketId socket);
    00197
    00198         // Reads data from the interested socket cache.  Can only read
    00199         // from sockets that have been previously registered.
    00200         // Blocks until timeout or data is available.
    00201         // Returns false (or null pointer) on timeout and no data.
    00202         // With the return version of the function, there is no
    00203         // copying performed.
    00204         //
    00205         // Timeout is in milliseconds.  Default timeout set by constructor
    00206         // is used if set to -1.
    00207         bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
    00208         DataHandle SocketRead(SocketId socket, int timeout = -1);
    00209
    00210         // Returns true if data is available for that socket.
    00211         bool IsAvailable(SocketId socket) const;
    00212
    00213         // Called by the application's "read thread" to read the next usb
    00214         // packet and route it to the correct queue.  Returns after every
    00215         // read, even if a handler is associated with a queue.
    00216         // Note: this function is safe to call before SetUsbDevice() is
    00217         // called... it just doesn't do anything if there is no usb
    00218         // device to work with.
    00219         //
    00220         // Timeout is in milliseconds.  Default is default USB timeout.
    00221         void DoRead(int timeout = -1);
    00222
    00223         // Utility function to make it easier for the user to create the
    00224         // USB pure-read thread.  If the user wants anything more complicated
    00225         // in this background thread, he can implement it himself and call
    00226         // the above DoRead() in a loop.  If only the basics are needed,
    00227         // then this makes it easy.
    00228         // Throws Barry::ErrnoError on thread creation error.
    00229         void SpinoffSimpleReadThread();
    00230 };
    00231
    00232
    00233 //
    00234 // DataHandle
    00235 //
    00236 /// std::auto_ptr like class that handles pointers to Data, but instead of
    00237 /// freeing them completely, the Data objects are turned to the
    00238 /// SocketRoutingQueue from whence they came.
    00239 ///
    00240 class BXEXPORT DataHandle
    00241 {
    00242 private:
    00243         SocketRoutingQueue &m_queue;
    00244         mutable Data *m_data;
    00245
    00246 protected:
    00247         void clear()
    00248         {
    00249                 if( m_data ) {
    00250                         m_queue.ReturnBuffer(m_data);
    00251                         m_data = 0;
    00252                 }
    00253         }
    00254
    00255 public:
    00256         DataHandle(SocketRoutingQueue &q, Data *data)
    00257                 : m_queue(q)
    00258                 , m_data(data)
    00259         {
    00260         }
    00261
    00262         DataHandle(const DataHandle &other)
    00263                 : m_queue(other.m_queue)
    00264                 , m_data(other.m_data)
    00265         {
    00266                 // we now own the pointer
    00267                 other.m_data = 0;
    00268         }
    00269
    00270         ~DataHandle()
    00271         {
    00272                 clear();
    00273         }
    00274
    00275         Data* get()
    00276         {
    00277                 return m_data;
    00278         }
    00279
    00280         Data* release() // no longer owns the pointer
    00281         {
    00282                 Data *ret = m_data;
    00283                 m_data = 0;
    00284                 return ret;
    00285         }
    00286
    00287         Data* operator->()
    00288         {
    00289                 return m_data;
    00290         }
    00291
    00292         const Data* operator->() const
    00293         {
    00294                 return m_data;
    00295         }
    00296
    00297         DataHandle& operator=(const DataHandle &other)
    00298         {
    00299                 if( &m_queue != &other.m_queue )
    00300                         throw std::logic_error("Trying to copy DataHandles of different queues!");
    00301
    00302                 // remove our current data
    00303                 clear();
    00304
    00305                 // accept the new
    00306                 m_data = other.m_data;
    00307
    00308                 // we now own it
    00309                 other.m_data = 0;
    00310
    00311                 return *this;
    00312         }
    00313
    00314 };
    00315
    00316
    00317 } // namespace Barry
    00318
    00319 #endif
    00320