Updating text, names and comments to be consistent and generally make a bit more...
[barry.git] / src / router.h
blobeaf08fa0551449eb936395354d71abb4daef5db7
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"
33 namespace Usb { class Device; }
35 namespace Barry {
37 class DataHandle;
39 class BXEXPORT SocketRoutingQueue
41 friend class DataHandle;
43 public:
44 typedef void (*SocketDataHandler)(void *ctx, Data*); //< See RegisterInterest() for information on this callback.
45 struct QueueEntry
47 SocketDataHandler m_handler;
48 void *m_context;
49 DataQueue m_queue;
51 QueueEntry(SocketDataHandler h, void *c)
52 : m_handler(h)
53 , m_context(c)
56 typedef std::tr1::shared_ptr<QueueEntry> QueueEntryPtr;
57 typedef uint16_t SocketId;
58 typedef std::map<SocketId, QueueEntryPtr> SocketQueueMap;
60 private:
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
69 // locking per queue
71 pthread_mutex_t m_readwaitMutex;
72 pthread_cond_t m_readwaitCond;
74 DataQueue m_free;
75 DataQueue m_default;
76 SocketQueueMap m_socketQueues;
78 // thread state
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
85 protected:
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);
95 public:
96 SocketRoutingQueue(int prealloc_buffer_count = 4);
97 ~SocketRoutingQueue();
100 // data access
102 int GetWriteEp() const { return m_writeEp; }
103 int GetReadEp() const { return m_readEp; }
106 // These functions connect the router to an external Usb::Device
107 // object. Normally this is handled automatically by the
108 // Controller class, but are public here in case they are needed.
109 void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp);
110 void ClearUsbDevice();
111 bool UsbDeviceReady();
112 Usb::Device* GetUsbDevice() { return m_dev; }
114 // This class starts out with no buffers, and will grow one buffer
115 // at a time if needed. Call this to allocate count buffers
116 // all at once and place them on the free queue.
117 void AllocateBuffers(int count);
119 // Returns the data for the next unregistered socket.
120 // Blocks until timeout or data is available.
121 // Returns false (or null pointer) on timeout and no data.
122 // With the return version of the function, there is no
123 // copying performed.
124 bool DefaultRead(Data &receive, int timeout = -1);
125 DataHandle DefaultRead(int timeout = -1);
127 // Register an interest in data from a certain socket. To read
128 // from that socket, use the SocketRead() function from then on.
129 // Any non-registered socket goes in the default queue
130 // and must be read by DefaultRead()
131 // If not null, handler is called when new data is read. It will
132 // be called in the same thread instance that DoRead() is called from.
133 // Handler is passed the DataQueue Data pointer, and so no
134 // copying is done. Once the handler returns, the data is
135 // considered processed and not added to the interested queue,
136 // but instead returned to m_free.
137 void RegisterInterest(SocketId socket, SocketDataHandler handler = 0, void *context = 0);
139 // Unregisters interest in data from the given socket, and discards
140 // any existing data in its interest queue. Any new incoming data
141 // for this socket will be placed in the default queue.
142 void UnregisterInterest(SocketId socket);
144 // Reads data from the interested socket cache. Can only read
145 // from sockets that have been previously registered.
146 // Blocks until timeout or data is available.
147 // Returns false (or null pointer) on timeout and no data.
148 // With the return version of the function, there is no
149 // copying performed.
150 bool SocketRead(SocketId socket, Data &receive, int timeout = -1);
151 DataHandle SocketRead(SocketId socket, int timeout = -1);
153 // Returns true if data is available for that socket.
154 bool IsAvailable(SocketId socket) const;
156 // Called by the application's "read thread" to read the next usb
157 // packet and route it to the correct queue. Returns after every
158 // read, even if a handler is associated with a queue.
159 // Note: this function is safe to call before SetUsbDevice() is
160 // called... it just doesn't do anything if there is no usb
161 // device to work with.
163 // Timeout is in milliseconds.
165 // Returns false in the case of USB errors, and puts the error
166 // message in msg.
167 bool DoRead(std::string &msg, int timeout = -1);
169 // Utility function to make it easier for the user to create the
170 // USB pure-read thread. If the user wants anything more complicated
171 // in this background thread, he can implement it himself and call
172 // the above DoRead() in a loop. If only the basics are needed,
173 // then this makes it easy.
174 // Throws Barry::ErrnoError on thread creation error.
175 void SpinoffSimpleReadThread();
180 // DataHandle
182 /// std::auto_ptr like class that handles pointers to Data, but instead of
183 /// freeing them completely, the Data objects are turned to the
184 /// SocketRoutingQueue from whence they came.
186 class BXEXPORT DataHandle
188 private:
189 SocketRoutingQueue &m_queue;
190 mutable Data *m_data;
192 protected:
193 void clear()
195 if( m_data ) {
196 m_queue.ReturnBuffer(m_data);
197 m_data = 0;
201 public:
202 DataHandle(SocketRoutingQueue &q, Data *data)
203 : m_queue(q)
204 , m_data(data)
208 DataHandle(const DataHandle &other)
209 : m_queue(other.m_queue)
210 , m_data(other.m_data)
212 // we now own the pointer
213 other.m_data = 0;
216 ~DataHandle()
218 clear();
221 Data* get()
223 return m_data;
226 Data* release() // no longer owns the pointer
228 Data *ret = m_data;
229 m_data = 0;
230 return ret;
233 Data* operator->()
235 return m_data;
238 const Data* operator->() const
240 return m_data;
243 DataHandle& operator=(const DataHandle &other)
245 if( &m_queue != &other.m_queue )
246 throw std::logic_error("Trying to copy DataHandles of different queues!");
248 // remove our current data
249 clear();
251 // accept the new
252 m_data = other.m_data;
254 // we now own it
255 other.m_data = 0;
257 return *this;
263 } // namespace Barry
265 #endif