Fawkes API Fawkes Development Version
handler.cpp
1
2/***************************************************************************
3 * network_handler.cpp - BlackBoard Network Handler
4 *
5 * Generated: Sat Mar 01 16:00:34 2008
6 * Copyright 2006-2007 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <arpa/inet.h>
25#include <blackboard/blackboard.h>
26#include <blackboard/exceptions.h>
27#include <blackboard/net/handler.h>
28#include <blackboard/net/ilist_content.h>
29#include <blackboard/net/interface_listener.h>
30#include <blackboard/net/interface_observer.h>
31#include <blackboard/net/messages.h>
32#include <interface/interface.h>
33#include <interface/interface_info.h>
34#include <logging/liblogger.h>
35#include <netcomm/fawkes/component_ids.h>
36#include <netcomm/fawkes/hub.h>
37
38#include <cstdlib>
39#include <cstring>
40
41namespace fawkes {
42
43/** @class BlackBoardNetworkHandler <blackboard/net/handler.h>
44 * BlackBoard Network Handler.
45 * This class provides a network handler that can be registered with the
46 * FawkesServerThread to handle client requests to a BlackBoard instance.
47 *
48 * @author Tim Niemueller
49 */
50
51/** Constructor.
52 * @param blackboard BlackBoard instance to provide network access to
53 * @param hub Fawkes network hub
54 */
56: Thread("BlackBoardNetworkHandler", Thread::OPMODE_WAITFORWAKEUP),
57 FawkesNetworkHandler(FAWKES_CID_BLACKBOARD)
58{
59 bb_ = blackboard;
60 nhub_ = hub;
61 nhub_->add_handler(this);
62
63 observer_ = new BlackBoardNetHandlerInterfaceObserver(blackboard, hub);
64}
65
66/** Destructor. */
68{
69 delete observer_;
70 nhub_->remove_handler(this);
71 inbound_queue_.clear();
72 // close all open interfaces
73 for (lit_ = listeners_.begin(); lit_ != listeners_.end(); ++lit_) {
74 delete lit_->second;
75 }
76 for (iit_ = interfaces_.begin(); iit_ != interfaces_.end(); ++iit_) {
77 bb_->close(iit_->second);
78 }
79}
80
81/** Process all network messages that have been received. */
82void
84{
85 while (!inbound_queue_.empty()) {
86 FawkesNetworkMessage *msg = inbound_queue_.front();
87
88 // used often and thus queried _once_
89 unsigned int clid = msg->clid();
90
91 switch (msg->msgid()) {
92 case MSG_BB_LIST_ALL: {
94 InterfaceInfoList * infl = bb_->list_all();
95
96 for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
97 ilist->append_interface(*i);
98 }
99
100 try {
101 nhub_->send(clid, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_LIST, ilist);
102 } catch (Exception &e) {
103 LibLogger::log_error("BlackBoardNetworkHandler",
104 "Failed to send interface "
105 "list to %u, exception follows",
106 clid);
107 LibLogger::log_error("BlackBoardNetworkHandler", e);
108 }
109 delete infl;
110 } break;
111
112 case MSG_BB_LIST: {
114
116
117 char type_pattern[INTERFACE_TYPE_SIZE_ + 1];
118 char id_pattern[INTERFACE_ID_SIZE_ + 1];
119 type_pattern[INTERFACE_TYPE_SIZE_] = 0;
120 id_pattern[INTERFACE_ID_SIZE_] = 0;
121 strncpy(type_pattern, lrm->type_pattern, INTERFACE_TYPE_SIZE_);
122 strncpy(id_pattern, lrm->id_pattern, INTERFACE_ID_SIZE_);
123
124 InterfaceInfoList *infl = bb_->list(type_pattern, id_pattern);
125 for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
126 ilist->append_interface(*i);
127 }
128
129 try {
130 nhub_->send(clid, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_LIST, ilist);
131 } catch (Exception &e) {
132 LibLogger::log_error("BlackBoardNetworkHandler",
133 "Failed to send "
134 "interface list to %u, exception follows",
135 clid);
136 LibLogger::log_error("BlackBoardNetworkHandler", e);
137 }
138 delete infl;
139 } break;
140
141 case MSG_BB_OPEN_FOR_READING:
142 case MSG_BB_OPEN_FOR_WRITING: {
143 bb_iopen_msg_t *om = msg->msg<bb_iopen_msg_t>();
144
145 char type[INTERFACE_TYPE_SIZE_ + 1];
146 char id[INTERFACE_ID_SIZE_ + 1];
147 type[INTERFACE_TYPE_SIZE_] = 0;
148 id[INTERFACE_ID_SIZE_] = 0;
149 strncpy(type, om->type, INTERFACE_TYPE_SIZE_);
150 strncpy(id, om->id, INTERFACE_ID_SIZE_);
151
152 LibLogger::log_debug("BlackBoardNetworkHandler", "Remote opens interface %s::%s", type, id);
153 try {
154 Interface *iface;
155
156 if (msg->msgid() == MSG_BB_OPEN_FOR_READING) {
157 iface = bb_->open_for_reading(type, id, "remote");
158 } else {
159 iface = bb_->open_for_writing(type, id, "remote");
160 }
161 if (memcmp(iface->hash(), om->hash, INTERFACE_HASH_SIZE_) != 0) {
162 LibLogger::log_warn("BlackBoardNetworkHandler",
163 "Opening interface %s::%s failed, "
164 "hash mismatch",
165 type,
166 id);
167 send_openfailure(clid, BB_ERR_HASH_MISMATCH);
168 } else {
169 interfaces_[iface->serial()] = iface;
170 client_interfaces_[clid].push_back(iface);
171 serial_to_clid_[iface->serial()] = clid;
172 listeners_[iface->serial()] =
173 new BlackBoardNetHandlerInterfaceListener(bb_, iface, nhub_, clid);
174 send_opensuccess(clid, iface);
175 }
177 LibLogger::log_warn("BlackBoardNetworkHandler",
178 "Opening interface %s::%s failed, "
179 "interface class not found",
180 type,
181 id);
182 send_openfailure(clid, BB_ERR_UNKNOWN_TYPE);
183 } catch (BlackBoardWriterActiveException &wae) {
184 LibLogger::log_warn("BlackBoardNetworkHandler",
185 "Opening interface %s::%s failed, "
186 "writer already exists",
187 type,
188 id);
189 send_openfailure(clid, BB_ERR_WRITER_EXISTS);
190 } catch (Exception &e) {
191 LibLogger::log_warn("BlackBoardNetworkHandler",
192 "Opening interface %s::%s failed",
193 type,
194 id);
195 LibLogger::log_warn("BlackBoardNetworkHandler", e);
196 send_openfailure(clid, BB_ERR_UNKNOWN_ERR);
197 }
198
199 //LibLogger::log_debug("BBNH", "interfaces: %zu s2c: %zu ci: %zu",
200 // interfaces_.size(), serial_to_clid_.size(),
201 // client_interfaces_.size());
202
203 } break;
204
205 case MSG_BB_CLOSE: {
207 Uuid sm_serial = sm->serial;
208 if (interfaces_.find(sm_serial) != interfaces_.end()) {
209 bool close = false;
210 client_interfaces_.lock();
211 if (client_interfaces_.find(clid) != client_interfaces_.end()) {
212 // this client has interfaces, check if this one as well
213 for (ciit_ = client_interfaces_[clid].begin(); ciit_ != client_interfaces_[clid].end();
214 ++ciit_) {
215 if ((*ciit_)->serial() == sm_serial) {
216 close = true;
217 serial_to_clid_.erase(sm_serial);
218 client_interfaces_[clid].erase(ciit_);
219 if (client_interfaces_[clid].empty()) {
220 client_interfaces_.erase(clid);
221 }
222 break;
223 }
224 }
225 }
226 client_interfaces_.unlock();
227
228 if (close) {
229 interfaces_.lock();
230 LibLogger::log_debug("BlackBoardNetworkHandler",
231 "Remote %u closing interface %s",
232 clid,
233 interfaces_[sm_serial]->uid());
234 delete listeners_[sm_serial];
235 listeners_.erase(sm_serial);
236 bb_->close(interfaces_[sm_serial]);
237 interfaces_.erase(sm_serial);
238 interfaces_.unlock();
239 } else {
240 LibLogger::log_warn("BlackBoardNetworkHandler",
241 "Client %u tried to close "
242 "interface with serial %s, but opened by other client",
243 clid,
244 sm_serial.get_string().c_str());
245 }
246 } else {
247 LibLogger::log_warn("BlackBoardNetworkHandler",
248 "Client %u tried to close "
249 "interface with serial %s which has not been opened",
250 clid,
251 sm_serial.get_string().c_str());
252 }
253
254 //LibLogger::log_debug("BBNH", "C: interfaces: %zu s2c: %zu ci: %zu",
255 // interfaces_.size(), serial_to_clid_.size(),
256 // client_interfaces_.size());
257 } break;
258
259 case MSG_BB_DATA_CHANGED:
260 case MSG_BB_DATA_REFRESHED: {
261 bool data_changed = msg->msgid() == MSG_BB_DATA_CHANGED;
262 void * payload = msg->payload();
263 bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
264 Uuid dm_serial = dm->serial;
265 if (interfaces_.find(dm_serial) != interfaces_.end()) {
266 if (ntohl(dm->data_size) != interfaces_[dm_serial]->datasize()) {
267 LibLogger::log_error("BlackBoardNetworkHandler",
268 "%s: Data size mismatch, expected %zu, but got %zu, ignoring.",
269 data_changed ? "DATA_CHANGED" : "DATA_REFRESHED",
270 interfaces_[dm_serial]->datasize(),
271 ntohl(dm->data_size));
272 } else {
273 interfaces_[dm_serial]->set_from_chunk((char *)payload + sizeof(bb_idata_msg_t));
274 if (data_changed)
275 interfaces_[dm_serial]->mark_data_changed();
276 interfaces_[dm_serial]->write();
277 }
278 } else {
279 LibLogger::log_error("BlackBoardNetworkHandler",
280 "%s: Interface with "
281 "serial %s not found, ignoring.",
282 data_changed ? "DATA_CHANGED" : "DATA_REFRESHED",
283 dm_serial.get_string().c_str());
284 }
285 } break;
286
287 case MSG_BB_INTERFACE_MESSAGE: {
288 void * payload = msg->payload();
289 bb_imessage_msg_t *mm = (bb_imessage_msg_t *)payload;
290 Uuid mm_serial = mm->serial;
291 Uuid mm_source = mm->source;
292 if (interfaces_.find(mm_serial) != interfaces_.end()) {
293 if (!interfaces_[mm_serial]->is_writer()) {
294 try {
295 Message *ifm = interfaces_[mm_serial]->create_message(mm->msg_type);
296 ifm->set_id(ntohl(mm->msgid));
297 ifm->set_hops(ntohl(mm->hops));
298
299 if (ntohl(mm->data_size) != ifm->datasize()) {
300 LibLogger::log_error("BlackBoardNetworkHandler",
301 "MESSAGE: Data size mismatch, "
302 "expected %zu, but got %zu, ignoring.",
303 ifm->datasize(),
304 ntohl(mm->data_size));
305 } else {
306 ifm->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
307 ifm->set_source_id(mm_source);
308 LibLogger::log_debug("BlackBoardNetworkHandler",
309 "Processing message from sender %s, source %s, mm source %s",
310 ifm->sender_id().get_string().c_str(),
311 ifm->source_id().get_string().c_str(),
312 mm_source.get_string().c_str());
313
314 interfaces_[mm_serial]->msgq_enqueue(ifm, true);
315 }
316 } catch (Exception &e) {
317 LibLogger::log_error("BlackBoardNetworkHandler",
318 "MESSAGE: Could not create "
319 "interface message, ignoring.");
320 LibLogger::log_error("BlackBoardNetworkHandler", e);
321 }
322 } else {
323 LibLogger::log_error("BlackBoardNetworkHandler",
324 "MESSAGE: Received message "
325 "notification, but for a writing instance, ignoring.");
326 }
327 } else {
328 LibLogger::log_error("BlackBoardNetworkHandler",
329 "DATA_CHANGED: Interface with "
330 "serial %s not found, ignoring.",
331 mm_serial.get_string().c_str());
332 }
333 } break;
334
335 default:
336 LibLogger::log_warn("BlackBoardNetworkHandler",
337 "Unknown message of type %u "
338 "received",
339 msg->msgid());
340 break;
341 }
342
343 msg->unref();
344 inbound_queue_.pop_locked();
345 }
346}
347
348void
349BlackBoardNetworkHandler::send_opensuccess(unsigned int clid, Interface *interface)
350{
351 void * payload = calloc(1, sizeof(bb_iopensucc_msg_t) + interface->datasize());
352 bb_iopensucc_msg_t *osm = (bb_iopensucc_msg_t *)payload;
353 osm->serial = interface->serial();
354 osm->writer_readers = htonl(interface->num_readers());
355 if (interface->has_writer()) {
356 osm->writer_readers |= htonl(0x80000000);
357 } else {
358 osm->writer_readers &= htonl(0x7FFFFFFF);
359 }
360 osm->data_size = htonl(interface->datasize());
361
362 if (!interface->is_writer()) {
363 interface->read();
364 }
365
366 memcpy((char *)payload + sizeof(bb_iopensucc_msg_t),
367 interface->datachunk(),
368 interface->datasize());
369
370 FawkesNetworkMessage *omsg =
371 new FawkesNetworkMessage(clid,
372 FAWKES_CID_BLACKBOARD,
373 MSG_BB_OPEN_SUCCESS,
374 payload,
375 sizeof(bb_iopensucc_msg_t) + interface->datasize());
376 try {
377 nhub_->send(omsg);
378 } catch (Exception &e) {
379 LibLogger::log_error("BlackBoardNetworkHandler",
380 "Failed to send interface "
381 "open success to %u, exception follows",
382 clid);
383 LibLogger::log_error("BlackBoardNetworkHandler", e);
384 }
385}
386
387void
388BlackBoardNetworkHandler::send_openfailure(unsigned int clid, unsigned int error_code)
389{
390 bb_iopenfail_msg_t *ofm = (bb_iopenfail_msg_t *)malloc(sizeof(bb_iopenfail_msg_t));
391 ofm->error_code = htonl(error_code);
392
393 FawkesNetworkMessage *omsg = new FawkesNetworkMessage(
394 clid, FAWKES_CID_BLACKBOARD, MSG_BB_OPEN_FAILURE, ofm, sizeof(bb_iopenfail_msg_t));
395 try {
396 nhub_->send(omsg);
397 } catch (Exception &e) {
398 LibLogger::log_error("BlackBoardNetworkHandler",
399 "Failed to send interface "
400 "open failure to %u, exception follows",
401 clid);
402 LibLogger::log_error("BlackBoardNetworkHandler", e);
403 }
404}
405
406/** Handle network message.
407 * The message is put into the inbound queue and processed in processAfterLoop().
408 * @param msg message
409 */
410void
412{
413 msg->ref();
414 inbound_queue_.push_locked(msg);
415 wakeup();
416}
417
418/** Client connected. Ignored.
419 * @param clid client ID
420 */
421void
423{
424}
425
426/** Client disconnected.
427 * If the client had opened any interfaces these are closed.
428 * @param clid client ID
429 */
430void
432{
433 // close any interface that this client had opened
434 client_interfaces_.lock();
435 if (client_interfaces_.find(clid) != client_interfaces_.end()) {
436 // Close all interfaces
437 for (ciit_ = client_interfaces_[clid].begin(); ciit_ != client_interfaces_[clid].end();
438 ++ciit_) {
439 LibLogger::log_debug("BlackBoardNetworkHandler",
440 "Closing interface %s::%s of remote "
441 "%u (client disconnected)",
442 (*ciit_)->type(),
443 (*ciit_)->id(),
444 clid);
445
446 Uuid serial = (*ciit_)->serial();
447 serial_to_clid_.erase(serial);
448 interfaces_.erase_locked(serial);
449 delete listeners_[serial];
450 listeners_.erase(serial);
451 bb_->close(*ciit_);
452 }
453 client_interfaces_.erase(clid);
454 }
455 client_interfaces_.unlock();
456}
457
458} // end namespace fawkes
BlackBoard interface list content.
Definition: ilist_content.h:36
void append_interface(const char *type, const char *id, const unsigned char *hash, unsigned int serial, bool has_writer, unsigned int num_readers, const fawkes::Time &time)
Append interface info.
Thrown if no definition of interface or interface generator found.
Definition: exceptions.h:95
Interface listener for network handler.
Interface observer for blackboard network handler.
virtual void client_connected(unsigned int clid)
Client connected.
Definition: handler.cpp:422
virtual void client_disconnected(unsigned int clid)
Client disconnected.
Definition: handler.cpp:431
~BlackBoardNetworkHandler()
Destructor.
Definition: handler.cpp:67
virtual void handle_network_message(FawkesNetworkMessage *msg)
Handle network message.
Definition: handler.cpp:411
virtual void loop()
Process all network messages that have been received.
Definition: handler.cpp:83
BlackBoardNetworkHandler(BlackBoard *blackboard, FawkesNetworkHub *hub)
Constructor.
Definition: handler.cpp:55
Thrown if a writer is already active on an interface that writing has been requested for.
Definition: exceptions.h:125
The BlackBoard abstract class.
Definition: blackboard.h:46
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual InterfaceInfoList * list_all()=0
Get list of all currently existing interfaces.
virtual InterfaceInfoList * list(const char *type_pattern, const char *id_pattern)=0
Get list of interfaces matching type and ID patterns.
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
virtual void close(Interface *interface)=0
Close interface.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Network handler abstract base class.
Definition: handler.h:32
Fawkes Network Hub.
Definition: hub.h:34
virtual void send(FawkesNetworkMessage *msg)=0
Method to send a message to a specific client.
virtual void remove_handler(FawkesNetworkHandler *handler)=0
Remove a message handler.
virtual void add_handler(FawkesNetworkHandler *handler)=0
Add a message handler.
Representation of a message that is sent over the network.
Definition: message.h:77
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:294
MT * msg() const
Get correctly casted payload.
Definition: message.h:120
unsigned int clid() const
Get client ID.
Definition: message.cpp:276
void * payload() const
Get payload buffer.
Definition: message.cpp:312
Interface information list.
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:436
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:445
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:305
Uuid serial() const
Get instance serial of interface.
Definition: interface.cpp:695
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:876
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:479
unsigned int datasize() const
Get data size.
Definition: interface.cpp:540
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:848
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:156
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:174
static void log_debug(const char *component, const char *format,...)
Log debug message.
Definition: liblogger.cpp:120
void clear()
Clear the queue.
Definition: lock_queue.h:153
void pop_locked()
Pop element from queue with lock protection.
Definition: lock_queue.h:144
void push_locked(const Type &x)
Push element to queue with lock protection.
Definition: lock_queue.h:135
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
unsigned int datasize() const
Get size of data.
Definition: message.cpp:290
Uuid source_id() const
Get ID of the original source of the message.
Definition: message.cpp:346
void set_source_id(const Uuid &id)
Set source ID.
Definition: message.cpp:218
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:301
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:199
Uuid sender_id() const
Get ID of the immediate sender, not necessarily the creator of the message.
Definition: message.cpp:336
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:227
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
void ref()
Increment reference count.
Definition: refcount.cpp:67
Thread class encapsulation of pthreads.
Definition: thread.h:46
void wakeup()
Wake up thread.
Definition: thread.cpp:995
A convenience class for universally unique identifiers (UUIDs).
Definition: uuid.h:29
std::string get_string() const
Get the string representation of the Uuid.
Definition: uuid.cpp:107
Fawkes library namespace.
@ BB_ERR_UNKNOWN_ERR
Unknown error occured.
Definition: messages.h:60
@ BB_ERR_WRITER_EXISTS
You tried to open an interface for writing but there is already a writing instance for this interface...
Definition: messages.h:64
@ BB_ERR_HASH_MISMATCH
The hashes of the interfaces do not match.
Definition: messages.h:62
@ BB_ERR_UNKNOWN_TYPE
Requested interface type is unknown.
Definition: messages.h:61
Interface data message.
Definition: messages.h:165
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:167
Uuid serial
instance serial to unique identify this instance
Definition: messages.h:166
Message to request constrained interface list.
Definition: messages.h:76
char type_pattern[INTERFACE_TYPE_SIZE_]
type pattern
Definition: messages.h:77
char id_pattern[INTERFACE_ID_SIZE_]
ID pattern.
Definition: messages.h:78
Interface message.
Definition: messages.h:175
Uuid serial
interface instance serial
Definition: messages.h:176
uint32_t msgid
message ID
Definition: messages.h:179
Uuid source
serial of the original message source
Definition: messages.h:177
uint32_t data_size
data for message
Definition: messages.h:181
char msg_type[INTERFACE_MESSAGE_TYPE_SIZE_]
message type
Definition: messages.h:178
uint32_t hops
number of hops this message already passed
Definition: messages.h:180
Message to identify an interface on open.
Definition: messages.h:83
char id[INTERFACE_ID_SIZE_]
interface instance ID
Definition: messages.h:85
unsigned char hash[INTERFACE_HASH_SIZE_]
interface version hash
Definition: messages.h:86
char type[INTERFACE_TYPE_SIZE_]
interface type name
Definition: messages.h:84
Interface open success The serial denotes a unique instance of an interface within the (remote) Black...
Definition: messages.h:142
Uuid serial
instance serial to unique identify this instance
Definition: messages.h:143
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:148
uint32_t writer_readers
combined writer reader information.
Definition: messages.h:144
Message to identify an interface instance.
Definition: messages.h:120
Uuid serial
instance serial to unique identify this instance
Definition: messages.h:121