Fawkes API
Fawkes Development Version
|
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