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-2012, 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         // Helper function to add a buffer to a socket queue
00133         // Returns false if no queue is available for that socket
00134         // Also empties the DataHandle on success.
00135         bool QueuePacket(SocketId socket, DataHandle &buf);
00136         bool QueuePacket(DataQueue &queue, DataHandle &buf);
00137         bool RouteOrQueuePacket(SocketId socket, DataHandle &buf);
00138 
00139         // Thread function for the simple read behaviour... thread is
00140         // created in the SpinoffSimpleReadThread() member below.
00141         static void *SimpleReadThread(void *userptr);
00142 
00143         void DumpSocketQueue(SocketId socket, const DataQueue &dq);
00144 
00145 public:
00146         SocketRoutingQueue(int prealloc_buffer_count = 4,
00147                 int default_read_timeout = USBWRAP_DEFAULT_TIMEOUT);
00148         ~SocketRoutingQueue();
00149 
00150         //
00151         // data access
00152         //
00153         int GetWriteEp() const { return m_writeEp; }
00154         int GetReadEp() const { return m_readEp; }
00155 
00156 
00157         // These functions connect the router to an external Usb::Device
00158         // object.  Normally this is handled automatically by the
00159         // Controller class, but are public here in case they are needed.
00160         //
00161         // If DoRead encounters an error, it sets a flag and stops
00162         // reading.  To recover, you should handle the Error() call in
00163         // the callback, fix the USB device, and then call
00164         // ClearUsbError() to clear the flag.
00165         //
00166         void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp,
00167                 SocketDataHandlerPtr callback = SocketDataHandlerPtr());
00168         void ClearUsbDevice();
00169         bool UsbDeviceReady();
00170         Usb::Device* GetUsbDevice() { return m_dev; }
00171         void ClearUsbError();
00172 
00173 
00174         // This class starts out with no buffers, and will grow one buffer
00175         // at a time if needed.  Call this to allocate count buffers
00176         // all at once and place them on the free queue.
00177         void AllocateBuffers(int count);
00178 
00179         // Returns the data for the next unregistered socket.
00180         // Blocks until timeout or data is available.
00181         // Returns false (or null pointer) on timeout and no data.
00182         // With the return version of the function, there is no
00183         // copying performed.
00184         //
00185         // Timeout is in milliseconds.  Default timeout set by constructor
00186         // is used if set to -1.
00187         bool DefaultRead(Data &receive, int timeout = -1);
00188         DataHandle DefaultRead(int timeout = -1);
00189 
00190         // Register an interest in data from a certain socket.  To read
00191         // from that socket, use the SocketRead() function from then on.
00192         // Any non-registered socket goes in the default queue
00193         // and must be read by DefaultRead()
00194         // If not null, handler is called when new data is read.  It will
00195         // be called in the same thread instance that DoRead() is called from.
00196         // Handler is passed the DataQueue Data object, and so no
00197         // copying is done.  Once the handler returns, the data is
00198         // considered processed and not added to the interested queue,
00199         // but instead returned to m_free.
00200         void RegisterInterest(SocketId socket, SocketDataHandlerPtr handler);
00201 
00202         // Unregisters interest in data from the given socket, and discards
00203         // any existing data in its interest queue.  Any new incoming data
00204         // for this socket will be placed in the default queue.
00205         void UnregisterInterest(SocketId socket);
00206 
00207         // Reads data from the interested socket cache.  Can only read
00208         // from sockets that have been previously registered.
00209         // Blocks until timeout or data is available.
00210         // Returns false (or null pointer) on timeout and no data.
00211         // With the return version of the function, there is no
00212         // copying performed.
00213         //
00214         // Timeout is in milliseconds.  Default timeout set by constructor
00215         // is used if set to -1.
00216         bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
00217         DataHandle SocketRead(SocketId socket, int timeout = -1);
00218 
00219         // Returns true if data is available for that socket.
00220         bool IsAvailable(SocketId socket) const;
00221 
00222         // Called by the application's "read thread" to read the next usb
00223         // packet and route it to the correct queue.  Returns after every
00224         // read, even if a handler is associated with a queue.
00225         // Note: this function is safe to call before SetUsbDevice() is
00226         // called... it just doesn't do anything if there is no usb
00227         // device to work with.
00228         //
00229         // Timeout is in milliseconds.  Default is default USB timeout.
00230         void DoRead(int timeout = -1);
00231 
00232         // Utility function to make it easier for the user to create the
00233         // USB pure-read thread.  If the user wants anything more complicated
00234         // in this background thread, he can implement it himself and call
00235         // the above DoRead() in a loop.  If only the basics are needed,
00236         // then this makes it easy.
00237         // Throws Barry::ErrnoError on thread creation error.
00238         void SpinoffSimpleReadThread();
00239 };
00240 
00241 
00242 //
00243 // DataHandle
00244 //
00245 /// std::auto_ptr like class that handles pointers to Data, but instead of
00246 /// freeing them completely, the Data objects are turned to the
00247 /// SocketRoutingQueue from whence they came.
00248 ///
00249 class BXEXPORT DataHandle
00250 {
00251 private:
00252         SocketRoutingQueue &m_queue;
00253         mutable Data *m_data;
00254 
00255 protected:
00256         void clear()
00257         {
00258                 if( m_data ) {
00259                         m_queue.ReturnBuffer(m_data);
00260                         m_data = 0;
00261                 }
00262         }
00263 
00264 public:
00265         DataHandle(SocketRoutingQueue &q, Data *data)
00266                 : m_queue(q)
00267                 , m_data(data)
00268         {
00269         }
00270 
00271         DataHandle(const DataHandle &other)
00272                 : m_queue(other.m_queue)
00273                 , m_data(other.m_data)
00274         {
00275                 // we now own the pointer
00276                 other.m_data = 0;
00277         }
00278 
00279         ~DataHandle()
00280         {
00281                 clear();
00282         }
00283 
00284         Data* get()
00285         {
00286                 return m_data;
00287         }
00288 
00289         Data* release() // no longer owns the pointer, and does not free it
00290         {
00291                 Data *ret = m_data;
00292                 m_data = 0;
00293                 return ret;
00294         }
00295 
00296         // frees current pointer, and takes ownership of new one
00297         void reset(Data *next = 0)
00298         {
00299                 clear();
00300                 m_data = next;
00301         }
00302 
00303         Data* operator->()
00304         {
00305                 return m_data;
00306         }
00307 
00308         const Data* operator->() const
00309         {
00310                 return m_data;
00311         }
00312 
00313         DataHandle& operator=(const DataHandle &other)
00314         {
00315                 if( &m_queue != &other.m_queue )
00316                         throw std::logic_error("Trying to copy DataHandles of different queues!");
00317 
00318                 // remove our current data
00319                 clear();
00320 
00321                 // accept the new
00322                 m_data = other.m_data;
00323 
00324                 // we now own it
00325                 other.m_data = 0;
00326 
00327                 return *this;
00328         }
00329 
00330 };
00331 
00332 
00333 } // namespace Barry
00334 
00335 #endif
00336