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"
33 namespace Usb
{ class Device
; }
39 class BXEXPORT SocketRoutingQueue
41 friend class DataHandle
;
44 typedef void (*SocketDataHandler
)(void *ctx
, Data
*); //< See RegisterInterest() for information on this callback.
47 SocketDataHandler m_handler
;
51 QueueEntry(SocketDataHandler h
, void *c
)
56 typedef std::tr1::shared_ptr
<QueueEntry
> QueueEntryPtr
;
57 typedef uint16_t SocketId
;
58 typedef std::map
<SocketId
, QueueEntryPtr
> SocketQueueMap
;
61 Usb::Device
* volatile m_dev
;
62 volatile int m_writeEp
, m_readEp
;
64 volatile bool m_interest
; // true if at least one socket has an interest.
65 // used to optimize the reading
67 mutable pthread_mutex_t m_mutex
;// controls access to local data, but not
68 // DataQueues, as they have their own
71 pthread_mutex_t m_readwaitMutex
;
72 pthread_cond_t m_readwaitCond
;
76 SocketQueueMap m_socketQueues
;
79 pthread_t m_usb_read_thread
;
80 volatile bool m_continue_reading
;// set to true when the thread is created,
81 // then set to false in the destructor
82 // to signal the end of the thread
83 // and handle the join
86 // Provides a method of returning a buffer to the free queue
87 // after processing. The DataHandle class calls this automatically
88 // from its destructor.
89 void ReturnBuffer(Data
*buf
);
91 // Thread function for the simple read behaviour... thread is
92 // created in the SpinoffSimpleReadThread() member below.
93 static void *SimpleReadThread(void *userptr
);
96 SocketRoutingQueue(int prealloc_buffer_count
= 4);
97 ~SocketRoutingQueue();
99 // These functions connect the router to an external Usb::Device
100 // object. Normally this is handled automatically by the
101 // Controller class, but are public here in case they are needed.
102 void SetUsbDevice(Usb::Device
*dev
, int writeEp
, int readEp
);
103 void ClearUsbDevice();
104 bool UsbDeviceReady();
105 Usb::Device
* GetUsbDevice() { return m_dev
; }
107 // This class starts out with no buffers, and will grow one buffer
108 // at a time if needed. Call this to allocate count buffers
109 // all at once and place them on the free queue.
110 void AllocateBuffers(int count
);
112 // Returns the data for the next unregistered socket.
113 // Blocks until timeout or data is available.
114 // Returns false (or null pointer) on timeout and no data.
115 // With the return version of the function, there is no
116 // copying performed.
117 bool DefaultRead(Data
&receive
, int timeout
= -1);
118 DataHandle
DefaultRead(int timeout
= -1);
120 // Register an interest in data from a certain socket. To read
121 // from that socket, use the SocketRead() function from then on.
122 // Any non-registered socket goes in the default queue
123 // and must be read by DefaultRead()
124 // If not null, handler is called when new data is read. It will
125 // be called in the same thread instance that DoRead() is called from.
126 // Handler is passed the DataQueue Data pointer, and so no
127 // copying is done. Once the handler returns, the data is
128 // considered processed and not added to the interested queue,
129 // but instead returned to m_free.
130 void RegisterInterest(SocketId socket
, SocketDataHandler handler
= 0, void *context
= 0);
132 // Unregisters interest in data from the given socket, and discards
133 // any existing data in its interest queue. Any new incoming data
134 // for this socket will be placed in the default queue.
135 void UnregisterInterest(SocketId socket
);
137 // Reads data from the interested socket cache. Can only read
138 // from sockets that have been previously registered.
139 // Blocks until timeout or data is available.
140 // Returns false (or null pointer) on timeout and no data.
141 // With the return version of the function, there is no
142 // copying performed.
143 bool SocketRead(SocketId socket
, Data
&receive
, int timeout
= -1);
144 DataHandle
SocketRead(SocketId socket
, int timeout
= -1);
146 // Returns true if data is available for that socket.
147 bool IsAvailable(SocketId socket
) const;
149 // Called by the application's "read thread" to read the next usb
150 // packet and route it to the correct queue. Returns after every
151 // read, even if a handler is associated with a queue.
152 // Note: this function is safe to call before SetUsbDevice() is
153 // called... it just doesn't do anything if there is no usb
154 // device to work with.
156 // Timeout is in milliseconds.
158 // Returns false in the case of USB errors, and puts the error
160 bool DoRead(std::string
&msg
, int timeout
= -1);
162 // Utility function to make it easier for the user to create the
163 // USB pure-read thread. If the user wants anything more complicated
164 // in this background thread, he can implement it himself and call
165 // the above DoRead() in a loop. If only the basics are needed,
166 // then this makes it easy.
167 // Throws Barry::ErrnoError on thread creation error.
168 void SpinoffSimpleReadThread();
175 /// std::auto_ptr like class that handles pointers to Data, but instead of
176 /// freeing them completely, the Data objects are turned to the
177 /// SocketRoutingQueue from whence they came.
179 class BXEXPORT DataHandle
182 SocketRoutingQueue
&m_queue
;
183 mutable Data
*m_data
;
189 m_queue
.ReturnBuffer(m_data
);
195 DataHandle(SocketRoutingQueue
&q
, Data
*data
)
201 DataHandle(const DataHandle
&other
)
202 : m_queue(other
.m_queue
)
203 , m_data(other
.m_data
)
205 // we now own the pointer
219 Data
* release() // no longer owns the pointer
231 const Data
* operator->() const
236 DataHandle
& operator=(const DataHandle
&other
)
238 if( &m_queue
!= &other
.m_queue
)
239 throw std::logic_error("Trying to copy DataHandles of different queus!");
241 // remove our current data
245 m_data
= other
.m_data
;