Fawkes API  Fawkes Development Version
handler.cpp
00001 
00002 /***************************************************************************
00003  *  network_handler.cpp - BlackBoard Network Handler
00004  *
00005  *  Generated: Sat Mar 01 16:00:34 2008
00006  *  Copyright  2006-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <blackboard/net/handler.h>
00025 #include <blackboard/net/messages.h>
00026 #include <blackboard/net/ilist_content.h>
00027 #include <blackboard/blackboard.h>
00028 #include <blackboard/exceptions.h>
00029 #include <blackboard/net/interface_listener.h>
00030 #include <blackboard/net/interface_observer.h>
00031 
00032 #include <interface/interface.h>
00033 #include <interface/interface_info.h>
00034 
00035 #include <logging/liblogger.h>
00036 #include <netcomm/fawkes/component_ids.h>
00037 #include <netcomm/fawkes/hub.h>
00038 
00039 #include <cstdlib>
00040 #include <cstring>
00041 #include <arpa/inet.h>
00042 
00043 namespace fawkes {
00044 
00045 /** @class BlackBoardNetworkHandler <blackboard/net/handler.h>
00046  * BlackBoard Network Handler.
00047  * This class provides a network handler that can be registered with the
00048  * FawkesServerThread to handle client requests to a BlackBoard instance.
00049  *
00050  * @author Tim Niemueller
00051  */
00052 
00053 /** Constructor.
00054  * @param blackboard BlackBoard instance to provide network access to
00055  * @param hub Fawkes network hub
00056  */
00057 BlackBoardNetworkHandler::BlackBoardNetworkHandler(BlackBoard *blackboard,
00058                                                    FawkesNetworkHub *hub)
00059   : Thread("BlackBoardNetworkHandler", Thread::OPMODE_WAITFORWAKEUP),
00060     FawkesNetworkHandler(FAWKES_CID_BLACKBOARD)
00061 {
00062   __bb   = blackboard;
00063   __nhub = hub;
00064   __nhub->add_handler(this);
00065 
00066   __observer = new BlackBoardNetHandlerInterfaceObserver(blackboard, hub);
00067 }
00068 
00069 
00070 /** Destructor. */
00071 BlackBoardNetworkHandler::~BlackBoardNetworkHandler()
00072 {
00073   delete __observer;
00074   __nhub->remove_handler(this);
00075   __inbound_queue.clear();
00076   // close all open interfaces
00077   for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
00078     delete __lit->second;
00079   }
00080   for (__iit = __interfaces.begin(); __iit != __interfaces.end(); ++__iit) {
00081     __bb->close(__iit->second);
00082   }
00083 }
00084 
00085 
00086 /** Process all network messages that have been received. */
00087 void
00088 BlackBoardNetworkHandler::loop()
00089 {
00090   while ( ! __inbound_queue.empty() ) {
00091     FawkesNetworkMessage *msg = __inbound_queue.front();
00092 
00093     // used often and thus queried _once_
00094     unsigned int clid = msg->clid();
00095 
00096     switch (msg->msgid()) {
00097     case MSG_BB_LIST_ALL:
00098       {
00099         BlackBoardInterfaceListContent *ilist = new BlackBoardInterfaceListContent();
00100         InterfaceInfoList *infl = __bb->list_all();
00101         
00102         for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i) {
00103           ilist->append_interface(*i);
00104         }
00105 
00106         try {
00107           __nhub->send(clid, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_LIST, ilist);
00108         } catch (Exception &e) {
00109           LibLogger::log_error("BlackBoardNetworkHandler", "Failed to sent interface "
00110                                "list to %u, exception follows", clid);
00111           LibLogger::log_error("BlackBoardNetworkHandler", e);
00112         }
00113         delete infl;
00114       }
00115       break;
00116 
00117     case MSG_BB_LIST:
00118       {
00119         BlackBoardInterfaceListContent *ilist =
00120           new BlackBoardInterfaceListContent();
00121 
00122         bb_ilistreq_msg_t *lrm = msg->msg<bb_ilistreq_msg_t>();
00123 
00124         char type_pattern[__INTERFACE_TYPE_SIZE + 1];
00125         char id_pattern[__INTERFACE_ID_SIZE + 1];
00126         type_pattern[__INTERFACE_TYPE_SIZE] = 0;
00127         id_pattern[__INTERFACE_ID_SIZE] = 0;
00128         strncpy(type_pattern, lrm->type_pattern, __INTERFACE_TYPE_SIZE);
00129         strncpy(id_pattern, lrm->id_pattern, __INTERFACE_ID_SIZE);
00130 
00131         InterfaceInfoList *infl = __bb->list(type_pattern, id_pattern);
00132         for (InterfaceInfoList::iterator i = infl->begin(); i != infl->end(); ++i)
00133         {
00134           ilist->append_interface(*i);
00135         }
00136 
00137         try {
00138           __nhub->send(clid, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_LIST, ilist);
00139         } catch (Exception &e) {
00140           LibLogger::log_error("BlackBoardNetworkHandler", "Failed to sent "
00141                                "interface list to %u, exception follows", clid);
00142           LibLogger::log_error("BlackBoardNetworkHandler", e);
00143         }
00144         delete infl;
00145       }
00146       break;
00147 
00148     case MSG_BB_OPEN_FOR_READING:
00149     case MSG_BB_OPEN_FOR_WRITING:
00150       {
00151         bb_iopen_msg_t *om = msg->msg<bb_iopen_msg_t>();
00152 
00153         char type[__INTERFACE_TYPE_SIZE + 1];
00154         char id[__INTERFACE_ID_SIZE + 1];
00155         type[__INTERFACE_TYPE_SIZE] = 0;
00156         id[__INTERFACE_ID_SIZE] = 0;
00157         strncpy(type, om->type, __INTERFACE_TYPE_SIZE);
00158         strncpy(id, om->id, __INTERFACE_ID_SIZE);
00159 
00160         LibLogger::log_debug("BlackBoardNetworkHandler", "Remote opens interface %s::%s",
00161                              type, id);
00162         try {
00163           Interface *iface;
00164 
00165           if ( msg->msgid() == MSG_BB_OPEN_FOR_READING ) {
00166             iface = __bb->open_for_reading(type, id);
00167           } else {
00168             iface = __bb->open_for_writing(type, id);
00169           }
00170           if ( memcmp(iface->hash(), om->hash, __INTERFACE_HASH_SIZE) != 0 ) {
00171             LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed, "
00172                                 "hash mismatch", type, id);
00173             send_openfailure(clid, BB_ERR_HASH_MISMATCH);
00174           } else {
00175             __interfaces[iface->serial()] = iface;
00176             __client_interfaces[clid].push_back(iface);
00177             __serial_to_clid[iface->serial()] = clid;
00178             __listeners[iface->serial()] = new BlackBoardNetHandlerInterfaceListener(__bb,
00179                                                                                      iface,
00180                                                                                      __nhub,
00181                                                                                      clid);
00182             send_opensuccess(clid, iface);
00183           }
00184         } catch (BlackBoardInterfaceNotFoundException &nfe) {
00185           LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed, "
00186                               "interface class not found", type, id);
00187           send_openfailure(clid, BB_ERR_UNKNOWN_TYPE);
00188         } catch (BlackBoardWriterActiveException &wae) {
00189           LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed, "
00190                               "writer already exists", type, id);
00191           send_openfailure(clid, BB_ERR_WRITER_EXISTS);
00192         } catch (Exception &e) {
00193           LibLogger::log_warn("BlackBoardNetworkHandler", "Opening interface %s::%s failed",
00194                               type, id);
00195           LibLogger::log_warn("BlackBoardNetworkHandler", e);
00196           send_openfailure(clid, BB_ERR_UNKNOWN_ERR);
00197         }
00198         
00199         //LibLogger::log_debug("BBNH", "interfaces: %zu  s2c: %zu  ci: %zu",
00200         //                   __interfaces.size(), __serial_to_clid.size(),
00201         //                   __client_interfaces.size());
00202 
00203       }
00204       break;
00205 
00206     case MSG_BB_CLOSE:
00207       {
00208         bb_iserial_msg_t *sm = msg->msg<bb_iserial_msg_t>();
00209         unsigned int sm_serial = ntohl(sm->serial);
00210         if ( __interfaces.find(sm_serial) != __interfaces.end() ) {
00211           bool close = false;
00212           __client_interfaces.lock();
00213           if ( __client_interfaces.find(clid) != __client_interfaces.end()) {
00214             // this client has interfaces, check if this one as well
00215             for ( __ciit = __client_interfaces[clid].begin(); __ciit != __client_interfaces[clid].end(); ++__ciit) {
00216               if ( (*__ciit)->serial() == sm_serial ) {
00217                 close = true;
00218                 __serial_to_clid.erase(sm_serial);
00219                 __client_interfaces[clid].erase(__ciit);
00220                 if ( __client_interfaces[clid].empty() ) {
00221                   __client_interfaces.erase(clid);
00222                 }
00223                 break;
00224               }
00225             }
00226           }
00227           __client_interfaces.unlock();
00228 
00229           if ( close ) {
00230             __interfaces.lock();
00231             LibLogger::log_debug("BlackBoardNetworkHandler", "Remote %u closing interface %s",
00232                                  clid, __interfaces[sm_serial]->uid());
00233             delete __listeners[sm_serial];
00234             __listeners.erase(sm_serial);
00235             __bb->close(__interfaces[sm_serial]);
00236             __interfaces.erase(sm_serial);
00237             __interfaces.unlock();
00238           } else {
00239             LibLogger::log_warn("BlackBoardNetworkHandler", "Client %u tried to close "
00240                                 "interface with serial %u, but opened by other client",
00241                                 clid, sm_serial);
00242           }
00243         } else {
00244           LibLogger::log_warn("BlackBoardNetworkHandler", "Client %u tried to close "
00245                               "interface with serial %u which has not been opened",
00246                               clid, sm_serial);
00247         }
00248 
00249         //LibLogger::log_debug("BBNH", "C: interfaces: %zu  s2c: %zu  ci: %zu",
00250         //                   __interfaces.size(), __serial_to_clid.size(),
00251         //                   __client_interfaces.size());
00252       }
00253       break;
00254 
00255     case MSG_BB_DATA_CHANGED:
00256       {
00257         void *payload = msg->payload();
00258         bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
00259         unsigned int dm_serial = ntohl(dm->serial);
00260         if ( __interfaces.find(dm_serial) != __interfaces.end() ) {
00261         
00262           if ( ntohl(dm->data_size) != __interfaces[dm_serial]->datasize() ) {
00263             LibLogger::log_error("BlackBoardNetworkHandler", "DATA_CHANGED: Data size mismatch, "
00264                                  "expected %zu, but got %zu, ignoring.",
00265                                  __interfaces[dm_serial]->datasize(), ntohl(dm->data_size));
00266           } else {
00267             __interfaces[dm_serial]->set_from_chunk((char *)payload + sizeof(bb_idata_msg_t));
00268             __interfaces[dm_serial]->write();
00269           }
00270         } else {
00271           LibLogger::log_error("BlackBoardNetworkHandler", "DATA_CHANGED: Interface with "
00272                                "serial %u not found, ignoring.", dm_serial);
00273         }
00274       }
00275       break;
00276 
00277     case MSG_BB_INTERFACE_MESSAGE:
00278       {
00279         void *payload = msg->payload();
00280         bb_imessage_msg_t *mm = (bb_imessage_msg_t *)payload;
00281         unsigned int mm_serial = ntohl(mm->serial);
00282         if ( __interfaces.find(mm_serial) != __interfaces.end() ) {
00283 
00284           if ( ! __interfaces[mm_serial]->is_writer() ) {
00285             try {
00286               Message *ifm = __interfaces[mm_serial]->create_message(mm->msg_type);
00287               ifm->set_id(ntohl(mm->msgid));
00288               ifm->set_hops(ntohl(mm->hops));
00289 
00290               if ( ntohl(mm->data_size) != ifm->datasize() ) {
00291                 LibLogger::log_error("BlackBoardNetworkHandler", "MESSAGE: Data size mismatch, "
00292                                      "expected %zu, but got %zu, ignoring.",
00293                                      ifm->datasize(), ntohl(mm->data_size));
00294               } else {
00295                 ifm->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
00296 
00297                 __interfaces[mm_serial]->msgq_enqueue(ifm);
00298 
00299               }
00300             } catch (Exception &e) {
00301               LibLogger::log_error("BlackBoardNetworkHandler", "MESSAGE: Could not create "
00302                                    "interface message, ignoring.");
00303               LibLogger::log_error("BlackBoardNetworkHandler", e);
00304             }
00305           } else {
00306             LibLogger::log_error("BlackBoardNetworkHandler", "MESSAGE: Received message "
00307                                  "notification, but for a writing instance, ignoring.");
00308           }
00309         } else {
00310           LibLogger::log_error("BlackBoardNetworkHandler", "DATA_CHANGED: Interface with "
00311                                "serial %u not found, ignoring.", mm_serial);
00312         }
00313       }
00314       break;
00315 
00316     default:
00317       LibLogger::log_warn("BlackBoardNetworkHandler", "Unknown message of type %u "
00318                           "received", msg->msgid());
00319       break;
00320     }
00321 
00322     msg->unref();
00323     __inbound_queue.pop_locked();
00324   }
00325 }
00326 
00327 
00328 void
00329 BlackBoardNetworkHandler::send_opensuccess(unsigned int clid, Interface *interface)
00330 {
00331   void *payload = calloc(1, sizeof(bb_iopensucc_msg_t) + interface->datasize());
00332   bb_iopensucc_msg_t *osm = (bb_iopensucc_msg_t *)payload;
00333   osm->serial = htonl(interface->serial());
00334   osm->has_writer = interface->has_writer() ? 1 : 0;
00335   osm->num_readers = htonl(interface->num_readers());
00336   osm->data_size = htonl(interface->datasize());
00337 
00338   if ( ! interface->is_writer() ) {
00339     interface->read();
00340   }
00341 
00342   memcpy((char *)payload + sizeof(bb_iopensucc_msg_t),
00343          interface->datachunk(), interface->datasize());
00344   
00345   FawkesNetworkMessage *omsg = new FawkesNetworkMessage(clid, FAWKES_CID_BLACKBOARD,
00346                                                         MSG_BB_OPEN_SUCCESS, payload,
00347                                                         sizeof(bb_iopensucc_msg_t) +
00348                                                         interface->datasize());
00349   try {
00350     __nhub->send(omsg);
00351   } catch (Exception &e) {
00352     LibLogger::log_error("BlackBoardNetworkHandler", "Failed to sent interface "
00353                          "open success to %u, exception follows", clid);
00354     LibLogger::log_error("BlackBoardNetworkHandler", e);
00355   }
00356 }
00357 
00358 
00359 void
00360 BlackBoardNetworkHandler::send_openfailure(unsigned int clid, unsigned int errno)
00361 {
00362   bb_iopenfail_msg_t *ofm = (bb_iopenfail_msg_t *)malloc(sizeof(bb_iopenfail_msg_t));
00363   ofm->errno = htonl(errno);
00364 
00365   FawkesNetworkMessage *omsg = new FawkesNetworkMessage(clid, FAWKES_CID_BLACKBOARD,
00366                                                         MSG_BB_OPEN_FAILURE, ofm,
00367                                                         sizeof(bb_iopenfail_msg_t));
00368   try {
00369     __nhub->send(omsg);
00370   } catch (Exception &e) {
00371     LibLogger::log_error("BlackBoardNetworkHandler", "Failed to sent interface "
00372                          "open failure to %u, exception follows", clid);
00373     LibLogger::log_error("BlackBoardNetworkHandler", e);
00374   }
00375 }
00376 
00377 
00378 /** Handle network message.
00379  * The message is put into the inbound queue and processed in processAfterLoop().
00380  * @param msg message
00381  */
00382 void
00383 BlackBoardNetworkHandler::handle_network_message(FawkesNetworkMessage *msg)
00384 {
00385   msg->ref();
00386   __inbound_queue.push_locked(msg);
00387   wakeup();
00388 }
00389 
00390 
00391 /** Client connected. Ignored.
00392  * @param clid client ID
00393  */
00394 void
00395 BlackBoardNetworkHandler::client_connected(unsigned int clid)
00396 {
00397 }
00398 
00399 
00400 /** Client disconnected.
00401  * If the client had opened any interfaces these are closed.
00402  * @param clid client ID
00403  */
00404 void
00405 BlackBoardNetworkHandler::client_disconnected(unsigned int clid)
00406 {
00407   // close any interface that this client had opened
00408   __client_interfaces.lock();
00409   if ( __client_interfaces.find(clid) != __client_interfaces.end() ) {
00410     // Close all interfaces
00411     for ( __ciit = __client_interfaces[clid].begin(); __ciit != __client_interfaces[clid].end(); ++__ciit) {
00412       LibLogger::log_debug("BlackBoardNetworkHandler", "Closing interface %s::%s of remote "
00413                            "%u (client disconnected)",
00414                            (*__ciit)->type(), (*__ciit)->id(), clid);
00415 
00416       unsigned int serial = (*__ciit)->serial();
00417       __serial_to_clid.erase(serial);
00418       __interfaces.erase_locked(serial);
00419       delete __listeners[serial];
00420       __listeners.erase(serial);
00421       __bb->close(*__ciit);
00422     }
00423     __client_interfaces.erase(clid);
00424   }
00425   __client_interfaces.unlock();
00426 }
00427 
00428 } // end namespace fawkes