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 
41 namespace 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. */
82 void
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 
115  bb_ilistreq_msg_t *lrm = msg->msg<bb_ilistreq_msg_t>();
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  }
176  } catch (BlackBoardInterfaceNotFoundException &nfe) {
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: {
206  bb_iserial_msg_t *sm = msg->msg<bb_iserial_msg_t>();
207  unsigned int sm_serial = ntohl(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 %u, but opened by other client",
243  clid,
244  sm_serial);
245  }
246  } else {
247  LibLogger::log_warn("BlackBoardNetworkHandler",
248  "Client %u tried to close "
249  "interface with serial %u which has not been opened",
250  clid,
251  sm_serial);
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  void * payload = msg->payload();
261  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
262  unsigned int dm_serial = ntohl(dm->serial);
263  if (interfaces_.find(dm_serial) != interfaces_.end()) {
264  if (ntohl(dm->data_size) != interfaces_[dm_serial]->datasize()) {
265  LibLogger::log_error("BlackBoardNetworkHandler",
266  "DATA_CHANGED: Data size mismatch, "
267  "expected %zu, but got %zu, ignoring.",
268  interfaces_[dm_serial]->datasize(),
269  ntohl(dm->data_size));
270  } else {
271  interfaces_[dm_serial]->set_from_chunk((char *)payload + sizeof(bb_idata_msg_t));
272  interfaces_[dm_serial]->write();
273  }
274  } else {
275  LibLogger::log_error("BlackBoardNetworkHandler",
276  "DATA_CHANGED: Interface with "
277  "serial %u not found, ignoring.",
278  dm_serial);
279  }
280  } break;
281 
282  case MSG_BB_INTERFACE_MESSAGE: {
283  void * payload = msg->payload();
284  bb_imessage_msg_t *mm = (bb_imessage_msg_t *)payload;
285  unsigned int mm_serial = ntohl(mm->serial);
286  if (interfaces_.find(mm_serial) != interfaces_.end()) {
287  if (!interfaces_[mm_serial]->is_writer()) {
288  try {
289  Message *ifm = interfaces_[mm_serial]->create_message(mm->msg_type);
290  ifm->set_id(ntohl(mm->msgid));
291  ifm->set_hops(ntohl(mm->hops));
292 
293  if (ntohl(mm->data_size) != ifm->datasize()) {
294  LibLogger::log_error("BlackBoardNetworkHandler",
295  "MESSAGE: Data size mismatch, "
296  "expected %zu, but got %zu, ignoring.",
297  ifm->datasize(),
298  ntohl(mm->data_size));
299  } else {
300  ifm->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
301 
302  interfaces_[mm_serial]->msgq_enqueue(ifm);
303  }
304  } catch (Exception &e) {
305  LibLogger::log_error("BlackBoardNetworkHandler",
306  "MESSAGE: Could not create "
307  "interface message, ignoring.");
308  LibLogger::log_error("BlackBoardNetworkHandler", e);
309  }
310  } else {
311  LibLogger::log_error("BlackBoardNetworkHandler",
312  "MESSAGE: Received message "
313  "notification, but for a writing instance, ignoring.");
314  }
315  } else {
316  LibLogger::log_error("BlackBoardNetworkHandler",
317  "DATA_CHANGED: Interface with "
318  "serial %u not found, ignoring.",
319  mm_serial);
320  }
321  } break;
322 
323  default:
324  LibLogger::log_warn("BlackBoardNetworkHandler",
325  "Unknown message of type %u "
326  "received",
327  msg->msgid());
328  break;
329  }
330 
331  msg->unref();
332  inbound_queue_.pop_locked();
333  }
334 }
335 
336 void
337 BlackBoardNetworkHandler::send_opensuccess(unsigned int clid, Interface *interface)
338 {
339  void * payload = calloc(1, sizeof(bb_iopensucc_msg_t) + interface->datasize());
340  bb_iopensucc_msg_t *osm = (bb_iopensucc_msg_t *)payload;
341  osm->serial = htonl(interface->serial());
342  osm->writer_readers = htonl(interface->num_readers());
343  if (interface->has_writer()) {
344  osm->writer_readers |= htonl(0x80000000);
345  } else {
346  osm->writer_readers &= htonl(0x7FFFFFFF);
347  }
348  osm->data_size = htonl(interface->datasize());
349 
350  if (!interface->is_writer()) {
351  interface->read();
352  }
353 
354  memcpy((char *)payload + sizeof(bb_iopensucc_msg_t),
355  interface->datachunk(),
356  interface->datasize());
357 
358  FawkesNetworkMessage *omsg =
359  new FawkesNetworkMessage(clid,
360  FAWKES_CID_BLACKBOARD,
361  MSG_BB_OPEN_SUCCESS,
362  payload,
363  sizeof(bb_iopensucc_msg_t) + interface->datasize());
364  try {
365  nhub_->send(omsg);
366  } catch (Exception &e) {
367  LibLogger::log_error("BlackBoardNetworkHandler",
368  "Failed to send interface "
369  "open success to %u, exception follows",
370  clid);
371  LibLogger::log_error("BlackBoardNetworkHandler", e);
372  }
373 }
374 
375 void
376 BlackBoardNetworkHandler::send_openfailure(unsigned int clid, unsigned int error_code)
377 {
378  bb_iopenfail_msg_t *ofm = (bb_iopenfail_msg_t *)malloc(sizeof(bb_iopenfail_msg_t));
379  ofm->error_code = htonl(error_code);
380 
381  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(
382  clid, FAWKES_CID_BLACKBOARD, MSG_BB_OPEN_FAILURE, ofm, sizeof(bb_iopenfail_msg_t));
383  try {
384  nhub_->send(omsg);
385  } catch (Exception &e) {
386  LibLogger::log_error("BlackBoardNetworkHandler",
387  "Failed to send interface "
388  "open failure to %u, exception follows",
389  clid);
390  LibLogger::log_error("BlackBoardNetworkHandler", e);
391  }
392 }
393 
394 /** Handle network message.
395  * The message is put into the inbound queue and processed in processAfterLoop().
396  * @param msg message
397  */
398 void
400 {
401  msg->ref();
402  inbound_queue_.push_locked(msg);
403  wakeup();
404 }
405 
406 /** Client connected. Ignored.
407  * @param clid client ID
408  */
409 void
411 {
412 }
413 
414 /** Client disconnected.
415  * If the client had opened any interfaces these are closed.
416  * @param clid client ID
417  */
418 void
420 {
421  // close any interface that this client had opened
422  client_interfaces_.lock();
423  if (client_interfaces_.find(clid) != client_interfaces_.end()) {
424  // Close all interfaces
425  for (ciit_ = client_interfaces_[clid].begin(); ciit_ != client_interfaces_[clid].end();
426  ++ciit_) {
427  LibLogger::log_debug("BlackBoardNetworkHandler",
428  "Closing interface %s::%s of remote "
429  "%u (client disconnected)",
430  (*ciit_)->type(),
431  (*ciit_)->id(),
432  clid);
433 
434  unsigned int serial = (*ciit_)->serial();
435  serial_to_clid_.erase(serial);
436  interfaces_.erase_locked(serial);
437  delete listeners_[serial];
438  listeners_.erase(serial);
439  bb_->close(*ciit_);
440  }
441  client_interfaces_.erase(clid);
442  }
443  client_interfaces_.unlock();
444 }
445 
446 } // 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:410
virtual void client_disconnected(unsigned int clid)
Client disconnected.
Definition: handler.cpp:419
~BlackBoardNetworkHandler()
Destructor.
Definition: handler.cpp:67
virtual void handle_network_message(FawkesNetworkMessage *msg)
Handle network message.
Definition: handler.cpp:399
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
MT * msg() const
Get correctly casted payload.
Definition: message.h:120
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:294
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:79
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:429
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:438
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:298
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:686
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:845
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
unsigned int datasize() const
Get data size.
Definition: interface.cpp:531
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:817
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:45
unsigned int datasize() const
Get size of data.
Definition: message.cpp:270
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:281
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:198
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:207
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
Fawkes library namespace.
@ BB_ERR_UNKNOWN_ERR
Unknown error occured.
Definition: messages.h:59
@ 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:63
@ BB_ERR_HASH_MISMATCH
The hashes of the interfaces do not match.
Definition: messages.h:61
@ BB_ERR_UNKNOWN_TYPE
Requested interface type is unknown.
Definition: messages.h:60
Interface data message.
Definition: messages.h:164
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:165
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:166
Message to request constrained interface list.
Definition: messages.h:75
char type_pattern[INTERFACE_TYPE_SIZE_]
type pattern
Definition: messages.h:76
char id_pattern[INTERFACE_ID_SIZE_]
ID pattern.
Definition: messages.h:77
Interface message.
Definition: messages.h:174
uint32_t msgid
message ID
Definition: messages.h:177
uint32_t serial
interface instance serial
Definition: messages.h:175
uint32_t data_size
data for message
Definition: messages.h:179
char msg_type[INTERFACE_MESSAGE_TYPE_SIZE_]
message type
Definition: messages.h:176
uint32_t hops
number of hops this message already passed
Definition: messages.h:178
Message to identify an interface on open.
Definition: messages.h:82
char id[INTERFACE_ID_SIZE_]
interface instance ID
Definition: messages.h:84
unsigned char hash[INTERFACE_HASH_SIZE_]
interface version hash
Definition: messages.h:85
char type[INTERFACE_TYPE_SIZE_]
interface type name
Definition: messages.h:83
Interface open success The serial denotes a unique instance of an interface within the (remote) Black...
Definition: messages.h:141
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:142
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:147
uint32_t writer_readers
combined writer reader information.
Definition: messages.h:143
Message to identify an interface instance.
Definition: messages.h:119
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:120