lib: changed Usb::Error exception to deal in libusb_errcode instead of system
[barry/progweb.git] / src / router.h
blobd4eecad686d0fe6cbd262854dead9af9b22cf085
1 ///
2 /// \file router.h
3 /// Support classes for the pluggable socket routing system.
4 ///
6 /*
7 Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRY_ROUTER_H__
23 #define __BARRY_ROUTER_H__
25 #include "dll.h"
26 #include <stdint.h>
27 #include <map>
28 #include <tr1/memory>
29 #include <stdexcept>
30 #include <pthread.h>
31 #include "dataqueue.h"
32 #include "error.h"
33 #include "usbwrap.h"
35 namespace Barry {
37 class DataHandle;
39 class BXEXPORT SocketRoutingQueue
41 friend class DataHandle;
43 public:
44 // Interface class for socket data callbacks
45 // See RegisterInterest() for more information.
46 class BXEXPORT SocketDataHandler
48 public:
49 // Called when data is received on the socket
50 // for which interest has been registered.
52 // The lifetime of the data parameter is only valid
53 // for the duration of this method call.
54 virtual void DataReceived(Data& data) = 0;
56 // Called when an error has occured on the socket
57 // for which interest has been registered.
59 // The lifetime of the error parameter is only valid
60 // for the lifetime of this method call.
61 virtual void Error(Barry::Error &error);
63 virtual ~SocketDataHandler();
66 typedef std::tr1::shared_ptr<SocketDataHandler> SocketDataHandlerPtr;
68 // Simple wrapper template class for SocketDataHandler which provides a basic data recieved callback
69 template<typename T> class SimpleSocketDataHandler : public SocketDataHandler
71 void (*m_callback)(T&, Data*);
72 T& m_context;
73 public:
74 SimpleSocketDataHandler<T>(T& context, void (*callback)(T& context, Data* data))
75 : m_callback(callback)
76 , m_context(context)
78 virtual void DataReceived(Data& data)
80 m_callback(m_context, &data);
84 struct QueueEntry
86 SocketDataHandlerPtr m_handler;
87 DataQueue m_queue;
89 QueueEntry(SocketDataHandlerPtr h)
90 : m_handler(h)
93 typedef std::tr1::shared_ptr<QueueEntry> QueueEntryPtr;
94 typedef uint16_t SocketId;
95 typedef std::map<SocketId, QueueEntryPtr> SocketQueueMap;
97 private:
98 Usb::Device * volatile m_dev;
99 volatile int m_writeEp, m_readEp;
101 volatile bool m_interest; // true if at least one socket has an interest.
102 // used to optimize the reading
104 mutable pthread_mutex_t m_mutex;// controls access to local data, but not
105 // DataQueues, as they have their own
106 // locking per queue
108 pthread_mutex_t m_readwaitMutex;
109 pthread_cond_t m_readwaitCond;
110 bool m_seen_usb_error;
111 SocketDataHandlerPtr m_usb_error_dev_callback;
113 DataQueue m_free;
114 DataQueue m_default;
115 SocketQueueMap m_socketQueues;
117 int m_timeout;
119 // thread state
120 pthread_t m_usb_read_thread;
121 volatile bool m_continue_reading;// set to true when the thread is created,
122 // then set to false in the destructor
123 // to signal the end of the thread
124 // and handle the join
126 protected:
127 // Provides a method of returning a buffer to the free queue
128 // after processing. The DataHandle class calls this automatically
129 // from its destructor.
130 void ReturnBuffer(Data *buf);
132 // Helper function to add a buffer to a socket queue
133 // Returns false if no queue is available for that socket
134 // Also empties the DataHandle on success.
135 bool QueuePacket(SocketId socket, DataHandle &buf);
136 bool QueuePacket(DataQueue &queue, DataHandle &buf);
137 bool RouteOrQueuePacket(SocketId socket, DataHandle &buf);
139 // Thread function for the simple read behaviour... thread is
140 // created in the SpinoffSimpleReadThread() member below.
141 static void *SimpleReadThread(void *userptr);
143 void DumpSocketQueue(SocketId socket, const DataQueue &dq);
145 public:
146 SocketRoutingQueue(int prealloc_buffer_count = 4,
147 int default_read_timeout = USBWRAP_DEFAULT_TIMEOUT);
148 ~SocketRoutingQueue();
151 // data access
153 int GetWriteEp() const { return m_writeEp; }
154 int GetReadEp() const { return m_readEp; }
157 // These functions connect the router to an external Usb::Device
158 // object. Normally this is handled automatically by the
159 // Controller class, but are public here in case they are needed.
161 // If DoRead encounters an error, it sets a flag and stops
162 // reading. To recover, you should handle the Error() call in
163 // the callback, fix the USB device, and then call
164 // ClearUsbError() to clear the flag.
166 void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp,
167 SocketDataHandlerPtr callback = SocketDataHandlerPtr());
168 void ClearUsbDevice();
169 bool UsbDeviceReady();
170 Usb::Device* GetUsbDevice() { return m_dev; }
171 void ClearUsbError();
174 // This class starts out with no buffers, and will grow one buffer
175 // at a time if needed. Call this to allocate count buffers
176 // all at once and place them on the free queue.
177 void AllocateBuffers(int count);
179 // Returns the data for the next unregistered socket.
180 // Blocks until timeout or data is available.
181 // Returns false (or null pointer) on timeout and no data.
182 // With the return version of the function, there is no
183 // copying performed.
185 // Timeout is in milliseconds. Default timeout set by constructor
186 // is used if set to -1.
187 bool DefaultRead(Data &receive, int timeout = -1);
188 DataHandle DefaultRead(int timeout = -1);
190 // Register an interest in data from a certain socket. To read
191 // from that socket, use the SocketRead() function from then on.
192 // Any non-registered socket goes in the default queue
193 // and must be read by DefaultRead()
194 // If not null, handler is called when new data is read. It will
195 // be called in the same thread instance that DoRead() is called from.
196 // Handler is passed the DataQueue Data object, and so no
197 // copying is done. Once the handler returns, the data is
198 // considered processed and not added to the interested queue,
199 // but instead returned to m_free.
200 void RegisterInterest(SocketId socket, SocketDataHandlerPtr handler);
202 // Unregisters interest in data from the given socket, and discards
203 // any existing data in its interest queue. Any new incoming data
204 // for this socket will be placed in the default queue.
205 void UnregisterInterest(SocketId socket);
207 // Reads data from the interested socket cache. Can only read
208 // from sockets that have been previously registered.
209 // Blocks until timeout or data is available.
210 // Returns false (or null pointer) on timeout and no data.
211 // With the return version of the function, there is no
212 // copying performed.
214 // Timeout is in milliseconds. Default timeout set by constructor
215 // is used if set to -1.
216 bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
217 DataHandle SocketRead(SocketId socket, int timeout = -1);
219 // Returns true if data is available for that socket.
220 bool IsAvailable(SocketId socket) const;
222 // Called by the application's "read thread" to read the next usb
223 // packet and route it to the correct queue. Returns after every
224 // read, even if a handler is associated with a queue.
225 // Note: this function is safe to call before SetUsbDevice() is
226 // called... it just doesn't do anything if there is no usb
227 // device to work with.
229 // Timeout is in milliseconds. Default is default USB timeout.
230 void DoRead(int timeout = -1);
232 // Utility function to make it easier for the user to create the
233 // USB pure-read thread. If the user wants anything more complicated
234 // in this background thread, he can implement it himself and call
235 // the above DoRead() in a loop. If only the basics are needed,
236 // then this makes it easy.
237 // Throws Barry::ErrnoError on thread creation error.
238 void SpinoffSimpleReadThread();
243 // DataHandle
245 /// std::auto_ptr like class that handles pointers to Data, but instead of
246 /// freeing them completely, the Data objects are turned to the
247 /// SocketRoutingQueue from whence they came.
249 class BXEXPORT DataHandle
251 private:
252 SocketRoutingQueue &m_queue;
253 mutable Data *m_data;
255 protected:
256 void clear()
258 if( m_data ) {
259 m_queue.ReturnBuffer(m_data);
260 m_data = 0;
264 public:
265 DataHandle(SocketRoutingQueue &q, Data *data)
266 : m_queue(q)
267 , m_data(data)
271 DataHandle(const DataHandle &other)
272 : m_queue(other.m_queue)
273 , m_data(other.m_data)
275 // we now own the pointer
276 other.m_data = 0;
279 ~DataHandle()
281 clear();
284 Data* get()
286 return m_data;
289 Data* release() // no longer owns the pointer, and does not free it
291 Data *ret = m_data;
292 m_data = 0;
293 return ret;
296 // frees current pointer, and takes ownership of new one
297 void reset(Data *next = 0)
299 clear();
300 m_data = next;
303 Data* operator->()
305 return m_data;
308 const Data* operator->() const
310 return m_data;
313 DataHandle& operator=(const DataHandle &other)
315 if( &m_queue != &other.m_queue )
316 throw std::logic_error("Trying to copy DataHandles of different queues!");
318 // remove our current data
319 clear();
321 // accept the new
322 m_data = other.m_data;
324 // we now own it
325 other.m_data = 0;
327 return *this;
333 } // namespace Barry
335 #endif