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