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-2008, 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         //
00100         // data access
00101         //
00102         int GetWriteEp() const { return m_writeEp; }
00103         int GetReadEp() const { return m_readEp; }
00104 
00105 
00106         // These functions connect the router to an external Usb::Device
00107         // object.  Normally this is handled automatically by the
00108         // Controller class, but are public here in case they are needed.
00109         void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp);
00110         void ClearUsbDevice();
00111         bool UsbDeviceReady();
00112         Usb::Device* GetUsbDevice() { return m_dev; }
00113 
00114         // This class starts out with no buffers, and will grow one buffer
00115         // at a time if needed.  Call this to allocate count buffers
00116         // all at once and place them on the free queue.
00117         void AllocateBuffers(int count);
00118 
00119         // Returns the data for the next unregistered socket.
00120         // Blocks until timeout or data is available.
00121         // Returns false (or null pointer) on timeout and no data.
00122         // With the return version of the function, there is no
00123         // copying performed.
00124         bool DefaultRead(Data &receive, int timeout = -1);
00125         DataHandle DefaultRead(int timeout = -1);
00126 
00127         // Register an interest in data from a certain socket.  To read
00128         // from that socket, use the SocketRead() function from then on.
00129         // Any non-registered socket goes in the default queue
00130         // and must be read by DefaultRead()
00131         // If not null, handler is called when new data is read.  It will
00132         // be called in the same thread instance that DoRead() is called from.
00133         // Handler is passed the DataQueue Data pointer, and so no
00134         // copying is done.  Once the handler returns, the data is
00135         // considered processed and not added to the interested queue,
00136         // but instead returned to m_free.
00137         void RegisterInterest(SocketId socket, SocketDataHandler handler = 0, void *context = 0);
00138 
00139         // Unregisters interest in data from the given socket, and discards
00140         // any existing data in its interest queue.  Any new incoming data
00141         // for this socket will be placed in the default queue.
00142         void UnregisterInterest(SocketId socket);
00143 
00144         // Reads data from the interested socket cache.  Can only read
00145         // from sockets that have been previously registered.
00146         // Blocks until timeout or data is available.
00147         // Returns false (or null pointer) on timeout and no data.
00148         // With the return version of the function, there is no
00149         // copying performed.
00150         bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
00151         DataHandle SocketRead(SocketId socket, int timeout = -1);
00152 
00153         // Returns true if data is available for that socket.
00154         bool IsAvailable(SocketId socket) const;
00155 
00156         // Called by the application's "read thread" to read the next usb
00157         // packet and route it to the correct queue.  Returns after every
00158         // read, even if a handler is associated with a queue.
00159         // Note: this function is safe to call before SetUsbDevice() is
00160         // called... it just doesn't do anything if there is no usb
00161         // device to work with.
00162         //
00163         // Timeout is in milliseconds.
00164         //
00165         // Returns false in the case of USB errors, and puts the error
00166         // message in msg.
00167         bool DoRead(std::string &msg, int timeout = -1);
00168 
00169         // Utility function to make it easier for the user to create the
00170         // USB pure-read thread.  If the user wants anything more complicated
00171         // in this background thread, he can implement it himself and call
00172         // the above DoRead() in a loop.  If only the basics are needed,
00173         // then this makes it easy.
00174         // Throws Barry::ErrnoError on thread creation error.
00175         void SpinoffSimpleReadThread();
00176 };
00177 
00178 
00179 //
00180 // DataHandle
00181 //
00182 /// std::auto_ptr like class that handles pointers to Data, but instead of
00183 /// freeing them completely, the Data objects are turned to the
00184 /// SocketRoutingQueue from whence they came.
00185 ///
00186 class BXEXPORT DataHandle
00187 {
00188 private:
00189         SocketRoutingQueue &m_queue;
00190         mutable Data *m_data;
00191 
00192 protected:
00193         void clear()
00194         {
00195                 if( m_data ) {
00196                         m_queue.ReturnBuffer(m_data);
00197                         m_data = 0;
00198                 }
00199         }
00200 
00201 public:
00202         DataHandle(SocketRoutingQueue &q, Data *data)
00203                 : m_queue(q)
00204                 , m_data(data)
00205         {
00206         }
00207 
00208         DataHandle(const DataHandle &other)
00209                 : m_queue(other.m_queue)
00210                 , m_data(other.m_data)
00211         {
00212                 // we now own the pointer
00213                 other.m_data = 0;
00214         }
00215 
00216         ~DataHandle()
00217         {
00218                 clear();
00219         }
00220 
00221         Data* get()
00222         {
00223                 return m_data;
00224         }
00225 
00226         Data* release() // no longer owns the pointer
00227         {
00228                 Data *ret = m_data;
00229                 m_data = 0;
00230                 return ret;
00231         }
00232 
00233         Data* operator->()
00234         {
00235                 return m_data;
00236         }
00237 
00238         const Data* operator->() const
00239         {
00240                 return m_data;
00241         }
00242 
00243         DataHandle& operator=(const DataHandle &other)
00244         {
00245                 if( &m_queue != &other.m_queue )
00246                         throw std::logic_error("Trying to copy DataHandles of different queues!");
00247 
00248                 // remove our current data
00249                 clear();
00250 
00251                 // accept the new
00252                 m_data = other.m_data;
00253 
00254                 // we now own it
00255                 other.m_data = 0;
00256 
00257                 return *this;
00258         }
00259 
00260 };
00261 
00262 
00263 } // namespace Barry
00264 
00265 #endif
00266 
Generated by  doxygen 1.6.2-20100208