lib: add prefixes to enums to avoid name clashes on Windows (like ERROR)
[barry.git] / src / router.h
blob04f32cf027d6b976d88fbeadb313b17aabba90e0
1 ///
2 /// \file router.h
3 /// Support classes for the pluggable socket routing system.
4 ///
6 /*
7 Copyright (C) 2005-2008, 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"
34 namespace Usb { class Device; }
36 namespace Barry {
38 class DataHandle;
40 class BXEXPORT SocketRoutingQueue
42 friend class DataHandle;
44 public:
45 // Interface class for socket data callbacks
46 // See RegisterInterest() for more information.
47 class BXEXPORT SocketDataHandler
49 public:
50 // Called when data is received on the socket
51 // for which interest has been registered.
52 //
53 // The lifetime of the data parameter is only valid
54 // for the duration of this method call.
55 virtual void DataReceived(Data& data) = 0;
57 // Called when an error has occured on the socket
58 // for which interest has been registered.
60 // The lifetime of the error parameter is only valid
61 // for the lifetime of this method call.
62 virtual void Error(Barry::Error &error);
64 virtual ~SocketDataHandler();
67 typedef std::tr1::shared_ptr<SocketDataHandler> SocketDataHandlerPtr;
69 // Simple wrapper template class for SocketDataHandler which provides a basic data recieved callback
70 template<typename T> class SimpleSocketDataHandler : public SocketDataHandler
72 void (*m_callback)(T&, Data*);
73 T& m_context;
74 public:
75 SimpleSocketDataHandler<T>(T& context, void (*callback)(T& context, Data* data))
76 : m_callback(callback)
77 , m_context(context)
79 virtual void DataReceived(Data& data)
81 m_callback(m_context, &data);
85 struct QueueEntry
87 SocketDataHandlerPtr m_handler;
88 DataQueue m_queue;
90 QueueEntry(SocketDataHandlerPtr h)
91 : m_handler(h)
94 typedef std::tr1::shared_ptr<QueueEntry> QueueEntryPtr;
95 typedef uint16_t SocketId;
96 typedef std::map<SocketId, QueueEntryPtr> SocketQueueMap;
98 private:
99 Usb::Device * volatile m_dev;
100 volatile int m_writeEp, m_readEp;
102 volatile bool m_interest; // true if at least one socket has an interest.
103 // used to optimize the reading
105 mutable pthread_mutex_t m_mutex;// controls access to local data, but not
106 // DataQueues, as they have their own
107 // locking per queue
109 pthread_mutex_t m_readwaitMutex;
110 pthread_cond_t m_readwaitCond;
111 bool m_seen_usb_error;
112 SocketDataHandlerPtr m_usb_error_dev_callback;
114 DataQueue m_free;
115 DataQueue m_default;
116 SocketQueueMap m_socketQueues;
118 // thread state
119 pthread_t m_usb_read_thread;
120 volatile bool m_continue_reading;// set to true when the thread is created,
121 // then set to false in the destructor
122 // to signal the end of the thread
123 // and handle the join
125 protected:
126 // Provides a method of returning a buffer to the free queue
127 // after processing. The DataHandle class calls this automatically
128 // from its destructor.
129 void ReturnBuffer(Data *buf);
131 // Thread function for the simple read behaviour... thread is
132 // created in the SpinoffSimpleReadThread() member below.
133 static void *SimpleReadThread(void *userptr);
135 public:
136 SocketRoutingQueue(int prealloc_buffer_count = 4);
137 ~SocketRoutingQueue();
140 // data access
142 int GetWriteEp() const { return m_writeEp; }
143 int GetReadEp() const { return m_readEp; }
146 // These functions connect the router to an external Usb::Device
147 // object. Normally this is handled automatically by the
148 // Controller class, but are public here in case they are needed.
150 // If DoRead encounters an error, it sets a flag and stops
151 // reading. To recover, you should handle the Error() call in
152 // the callback, fix the USB device, and then call
153 // ClearUsbError() to clear the flag.
155 void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp,
156 SocketDataHandlerPtr callback = SocketDataHandlerPtr());
157 void ClearUsbDevice();
158 bool UsbDeviceReady();
159 Usb::Device* GetUsbDevice() { return m_dev; }
160 void ClearUsbError();
163 // This class starts out with no buffers, and will grow one buffer
164 // at a time if needed. Call this to allocate count buffers
165 // all at once and place them on the free queue.
166 void AllocateBuffers(int count);
168 // Returns the data for the next unregistered socket.
169 // Blocks until timeout or data is available.
170 // Returns false (or null pointer) on timeout and no data.
171 // With the return version of the function, there is no
172 // copying performed.
173 bool DefaultRead(Data &receive, int timeout = -1);
174 DataHandle DefaultRead(int timeout = -1);
176 // Register an interest in data from a certain socket. To read
177 // from that socket, use the SocketRead() function from then on.
178 // Any non-registered socket goes in the default queue
179 // and must be read by DefaultRead()
180 // If not null, handler is called when new data is read. It will
181 // be called in the same thread instance that DoRead() is called from.
182 // Handler is passed the DataQueue Data object, and so no
183 // copying is done. Once the handler returns, the data is
184 // considered processed and not added to the interested queue,
185 // but instead returned to m_free.
186 void RegisterInterest(SocketId socket, SocketDataHandlerPtr handler);
188 // Unregisters interest in data from the given socket, and discards
189 // any existing data in its interest queue. Any new incoming data
190 // for this socket will be placed in the default queue.
191 void UnregisterInterest(SocketId socket);
193 // Reads data from the interested socket cache. Can only read
194 // from sockets that have been previously registered.
195 // Blocks until timeout or data is available.
196 // Returns false (or null pointer) on timeout and no data.
197 // With the return version of the function, there is no
198 // copying performed.
199 bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
200 DataHandle SocketRead(SocketId socket, int timeout = -1);
202 // Returns true if data is available for that socket.
203 bool IsAvailable(SocketId socket) const;
205 // Called by the application's "read thread" to read the next usb
206 // packet and route it to the correct queue. Returns after every
207 // read, even if a handler is associated with a queue.
208 // Note: this function is safe to call before SetUsbDevice() is
209 // called... it just doesn't do anything if there is no usb
210 // device to work with.
212 // Timeout is in milliseconds.
213 void DoRead(int timeout = -1);
215 // Utility function to make it easier for the user to create the
216 // USB pure-read thread. If the user wants anything more complicated
217 // in this background thread, he can implement it himself and call
218 // the above DoRead() in a loop. If only the basics are needed,
219 // then this makes it easy.
220 // Throws Barry::ErrnoError on thread creation error.
221 void SpinoffSimpleReadThread();
226 // DataHandle
228 /// std::auto_ptr like class that handles pointers to Data, but instead of
229 /// freeing them completely, the Data objects are turned to the
230 /// SocketRoutingQueue from whence they came.
232 class BXEXPORT DataHandle
234 private:
235 SocketRoutingQueue &m_queue;
236 mutable Data *m_data;
238 protected:
239 void clear()
241 if( m_data ) {
242 m_queue.ReturnBuffer(m_data);
243 m_data = 0;
247 public:
248 DataHandle(SocketRoutingQueue &q, Data *data)
249 : m_queue(q)
250 , m_data(data)
254 DataHandle(const DataHandle &other)
255 : m_queue(other.m_queue)
256 , m_data(other.m_data)
258 // we now own the pointer
259 other.m_data = 0;
262 ~DataHandle()
264 clear();
267 Data* get()
269 return m_data;
272 Data* release() // no longer owns the pointer
274 Data *ret = m_data;
275 m_data = 0;
276 return ret;
279 Data* operator->()
281 return m_data;
284 const Data* operator->() const
286 return m_data;
289 DataHandle& operator=(const DataHandle &other)
291 if( &m_queue != &other.m_queue )
292 throw std::logic_error("Trying to copy DataHandles of different queues!");
294 // remove our current data
295 clear();
297 // accept the new
298 m_data = other.m_data;
300 // we now own it
301 other.m_data = 0;
303 return *this;
309 } // namespace Barry
311 #endif