Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 sent 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 sent "
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);
167  } else {
168  iface = __bb->open_for_writing(type, id);
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->has_writer = interface->has_writer() ? 1 : 0;
335  osm->num_readers = htonl(interface->num_readers());
336  osm->data_size = htonl(interface->datasize());
337 
338  if ( ! interface->is_writer() ) {
339  interface->read();
340  }
341 
342  memcpy((char *)payload + sizeof(bb_iopensucc_msg_t),
343  interface->datachunk(), interface->datasize());
344 
345  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(clid, FAWKES_CID_BLACKBOARD,
346  MSG_BB_OPEN_SUCCESS, payload,
347  sizeof(bb_iopensucc_msg_t) +
348  interface->datasize());
349  try {
350  __nhub->send(omsg);
351  } catch (Exception &e) {
352  LibLogger::log_error("BlackBoardNetworkHandler", "Failed to sent interface "
353  "open success to %u, exception follows", clid);
354  LibLogger::log_error("BlackBoardNetworkHandler", e);
355  }
356 }
357 
358 
359 void
360 BlackBoardNetworkHandler::send_openfailure(unsigned int clid, unsigned int errno)
361 {
362  bb_iopenfail_msg_t *ofm = (bb_iopenfail_msg_t *)malloc(sizeof(bb_iopenfail_msg_t));
363  ofm->errno = htonl(errno);
364 
365  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(clid, FAWKES_CID_BLACKBOARD,
366  MSG_BB_OPEN_FAILURE, ofm,
367  sizeof(bb_iopenfail_msg_t));
368  try {
369  __nhub->send(omsg);
370  } catch (Exception &e) {
371  LibLogger::log_error("BlackBoardNetworkHandler", "Failed to sent interface "
372  "open failure to %u, exception follows", clid);
373  LibLogger::log_error("BlackBoardNetworkHandler", e);
374  }
375 }
376 
377 
378 /** Handle network message.
379  * The message is put into the inbound queue and processed in processAfterLoop().
380  * @param msg message
381  */
382 void
384 {
385  msg->ref();
386  __inbound_queue.push_locked(msg);
387  wakeup();
388 }
389 
390 
391 /** Client connected. Ignored.
392  * @param clid client ID
393  */
394 void
396 {
397 }
398 
399 
400 /** Client disconnected.
401  * If the client had opened any interfaces these are closed.
402  * @param clid client ID
403  */
404 void
406 {
407  // close any interface that this client had opened
408  __client_interfaces.lock();
409  if ( __client_interfaces.find(clid) != __client_interfaces.end() ) {
410  // Close all interfaces
411  for ( __ciit = __client_interfaces[clid].begin(); __ciit != __client_interfaces[clid].end(); ++__ciit) {
412  LibLogger::log_debug("BlackBoardNetworkHandler", "Closing interface %s::%s of remote "
413  "%u (client disconnected)",
414  (*__ciit)->type(), (*__ciit)->id(), clid);
415 
416  unsigned int serial = (*__ciit)->serial();
417  __serial_to_clid.erase(serial);
418  __interfaces.erase_locked(serial);
419  delete __listeners[serial];
420  __listeners.erase(serial);
421  __bb->close(*__ciit);
422  }
423  __client_interfaces.erase(clid);
424  }
425  __client_interfaces.unlock();
426 }
427 
428 } // end namespace fawkes
uint32_t msgid
message ID
Definition: messages.h:167
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
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:43
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:670
Requested interface type is unknown.
Definition: messages.h:59
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:99
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:811
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:124
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:134
Message to identify an interface on open.
Definition: messages.h:78
void * payload() const
Get payload buffer.
Definition: message.cpp:321
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
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:292
Representation of a message that is sent over the network.
Definition: message.h:75
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:301
unsigned int datasize() const
Get size of data.
Definition: message.cpp:295
Thread class encapsulation of pthreads.
Definition: thread.h:42
char msg_type[__INTERFACE_MESSAGE_TYPE_SIZE]
message type
Definition: messages.h:166
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
virtual Interface * open_for_writing(const char *interface_type, const char *identifier)=0
Open interface for writing.
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
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:782
virtual void client_disconnected(unsigned int clid)
Client disconnected.
Definition: handler.cpp:405
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:178
Fawkes Network Hub.
Definition: hub.h:33
virtual void client_connected(unsigned int clid)
Client connected.
Definition: handler.cpp:395
Interface information list.
unsigned int datasize() const
Get data size.
Definition: interface.cpp:529
void wakeup()
Wake up thread.
Definition: thread.cpp:979
char id_pattern[__INTERFACE_ID_SIZE]
ID pattern.
Definition: messages.h:74
Base class for exceptions in Fawkes.
Definition: exception.h:36
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
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:133
void append_interface(const char *type, const char *id, const unsigned char *hash, unsigned int serial, bool has_writer, unsigned int num_readers)
Append interface info.
void ref()
Increment reference count.
Definition: refcount.cpp:70
The hashes of the interfaces do not match.
Definition: messages.h:60
uint32_t data_size
data for message
Definition: messages.h:169
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:160
Interface data message.
Definition: messages.h:154
~BlackBoardNetworkHandler()
Destructor.
Definition: handler.cpp:71
Interface message.
Definition: messages.h:164
Unknown error occured.
Definition: messages.h:58
void pop_locked()
Pop element from queue with lock protection.
Definition: lock_queue.h:149
uint32_t serial
interface instance serial
Definition: messages.h:165
MT * msg() const
Get correctly casted payload.
Definition: message.h:115
char id[__INTERFACE_ID_SIZE]
interface instance ID
Definition: messages.h:80
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:155
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:112
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)=0
Open interface for reading.
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:111
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:435
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:425
virtual void remove_handler(FawkesNetworkHandler *handler)=0
Remove a message handler.
The BlackBoard abstract class.
Definition: blackboard.h:49
Thrown if a writer is already active on an interface that writing has been requested for...
Definition: exceptions.h:121
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:156
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:217
unsigned int clid() const
Get client ID.
Definition: message.cpp:281
uint32_t hops
number of hops this message already passed
Definition: messages.h:168
virtual void handle_network_message(FawkesNetworkMessage *msg)
Handle network message.
Definition: handler.cpp:383
virtual void close(Interface *interface)=0
Close interface.