menu: added new Keywords tag to .desktop files
[barry.git] / src / router.h
blob3c8f6b46e583c06cf42f6a7be3ff0209642795b0
1 ///
2 /// \file router.h
3 /// Support classes for the pluggable socket routing system.
4 ///
6 /*
7 Copyright (C) 2005-2013, 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 // When registering interest in socket packets
45 // this type is used to indicate what type of
46 // packets are desired.
47 enum InterestType
49 DataPackets = 0x1,
50 SequencePackets = 0x2,
51 SequenceAndDataPackets = DataPackets | SequencePackets
54 // Interface class for socket data callbacks
55 // See RegisterInterest() for more information.
56 class BXEXPORT SocketDataHandler
58 public:
59 // Called when data is received on the socket
60 // for which interest has been registered.
62 // The lifetime of the data parameter is only valid
63 // for the duration of this method call.
64 virtual void DataReceived(Data& data) = 0;
66 // Called when an error has occured on the socket
67 // for which interest has been registered.
69 // The lifetime of the error parameter is only valid
70 // for the lifetime of this method call.
71 virtual void Error(Barry::Error &error);
73 virtual ~SocketDataHandler();
76 typedef std::tr1::shared_ptr<SocketDataHandler> SocketDataHandlerPtr;
78 // Simple wrapper template class for SocketDataHandler which provides a basic data recieved callback
79 template<typename T> class SimpleSocketDataHandler : public SocketDataHandler
81 void (*m_callback)(T&, Data*);
82 T& m_context;
83 public:
84 SimpleSocketDataHandler<T>(T& context, void (*callback)(T& context, Data* data))
85 : m_callback(callback)
86 , m_context(context)
88 virtual void DataReceived(Data& data)
90 m_callback(m_context, &data);
94 struct QueueEntry
96 SocketDataHandlerPtr m_handler;
97 DataQueue m_queue;
98 InterestType m_type;
100 QueueEntry(SocketDataHandlerPtr h, InterestType t)
101 : m_handler(h)
102 , m_type(t)
105 typedef std::tr1::shared_ptr<QueueEntry> QueueEntryPtr;
106 typedef uint16_t SocketId;
107 typedef std::map<SocketId, QueueEntryPtr> SocketQueueMap;
109 private:
110 Usb::Device * volatile m_dev;
111 volatile int m_writeEp, m_readEp;
113 volatile bool m_interest; // true if at least one socket has an interest.
114 // used to optimize the reading
116 mutable pthread_mutex_t m_mutex;// controls access to local data, but not
117 // DataQueues, as they have their own
118 // locking per queue
120 pthread_mutex_t m_readwaitMutex;
121 pthread_cond_t m_readwaitCond;
122 bool m_seen_usb_error;
123 SocketDataHandlerPtr m_usb_error_dev_callback;
125 DataQueue m_free;
126 DataQueue m_default;
127 SocketQueueMap m_socketQueues;
129 int m_timeout;
131 // thread state
132 pthread_t m_usb_read_thread;
133 volatile bool m_continue_reading;// set to true when the thread is created,
134 // then set to false in the destructor
135 // to signal the end of the thread
136 // and handle the join
138 protected:
139 // Provides a method of returning a buffer to the free queue
140 // after processing. The DataHandle class calls this automatically
141 // from its destructor.
142 void ReturnBuffer(Data *buf);
144 // Helper function to add a buffer to a socket queue
145 // Returns false if no queue is available for that socket
146 // Also empties the DataHandle on success.
147 bool QueuePacket(SocketId socket, DataHandle &buf);
148 bool QueuePacket(DataQueue &queue, DataHandle &buf);
149 bool RouteOrQueuePacket(SocketId socket, DataHandle &buf);
151 // Thread function for the simple read behaviour... thread is
152 // created in the SpinoffSimpleReadThread() member below.
153 static void *SimpleReadThread(void *userptr);
155 void DumpSocketQueue(SocketId socket, const DataQueue &dq);
157 public:
158 SocketRoutingQueue(int prealloc_buffer_count = 4,
159 int default_read_timeout = USBWRAP_DEFAULT_TIMEOUT);
160 ~SocketRoutingQueue();
163 // data access
165 int GetWriteEp() const { return m_writeEp; }
166 int GetReadEp() const { return m_readEp; }
169 // These functions connect the router to an external Usb::Device
170 // object. Normally this is handled automatically by the
171 // Controller class, but are public here in case they are needed.
173 // If DoRead encounters an error, it sets a flag and stops
174 // reading. To recover, you should handle the Error() call in
175 // the callback, fix the USB device, and then call
176 // ClearUsbError() to clear the flag.
178 void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp,
179 SocketDataHandlerPtr callback = SocketDataHandlerPtr());
180 void ClearUsbDevice();
181 bool UsbDeviceReady();
182 Usb::Device* GetUsbDevice() { return m_dev; }
183 void ClearUsbError();
186 // This class starts out with no buffers, and will grow one buffer
187 // at a time if needed. Call this to allocate count buffers
188 // all at once and place them on the free queue.
189 void AllocateBuffers(int count);
191 // Returns the data for the next unregistered socket.
192 // Blocks until timeout or data is available.
193 // Returns false (or null pointer) on timeout and no data.
194 // With the return version of the function, there is no
195 // copying performed.
197 // Timeout is in milliseconds. Default timeout set by constructor
198 // is used if set to -1.
199 bool DefaultRead(Data &receive, int timeout = -1);
200 DataHandle DefaultRead(int timeout = -1);
202 // Internal registration of interest in data from a certain socket,
203 // filtered by a type. NOTE: most code should not use this function,
204 // but use RegisterInterest() instead, since registering with the
205 // wrong type could cause Socket::SyncSend() to malfunction.
206 void RegisterInterestAndType(SocketId socket,
207 SocketDataHandlerPtr handler, InterestType type);
209 // Register an interest in data from a certain socket. To read
210 // from that socket, use the SocketRead() function from then on.
211 // Any non-registered socket goes in the default queue
212 // and must be read by DefaultRead()
213 // If not null, handler is called when new data is read. It will
214 // be called in the same thread instance that DoRead() is called from.
215 // Handler is passed the DataQueue Data object, and so no
216 // copying is done. Once the handler returns, the data is
217 // considered processed and not added to the interested queue,
218 // but instead returned to m_free.
220 // This simply calls RegisterInterestAndType(socket,handler,type)
221 // with type set to SequenceAndDataPackets. Most code should use
222 // this function.
223 void RegisterInterest(SocketId socket, SocketDataHandlerPtr handler);
225 // Unregisters interest in data from the given socket, and discards
226 // any existing data in its interest queue. Any new incoming data
227 // for this socket will be placed in the default queue.
228 void UnregisterInterest(SocketId socket);
230 // Changes the type of data that a client is interested in for a
231 // certain socket.
232 // Interest in the socket must have previously been registered by a
233 // call to RegisterInterest() or RegisterInterestAndType().
234 void ChangeInterest(SocketId socket, InterestType type);
236 // Reads data from the interested socket cache. Can only read
237 // from sockets that have been previously registered.
238 // Blocks until timeout or data is available.
239 // Returns false (or null pointer) on timeout and no data.
240 // With the return version of the function, there is no
241 // copying performed.
243 // Timeout is in milliseconds. Default timeout set by constructor
244 // is used if set to -1.
245 bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
246 DataHandle SocketRead(SocketId socket, int timeout = -1);
248 // Returns true if data is available for that socket.
249 bool IsAvailable(SocketId socket) const;
251 // Called by the application's "read thread" to read the next usb
252 // packet and route it to the correct queue. Returns after every
253 // read, even if a handler is associated with a queue.
254 // Note: this function is safe to call before SetUsbDevice() is
255 // called... it just doesn't do anything if there is no usb
256 // device to work with.
258 // Timeout is in milliseconds. Default is default USB timeout.
259 void DoRead(int timeout = -1);
261 // Utility function to make it easier for the user to create the
262 // USB pure-read thread. If the user wants anything more complicated
263 // in this background thread, he can implement it himself and call
264 // the above DoRead() in a loop. If only the basics are needed,
265 // then this makes it easy.
266 // Throws Barry::ErrnoError on thread creation error.
267 void SpinoffSimpleReadThread();
272 // DataHandle
274 /// std::auto_ptr like class that handles pointers to Data, but instead of
275 /// freeing them completely, the Data objects are turned to the
276 /// SocketRoutingQueue from whence they came.
278 class BXEXPORT DataHandle
280 private:
281 SocketRoutingQueue &m_queue;
282 mutable Data *m_data;
284 protected:
285 void clear()
287 if( m_data ) {
288 m_queue.ReturnBuffer(m_data);
289 m_data = 0;
293 public:
294 DataHandle(SocketRoutingQueue &q, Data *data)
295 : m_queue(q)
296 , m_data(data)
300 DataHandle(const DataHandle &other)
301 : m_queue(other.m_queue)
302 , m_data(other.m_data)
304 // we now own the pointer
305 other.m_data = 0;
308 ~DataHandle()
310 clear();
313 Data* get()
315 return m_data;
318 Data* release() // no longer owns the pointer, and does not free it
320 Data *ret = m_data;
321 m_data = 0;
322 return ret;
325 // frees current pointer, and takes ownership of new one
326 void reset(Data *next = 0)
328 clear();
329 m_data = next;
332 Data* operator->()
334 return m_data;
337 const Data* operator->() const
339 return m_data;
342 DataHandle& operator=(const DataHandle &other)
344 if( &m_queue != &other.m_queue )
345 throw std::logic_error("Trying to copy DataHandles of different queues!");
347 // remove our current data
348 clear();
350 // accept the new
351 m_data = other.m_data;
353 // we now own it
354 other.m_data = 0;
356 return *this;
362 } // namespace Barry
364 #endif