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