3 /// Support classes for the pluggable socket routing system.
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__
31 #include "dataqueue.h"
39 class BXEXPORT SocketRoutingQueue
41 friend class DataHandle
;
44 // Interface class for socket data callbacks
45 // See RegisterInterest() for more information.
46 class BXEXPORT SocketDataHandler
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
*);
74 SimpleSocketDataHandler
<T
>(T
& context
, void (*callback
)(T
& context
, Data
* data
))
75 : m_callback(callback
)
78 virtual void DataReceived(Data
& data
)
80 m_callback(m_context
, &data
);
86 SocketDataHandlerPtr m_handler
;
89 QueueEntry(SocketDataHandlerPtr h
)
93 typedef std::tr1::shared_ptr
<QueueEntry
> QueueEntryPtr
;
94 typedef uint16_t SocketId
;
95 typedef std::map
<SocketId
, QueueEntryPtr
> SocketQueueMap
;
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
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
;
115 SocketQueueMap m_socketQueues
;
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
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 // Thread function for the simple read behaviour... thread is
133 // created in the SpinoffSimpleReadThread() member below.
134 static void *SimpleReadThread(void *userptr
);
137 SocketRoutingQueue(int prealloc_buffer_count
= 4,
138 int default_read_timeout
= USBWRAP_DEFAULT_TIMEOUT
);
139 ~SocketRoutingQueue();
144 int GetWriteEp() const { return m_writeEp
; }
145 int GetReadEp() const { return m_readEp
; }
148 // These functions connect the router to an external Usb::Device
149 // object. Normally this is handled automatically by the
150 // Controller class, but are public here in case they are needed.
152 // If DoRead encounters an error, it sets a flag and stops
153 // reading. To recover, you should handle the Error() call in
154 // the callback, fix the USB device, and then call
155 // ClearUsbError() to clear the flag.
157 void SetUsbDevice(Usb::Device
*dev
, int writeEp
, int readEp
,
158 SocketDataHandlerPtr callback
= SocketDataHandlerPtr());
159 void ClearUsbDevice();
160 bool UsbDeviceReady();
161 Usb::Device
* GetUsbDevice() { return m_dev
; }
162 void ClearUsbError();
165 // This class starts out with no buffers, and will grow one buffer
166 // at a time if needed. Call this to allocate count buffers
167 // all at once and place them on the free queue.
168 void AllocateBuffers(int count
);
170 // Returns the data for the next unregistered socket.
171 // Blocks until timeout or data is available.
172 // Returns false (or null pointer) on timeout and no data.
173 // With the return version of the function, there is no
174 // copying performed.
176 // Timeout is in milliseconds. Default timeout set by constructor
177 // is used if set to -1.
178 bool DefaultRead(Data
&receive
, int timeout
= -1);
179 DataHandle
DefaultRead(int timeout
= -1);
181 // Register an interest in data from a certain socket. To read
182 // from that socket, use the SocketRead() function from then on.
183 // Any non-registered socket goes in the default queue
184 // and must be read by DefaultRead()
185 // If not null, handler is called when new data is read. It will
186 // be called in the same thread instance that DoRead() is called from.
187 // Handler is passed the DataQueue Data object, and so no
188 // copying is done. Once the handler returns, the data is
189 // considered processed and not added to the interested queue,
190 // but instead returned to m_free.
191 void RegisterInterest(SocketId socket
, SocketDataHandlerPtr handler
);
193 // Unregisters interest in data from the given socket, and discards
194 // any existing data in its interest queue. Any new incoming data
195 // for this socket will be placed in the default queue.
196 void UnregisterInterest(SocketId socket
);
198 // Reads data from the interested socket cache. Can only read
199 // from sockets that have been previously registered.
200 // Blocks until timeout or data is available.
201 // Returns false (or null pointer) on timeout and no data.
202 // With the return version of the function, there is no
203 // copying performed.
205 // Timeout is in milliseconds. Default timeout set by constructor
206 // is used if set to -1.
207 bool SocketRead(SocketId socket
, Data
&receive
, int timeout
= -1);
208 DataHandle
SocketRead(SocketId socket
, int timeout
= -1);
210 // Returns true if data is available for that socket.
211 bool IsAvailable(SocketId socket
) const;
213 // Called by the application's "read thread" to read the next usb
214 // packet and route it to the correct queue. Returns after every
215 // read, even if a handler is associated with a queue.
216 // Note: this function is safe to call before SetUsbDevice() is
217 // called... it just doesn't do anything if there is no usb
218 // device to work with.
220 // Timeout is in milliseconds. Default is default USB timeout.
221 void DoRead(int timeout
= -1);
223 // Utility function to make it easier for the user to create the
224 // USB pure-read thread. If the user wants anything more complicated
225 // in this background thread, he can implement it himself and call
226 // the above DoRead() in a loop. If only the basics are needed,
227 // then this makes it easy.
228 // Throws Barry::ErrnoError on thread creation error.
229 void SpinoffSimpleReadThread();
236 /// std::auto_ptr like class that handles pointers to Data, but instead of
237 /// freeing them completely, the Data objects are turned to the
238 /// SocketRoutingQueue from whence they came.
240 class BXEXPORT DataHandle
243 SocketRoutingQueue
&m_queue
;
244 mutable Data
*m_data
;
250 m_queue
.ReturnBuffer(m_data
);
256 DataHandle(SocketRoutingQueue
&q
, Data
*data
)
262 DataHandle(const DataHandle
&other
)
263 : m_queue(other
.m_queue
)
264 , m_data(other
.m_data
)
266 // we now own the pointer
280 Data
* release() // no longer owns the pointer
292 const Data
* operator->() const
297 DataHandle
& operator=(const DataHandle
&other
)
299 if( &m_queue
!= &other
.m_queue
)
300 throw std::logic_error("Trying to copy DataHandles of different queues!");
302 // remove our current data
306 m_data
= other
.m_data
;