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-2007, 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 
00033 namespace Usb { class Device; }
00034 
00035 namespace Barry {
00036 
00037 class DataHandle;
00038 
00039 class BXEXPORT SocketRoutingQueue
00040 {
00041         friend class DataHandle;
00042 
00043 public:
00044         typedef void (*SocketDataHandler)(void *ctx, Data*);    //< See RegisterInterest() for information on this callback.
00045         struct QueueEntry
00046         {
00047                 SocketDataHandler m_handler;
00048                 void *m_context;
00049                 DataQueue m_queue;
00050 
00051                 QueueEntry(SocketDataHandler h, void *c)
00052                         : m_handler(h)
00053                         , m_context(c)
00054                         {}
00055         };
00056         typedef std::tr1::shared_ptr<QueueEntry>        QueueEntryPtr;
00057         typedef uint16_t                                SocketId;
00058         typedef std::map<SocketId, QueueEntryPtr>       SocketQueueMap;
00059 
00060 private:
00061         Usb::Device * volatile m_dev;
00062         volatile int m_writeEp, m_readEp;
00063 
00064         volatile bool m_interest; // true if at least one socket has an interest.
00065                                 // used to optimize the reading
00066 
00067         mutable pthread_mutex_t m_mutex;// controls access to local data, but not
00068                                 // DataQueues, as they have their own
00069                                 // locking per queue
00070 
00071         pthread_mutex_t m_readwaitMutex;
00072         pthread_cond_t m_readwaitCond;
00073 
00074         DataQueue m_free;
00075         DataQueue m_default;
00076         SocketQueueMap m_socketQueues;
00077 
00078         // thread state
00079         pthread_t m_usb_read_thread;
00080         volatile bool m_continue_reading;// set to true when the thread is created,
00081                                 // then set to false in the destructor
00082                                 // to signal the end of the thread
00083                                 // and handle the join
00084 
00085 protected:
00086         // Provides a method of returning a buffer to the free queue
00087         // after processing.  The DataHandle class calls this automatically
00088         // from its destructor.
00089         void ReturnBuffer(Data *buf);
00090 
00091         // Thread function for the simple read behaviour... thread is
00092         // created in the SpinoffSimpleReadThread() member below.
00093         static void *SimpleReadThread(void *userptr);
00094 
00095 public:
00096         SocketRoutingQueue(int prealloc_buffer_count = 4);
00097         ~SocketRoutingQueue();
00098 
00099         // These functions connect the router to an external Usb::Device
00100         // object.  Normally this is handled automatically by the
00101         // Controller class, but are public here in case they are needed.
00102         void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp);
00103         void ClearUsbDevice();
00104         bool UsbDeviceReady();
00105         Usb::Device* GetUsbDevice() { return m_dev; }
00106 
00107         // This class starts out with no buffers, and will grow one buffer
00108         // at a time if needed.  Call this to allocate count buffers
00109         // all at once and place them on the free queue.
00110         void AllocateBuffers(int count);
00111 
00112         // Returns the data for the next unregistered socket.
00113         // Blocks until timeout or data is available.
00114         // Returns false (or null pointer) on timeout and no data.
00115         // With the return version of the function, there is no
00116         // copying performed.
00117         bool DefaultRead(Data &receive, int timeout = -1);
00118         DataHandle DefaultRead(int timeout = -1);
00119 
00120         // Register an interest in data from a certain socket.  To read
00121         // from that socket, use the SocketRead() function from then on.
00122         // Any non-registered socket goes in the default queue
00123         // and must be read by DefaultRead()
00124         // If not null, handler is called when new data is read.  It will
00125         // be called in the same thread instance that DoRead() is called from.
00126         // Handler is passed the DataQueue Data pointer, and so no
00127         // copying is done.  Once the handler returns, the data is
00128         // considered processed and not added to the interested queue,
00129         // but instead returned to m_free.
00130         void RegisterInterest(SocketId socket, SocketDataHandler handler = 0, void *context = 0);
00131 
00132         // Unregisters interest in data from the given socket, and discards
00133         // any existing data in its interest queue.  Any new incoming data
00134         // for this socket will be placed in the default queue.
00135         void UnregisterInterest(SocketId socket);
00136 
00137         // Reads data from the interested socket cache.  Can only read
00138         // from sockets that have been previously registered.
00139         // Blocks until timeout or data is available.
00140         // Returns false (or null pointer) on timeout and no data.
00141         // With the return version of the function, there is no
00142         // copying performed.
00143         bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
00144         DataHandle SocketRead(SocketId socket, int timeout = -1);
00145 
00146         // Returns true if data is available for that socket.
00147         bool IsAvailable(SocketId socket) const;
00148 
00149         // Called by the application's "read thread" to read the next usb
00150         // packet and route it to the correct queue.  Returns after every
00151         // read, even if a handler is associated with a queue.
00152         // Note: this function is safe to call before SetUsbDevice() is
00153         // called... it just doesn't do anything if there is no usb
00154         // device to work with.
00155         //
00156         // Timeout is in milliseconds.
00157         //
00158         // Returns false in the case of USB errors, and puts the error
00159         // message in msg.
00160         bool DoRead(std::string &msg, int timeout = -1);
00161 
00162         // Utility function to make it easier for the user to create the
00163         // USB pure-read thread.  If the user wants anything more complicated
00164         // in this background thread, he can implement it himself and call
00165         // the above DoRead() in a loop.  If only the basics are needed,
00166         // then this makes it easy.
00167         // Throws Barry::ErrnoError on thread creation error.
00168         void SpinoffSimpleReadThread();
00169 };
00170 
00171 
00172 //
00173 // DataHandle
00174 //
00175 /// std::auto_ptr like class that handles pointers to Data, but instead of
00176 /// freeing them completely, the Data objects are turned to the
00177 /// SocketRoutingQueue from whence they came.
00178 ///
00179 class BXEXPORT DataHandle
00180 {
00181 private:
00182         SocketRoutingQueue &m_queue;
00183         mutable Data *m_data;
00184 
00185 protected:
00186         void clear()
00187         {
00188                 if( m_data ) {
00189                         m_queue.ReturnBuffer(m_data);
00190                         m_data = 0;
00191                 }
00192         }
00193 
00194 public:
00195         DataHandle(SocketRoutingQueue &q, Data *data)
00196                 : m_queue(q)
00197                 , m_data(data)
00198         {
00199         }
00200 
00201         DataHandle(const DataHandle &other)
00202                 : m_queue(other.m_queue)
00203                 , m_data(other.m_data)
00204         {
00205                 // we now own the pointer
00206                 other.m_data = 0;
00207         }
00208 
00209         ~DataHandle()
00210         {
00211                 clear();
00212         }
00213 
00214         Data* get()
00215         {
00216                 return m_data;
00217         }
00218 
00219         Data* release() // no longer owns the pointer
00220         {
00221                 Data *ret = m_data;
00222                 m_data = 0;
00223                 return ret;
00224         }
00225 
00226         Data* operator->()
00227         {
00228                 return m_data;
00229         }
00230 
00231         const Data* operator->() const
00232         {
00233                 return m_data;
00234         }
00235 
00236         DataHandle& operator=(const DataHandle &other)
00237         {
00238                 if( &m_queue != &other.m_queue )
00239                         throw std::logic_error("Trying to copy DataHandles of different queus!");
00240 
00241                 // remove our current data
00242                 clear();
00243 
00244                 // accept the new
00245                 m_data = other.m_data;
00246 
00247                 // we now own it
00248                 other.m_data = 0;
00249 
00250                 return *this;
00251         }
00252 
00253 };
00254 
00255 
00256 } // namespace Barry
00257 
00258 #endif
00259 

Generated on Wed Sep 24 21:27:32 2008 for Barry by  doxygen 1.5.1