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 <blackboard/net/handler.h>
25 #include <blackboard/net/messages.h>
26 #include <blackboard/net/ilist_content.h>
27 #include <blackboard/blackboard.h>
28 #include <blackboard/exceptions.h>
29 #include <blackboard/net/interface_listener.h>
30 #include <blackboard/net/interface_observer.h>
31 
32 #include <interface/interface.h>
33 #include <interface/interface_info.h>
34 
35 #include <logging/liblogger.h>
36 #include <netcomm/fawkes/component_ids.h>
37 #include <netcomm/fawkes/hub.h>
38 
39 #include <cstdlib>
40 #include <cstring>
41 #include <arpa/inet.h>
42 
43 namespace fawkes {
44 
45 /** @class BlackBoardNetworkHandler <blackboard/net/handler.h>
46  * BlackBoard Network Handler.
47  * This class provides a network handler that can be registered with the
48  * FawkesServerThread to handle client requests to a BlackBoard instance.
49  *
50  * @author Tim Niemueller
51  */
52 
53 /** Constructor.
54  * @param blackboard BlackBoard instance to provide network access to
55  * @param hub Fawkes network hub
56  */
58  FawkesNetworkHub *hub)
59  : Thread("BlackBoardNetworkHandler", Thread::OPMODE_WAITFORWAKEUP),
60  FawkesNetworkHandler(FAWKES_CID_BLACKBOARD)
61 {
62  __bb = blackboard;
63  __nhub = hub;
64  __nhub->add_handler(this);
65 
66  __observer = new BlackBoardNetHandlerInterfaceObserver(blackboard, hub);
67 }
68 
69 
70 /** Destructor. */
72 {
73  delete __observer;
74  __nhub->remove_handler(this);
75  __inbound_queue.clear();
76  // close all open interfaces
77  for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
78  delete __lit->second;
79  }
80  for (__iit = __interfaces.begin(); __iit != __interfaces.end(); ++__iit) {
81  __bb->close(__iit->second);
82  }
83 }
84 
85 
86 /** Process all network messages that have been received. */
87 void
89 {
90  while ( ! __inbound_queue.empty() ) {
91  FawkesNetworkMessage *msg = __inbound_queue.front();
92 
93  // used often and thus queried _once_
94  unsigned int clid = msg->clid();
95 
96  switch (msg->msgid()) {
97  case MSG_BB_LIST_ALL:
98  {
100  InterfaceInfoList *infl = __bb->list_all();
101 
102  for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
103  ilist->append_interface(*i);
104  }
105 
106  try {
107  __nhub->send(clid, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_LIST, ilist);
108  } catch (Exception &e) {
109  LibLogger::log_error("BlackBoardNetworkHandler", "Failed to send interface "
110  "list to %u, exception follows", clid);
111  LibLogger::log_error("BlackBoardNetworkHandler", e);
112  }
113  delete infl;
114  }
115  break;
116 
117  case MSG_BB_LIST:
118  {
121 
122  bb_ilistreq_msg_t *lrm = msg->msg<bb_ilistreq_msg_t>();
123 
124  char type_pattern[__INTERFACE_TYPE_SIZE + 1];
125  char id_pattern[__INTERFACE_ID_SIZE + 1];
126  type_pattern[__INTERFACE_TYPE_SIZE] = 0;
127  id_pattern[__INTERFACE_ID_SIZE] = 0;
128  strncpy(type_pattern, lrm->type_pattern, __INTERFACE_TYPE_SIZE);
129  strncpy(id_pattern, lrm->id_pattern, __INTERFACE_ID_SIZE);
130 
131  InterfaceInfoList *infl = __bb->list(type_pattern, id_pattern);
132  for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i)
133  {
134  ilist->append_interface(*i);
135  }
136 
137  try {
138  __nhub->send(clid, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_LIST, ilist);
139  } catch (Exception &e) {
140  LibLogger::log_error("BlackBoardNetworkHandler", "Failed to send "
141  "interface list to %u, exception follows", clid);
142  LibLogger::log_error("BlackBoardNetworkHandler", e);
143  }
144  delete infl;
145  }
146  break;
147 
148  case MSG_BB_OPEN_FOR_READING:
149  case MSG_BB_OPEN_FOR_WRITING:
150  {
151  bb_iopen_msg_t *om = msg->msg<bb_iopen_msg_t>();
152 
153  char type[__INTERFACE_TYPE_SIZE + 1];
154  char id[__INTERFACE_ID_SIZE + 1];
155  type[__INTERFACE_TYPE_SIZE] = 0;
156  id[__INTERFACE_ID_SIZE] = 0;
157  strncpy(type, om->type, __INTERFACE_TYPE_SIZE);
158  strncpy(id, om->id, __INTERFACE_ID_SIZE);
159 
160  LibLogger::log_debug("BlackBoardNetworkHandler", "Remote opens interface %s::%s",
161  type, id);
162  try {
163  Interface *iface;
164 
165  if ( msg->msgid() == MSG_BB_OPEN_FOR_READING ) {
166  iface = __bb->open_for_reading(type, id, "remote");
167  } else {
168  iface = __bb->open_for_writing(type, id, "remote");
169  }
170  if ( memcmp(iface->hash(), om->hash, __INTERFACE_HASH_SIZE) != 0 ) {
171  LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed, "
172  "hash mismatch", type, id);
173  send_openfailure(clid, BB_ERR_HASH_MISMATCH);
174  } else {
175  __interfaces[iface->serial()] = iface;
176  __client_interfaces[clid].push_back(iface);
177  __serial_to_clid[iface->serial()] = clid;
178  __listeners[iface->serial()] = new BlackBoardNetHandlerInterfaceListener(__bb,
179  iface,
180  __nhub,
181  clid);
182  send_opensuccess(clid, iface);
183  }
184  } catch (BlackBoardInterfaceNotFoundException &nfe) {
185  LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed, "
186  "interface class not found", type, id);
187  send_openfailure(clid, BB_ERR_UNKNOWN_TYPE);
188  } catch (BlackBoardWriterActiveException &wae) {
189  LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed, "
190  "writer already exists", type, id);
191  send_openfailure(clid, BB_ERR_WRITER_EXISTS);
192  } catch (Exception &e) {
193  LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed",
194  type, 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  }
204  break;
205 
206  case MSG_BB_CLOSE:
207  {
208  bb_iserial_msg_t *sm = msg->msg<bb_iserial_msg_t>();
209  unsigned int sm_serial = ntohl(sm->serial);
210  if ( __interfaces.find(sm_serial) != __interfaces.end() ) {
211  bool close = false;
212  __client_interfaces.lock();
213  if ( __client_interfaces.find(clid) != __client_interfaces.end()) {
214  // this client has interfaces, check if this one as well
215  for ( __ciit = __client_interfaces[clid].begin(); __ciit != __client_interfaces[clid].end(); ++__ciit) {
216  if ( (*__ciit)->serial() == sm_serial ) {
217  close = true;
218  __serial_to_clid.erase(sm_serial);
219  __client_interfaces[clid].erase(__ciit);
220  if ( __client_interfaces[clid].empty() ) {
221  __client_interfaces.erase(clid);
222  }
223  break;
224  }
225  }
226  }
227  __client_interfaces.unlock();
228 
229  if ( close ) {
230  __interfaces.lock();
231  LibLogger::log_debug("BlackBoardNetworkHandler", "Remote %u closing interface %s",
232  clid, __interfaces[sm_serial]->uid());
233  delete __listeners[sm_serial];
234  __listeners.erase(sm_serial);
235  __bb->close(__interfaces[sm_serial]);
236  __interfaces.erase(sm_serial);
237  __interfaces.unlock();
238  } else {
239  LibLogger::log_warn("BlackBoardNetworkHandler", "Client %u tried to close "
240  "interface with serial %u, but opened by other client",
241  clid, sm_serial);
242  }
243  } else {
244  LibLogger::log_warn("BlackBoardNetworkHandler", "Client %u tried to close "
245  "interface with serial %u which has not been opened",
246  clid, sm_serial);
247  }
248 
249  //LibLogger::log_debug("BBNH", "C: interfaces: %zu s2c: %zu ci: %zu",
250  // __interfaces.size(), __serial_to_clid.size(),
251  // __client_interfaces.size());
252  }
253  break;
254 
255  case MSG_BB_DATA_CHANGED:
256  {
257  void *payload = msg->payload();
258  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
259  unsigned int dm_serial = ntohl(dm->serial);
260  if ( __interfaces.find(dm_serial) != __interfaces.end() ) {
261 
262  if ( ntohl(dm->data_size) != __interfaces[dm_serial]->datasize() ) {
263  LibLogger::log_error("BlackBoardNetworkHandler", "DATA_CHANGED: Data size mismatch, "
264  "expected %zu, but got %zu, ignoring.",
265  __interfaces[dm_serial]->datasize(), ntohl(dm->data_size));
266  } else {
267  __interfaces[dm_serial]->set_from_chunk((char *)payload + sizeof(bb_idata_msg_t));
268  __interfaces[dm_serial]->write();
269  }
270  } else {
271  LibLogger::log_error("BlackBoardNetworkHandler", "DATA_CHANGED: Interface with "
272  "serial %u not found, ignoring.", dm_serial);
273  }
274  }
275  break;
276 
277  case MSG_BB_INTERFACE_MESSAGE:
278  {
279  void *payload = msg->payload();
280  bb_imessage_msg_t *mm = (bb_imessage_msg_t *)payload;
281  unsigned int mm_serial = ntohl(mm->serial);
282  if ( __interfaces.find(mm_serial) != __interfaces.end() ) {
283 
284  if ( ! __interfaces[mm_serial]->is_writer() ) {
285  try {
286  Message *ifm = __interfaces[mm_serial]->create_message(mm->msg_type);
287  ifm->set_id(ntohl(mm->msgid));
288  ifm->set_hops(ntohl(mm->hops));
289 
290  if ( ntohl(mm->data_size) != ifm->datasize() ) {
291  LibLogger::log_error("BlackBoardNetworkHandler", "MESSAGE: Data size mismatch, "
292  "expected %zu, but got %zu, ignoring.",
293  ifm->datasize(), ntohl(mm->data_size));
294  } else {
295  ifm->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
296 
297  __interfaces[mm_serial]->msgq_enqueue(ifm);
298 
299  }
300  } catch (Exception &e) {
301  LibLogger::log_error("BlackBoardNetworkHandler", "MESSAGE: Could not create "
302  "interface message, ignoring.");
303  LibLogger::log_error("BlackBoardNetworkHandler", e);
304  }
305  } else {
306  LibLogger::log_error("BlackBoardNetworkHandler", "MESSAGE: Received message "
307  "notification, but for a writing instance, ignoring.");
308  }
309  } else {
310  LibLogger::log_error("BlackBoardNetworkHandler", "DATA_CHANGED: Interface with "
311  "serial %u not found, ignoring.", mm_serial);
312  }
313  }
314  break;
315 
316  default:
317  LibLogger::log_warn("BlackBoardNetworkHandler", "Unknown message of type %u "
318  "received", msg->msgid());
319  break;
320  }
321 
322  msg->unref();
323  __inbound_queue.pop_locked();
324  }
325 }
326 
327 
328 void
329 BlackBoardNetworkHandler::send_opensuccess(unsigned int clid, Interface *interface)
330 {
331  void *payload = calloc(1, sizeof(bb_iopensucc_msg_t) + interface->datasize());
332  bb_iopensucc_msg_t *osm = (bb_iopensucc_msg_t *)payload;
333  osm->serial = htonl(interface->serial());
334  osm->writer_readers = htonl(interface->num_readers());
335  if (interface->has_writer()) {
336  osm->writer_readers |= htonl(0x80000000);
337  } else {
338  osm->writer_readers &= htonl(0x7FFFFFFF);
339  }
340  osm->data_size = htonl(interface->datasize());
341 
342  if ( ! interface->is_writer() ) {
343  interface->read();
344  }
345 
346  memcpy((char *)payload + sizeof(bb_iopensucc_msg_t),
347  interface->datachunk(), interface->datasize());
348 
349  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(clid, FAWKES_CID_BLACKBOARD,
350  MSG_BB_OPEN_SUCCESS, payload,
351  sizeof(bb_iopensucc_msg_t) +
352  interface->datasize());
353  try {
354  __nhub->send(omsg);
355  } catch (Exception &e) {
356  LibLogger::log_error("BlackBoardNetworkHandler", "Failed to send interface "
357  "open success to %u, exception follows", clid);
358  LibLogger::log_error("BlackBoardNetworkHandler", e);
359  }
360 }
361 
362 
363 void
364 BlackBoardNetworkHandler::send_openfailure(unsigned int clid, unsigned int error_code)
365 {
366  bb_iopenfail_msg_t *ofm = (bb_iopenfail_msg_t *)malloc(sizeof(bb_iopenfail_msg_t));
367  ofm->error_code = htonl(error_code);
368 
369  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(clid, FAWKES_CID_BLACKBOARD,
370  MSG_BB_OPEN_FAILURE, ofm,
371  sizeof(bb_iopenfail_msg_t));
372  try {
373  __nhub->send(omsg);
374  } catch (Exception &e) {
375  LibLogger::log_error("BlackBoardNetworkHandler", "Failed to send interface "
376  "open failure to %u, exception follows", clid);
377  LibLogger::log_error("BlackBoardNetworkHandler", e);
378  }
379 }
380 
381 
382 /** Handle network message.
383  * The message is put into the inbound queue and processed in processAfterLoop().
384  * @param msg message
385  */
386 void
388 {
389  msg->ref();
390  __inbound_queue.push_locked(msg);
391  wakeup();
392 }
393 
394 
395 /** Client connected. Ignored.
396  * @param clid client ID
397  */
398 void
400 {
401 }
402 
403 
404 /** Client disconnected.
405  * If the client had opened any interfaces these are closed.
406  * @param clid client ID
407  */
408 void
410 {
411  // close any interface that this client had opened
412  __client_interfaces.lock();
413  if ( __client_interfaces.find(clid) != __client_interfaces.end() ) {
414  // Close all interfaces
415  for ( __ciit = __client_interfaces[clid].begin(); __ciit != __client_interfaces[clid].end(); ++__ciit) {
416  LibLogger::log_debug("BlackBoardNetworkHandler", "Closing interface %s::%s of remote "
417  "%u (client disconnected)",
418  (*__ciit)->type(), (*__ciit)->id(), clid);
419 
420  unsigned int serial = (*__ciit)->serial();
421  __serial_to_clid.erase(serial);
422  __interfaces.erase_locked(serial);
423  delete __listeners[serial];
424  __listeners.erase(serial);
425  __bb->close(*__ciit);
426  }
427  __client_interfaces.erase(clid);
428  }
429  __client_interfaces.unlock();
430 }
431 
432 } // end namespace fawkes
uint32_t msgid
message ID
Definition: messages.h:173
void * payload() const
Get payload buffer.
Definition: message.cpp:321
unsigned char hash[__INTERFACE_HASH_SIZE]
interface version hash
Definition: messages.h:81
char type[__INTERFACE_TYPE_SIZE]
interface type name
Definition: messages.h:79
void clear()
Clear the queue.
Definition: lock_queue.h:158
unsigned int datasize() const
Get data size.
Definition: interface.cpp:534
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
Requested interface type is unknown.
Definition: messages.h:59
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:99
BlackBoardNetworkHandler(BlackBoard *blackboard, FawkesNetworkHub *hub)
Constructor.
Definition: handler.cpp:57
static void log_debug(const char *component, const char *format,...)
Log debug message.
Definition: liblogger.cpp:126
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:138
Fawkes library namespace.
unsigned int clid() const
Get client ID.
Definition: message.cpp:281
Message to identify an interface on open.
Definition: messages.h:78
Interface listener for network handler.
virtual void add_handler(FawkesNetworkHandler *handler)=0
Add a message handler.
virtual void loop()
Process all network messages that have been received.
Definition: handler.cpp:88
Representation of a message that is sent over the network.
Definition: message.h:75
Thread class encapsulation of pthreads.
Definition: thread.h:42
char msg_type[__INTERFACE_MESSAGE_TYPE_SIZE]
message type
Definition: messages.h:172
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
Interface observer for blackboard network handler.
virtual InterfaceInfoList * list(const char *type_pattern, const char *id_pattern)=0
Get list of interfaces matching type and ID patterns.
You tried to open an interface for writing but there is already a writing instance for this interface...
Definition: messages.h:62
uint32_t error_code
Error code.
Definition: messages.h:149
virtual void client_disconnected(unsigned int clid)
Client disconnected.
Definition: handler.cpp:409
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:294
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:180
Fawkes Network Hub.
Definition: hub.h:33
virtual void client_connected(unsigned int clid)
Client connected.
Definition: handler.cpp:399
Interface information list.
void wakeup()
Wake up thread.
Definition: thread.cpp:1000
char id_pattern[__INTERFACE_ID_SIZE]
ID pattern.
Definition: messages.h:74
Base class for exceptions in Fawkes.
Definition: exception.h:36
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:697
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:477
virtual void send(FawkesNetworkMessage *msg)=0
Method to send a message to a specific client.
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:307
Interface open success The serial denotes a unique instance of an interface within the (remote) Black...
Definition: messages.h:137
void ref()
Increment reference count.
Definition: refcount.cpp:70
The hashes of the interfaces do not match.
Definition: messages.h:60
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:834
uint32_t data_size
data for message
Definition: messages.h:175
Network handler abstract base class.
Definition: handler.h:31
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:162
Interface data message.
Definition: messages.h:160
~BlackBoardNetworkHandler()
Destructor.
Definition: handler.cpp:71
Interface message.
Definition: messages.h:170
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:440
Unknown error occured.
Definition: messages.h:58
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.
void pop_locked()
Pop element from queue with lock protection.
Definition: lock_queue.h:149
uint32_t serial
interface instance serial
Definition: messages.h:171
char id[__INTERFACE_ID_SIZE]
interface instance ID
Definition: messages.h:80
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:301
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:161
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:116
virtual InterfaceInfoList * list_all()=0
Get list of all currently existing interfaces.
Thrown if no definition of interface or interface generator found.
Definition: exceptions.h:91
void push_locked(const Type &x)
Push element to queue with lock protection.
Definition: lock_queue.h:139
char type_pattern[__INTERFACE_TYPE_SIZE]
type pattern
Definition: messages.h:73
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
unsigned int datasize() const
Get size of data.
Definition: message.cpp:295
Message to request constrained interface list.
Definition: messages.h:72
BlackBoard interface list content.
Definition: ilist_content.h:35
Message to identify an interface instance.
Definition: messages.h:115
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:430
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:863
virtual void remove_handler(FawkesNetworkHandler *handler)=0
Remove a message handler.
The BlackBoard abstract class.
Definition: blackboard.h:48
Thrown if a writer is already active on an interface that writing has been requested for...
Definition: exceptions.h:121
MT * msg() const
Get correctly casted payload.
Definition: message.h:115
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:227
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:162
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:217
uint32_t hops
number of hops this message already passed
Definition: messages.h:174
virtual void handle_network_message(FawkesNetworkMessage *msg)
Handle network message.
Definition: handler.cpp:387
virtual void close(Interface *interface)=0
Close interface.
Message to send update data.
Definition: messages.h:148