Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * handler.cpp - Fawkes plugin network handler 00004 * 00005 * Created: Thu Feb 12 10:36:15 2009 00006 * Copyright 2006-2009 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 <plugin/manager.h> 00025 #include <plugin/net/handler.h> 00026 #include <plugin/net/messages.h> 00027 #include <plugin/net/list_message.h> 00028 00029 #include <logging/liblogger.h> 00030 00031 #include <netcomm/fawkes/component_ids.h> 00032 #include <netcomm/fawkes/hub.h> 00033 00034 #include <algorithm> 00035 #include <cstring> 00036 #include <cstdlib> 00037 #include <cerrno> 00038 00039 namespace fawkes { 00040 #if 0 /* just to make Emacs auto-indent happy */ 00041 } 00042 #endif 00043 00044 /** @class PluginNetworkHandler <plugin/net/handler.h> 00045 * Fawkes Plugin Network Handler. 00046 * This network handler handles requests of plugin lists and for loading/unloading 00047 * plugins received over the network. 00048 * 00049 * @author Tim Niemueller 00050 */ 00051 00052 /* IMPORANT IMPLEMENTER'S NOTE 00053 * 00054 * If you are going to work on this code mind the following: it is assumed 00055 * that only loop() will pop messages from the inbound queue. Thus the inbound 00056 * queue is only locked for this pop operation, not for the whole access time. 00057 * This is true as long as messages are only appended from the outside! 00058 * This is necessary to ensure that handle_network_message() will not hang 00059 * waiting for the queue lock. 00060 */ 00061 00062 /** Constructor. 00063 * @param manager plugin manager for the actual work 00064 * @param hub Fawkes network hub 00065 */ 00066 PluginNetworkHandler::PluginNetworkHandler(PluginManager *manager, 00067 FawkesNetworkHub *hub) 00068 : Thread("PluginNetworkHandler", Thread::OPMODE_WAITFORWAKEUP), 00069 FawkesNetworkHandler(FAWKES_CID_PLUGINMANAGER) 00070 { 00071 __manager = manager; 00072 __hub = hub; 00073 00074 __manager->add_listener(this); 00075 __hub->add_handler(this); 00076 } 00077 00078 00079 /** Destructor. */ 00080 PluginNetworkHandler::~PluginNetworkHandler() 00081 { 00082 __hub->remove_handler(this); 00083 __manager->remove_listener(this); 00084 } 00085 00086 00087 /** Generate list of all available plugins. 00088 * All files with the extension .so in the PLUGINDIR are returned. 00089 * @param num_plugins pointer to an unsigned int where the number 00090 * of all plugins is stored 00091 * @param plugin_list pointer to the string array where the list of 00092 * all plugins is stored. Memory is allocated at this address and 00093 * has to be freed by the caller! 00094 */ 00095 PluginListMessage * 00096 PluginNetworkHandler::list_avail() 00097 { 00098 PluginListMessage *m = new PluginListMessage(); 00099 00100 std::list<std::pair<std::string, std::string> > available_plugins; 00101 available_plugins = __manager->get_available_plugins(); 00102 00103 std::list<std::pair<std::string, std::string> >::iterator i; 00104 for (i = available_plugins.begin(); i != available_plugins.end(); ++i) { 00105 m->append(i->first.c_str(), i->first.length()); 00106 m->append(i->second.c_str(), i->second.length()); 00107 } 00108 return m; 00109 } 00110 00111 PluginListMessage * 00112 PluginNetworkHandler::list_loaded() 00113 { 00114 PluginListMessage *m = new PluginListMessage(); 00115 00116 std::list<std::string> loaded_plugins; 00117 loaded_plugins = __manager->get_loaded_plugins(); 00118 00119 std::list<std::string>::iterator i; 00120 for (i = loaded_plugins.begin(); i != loaded_plugins.end(); ++i) { 00121 m->append(i->c_str(), i->length()); 00122 } 00123 00124 return m; 00125 } 00126 00127 00128 void 00129 PluginNetworkHandler::send_load_failure(const char *plugin_name, 00130 unsigned int client_id) 00131 { 00132 try { 00133 plugin_load_failed_msg_t *r = (plugin_load_failed_msg_t *)calloc(1, sizeof(plugin_load_failed_msg_t)); 00134 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH); 00135 __hub->send(client_id, FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOAD_FAILED, 00136 r, sizeof(plugin_load_failed_msg_t)); 00137 } catch (Exception &e) { 00138 LibLogger::log_warn("PluginNetworkHandler", "Failed to send load failure, exception follows"); 00139 LibLogger::log_warn("PluginNetworkHandler", e); 00140 } 00141 } 00142 00143 00144 void 00145 PluginNetworkHandler::send_load_success(const char *plugin_name, unsigned int client_id) 00146 { 00147 try { 00148 plugin_loaded_msg_t *r = (plugin_loaded_msg_t *)calloc(1, sizeof(plugin_loaded_msg_t)); 00149 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH); 00150 __hub->send(client_id, FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOADED, 00151 r, sizeof(plugin_loaded_msg_t)); 00152 } catch (Exception &e) { 00153 LibLogger::log_warn("PluginNetworkHandler", "Failed to send load success, exception follows"); 00154 LibLogger::log_warn("PluginNetworkHandler", e); 00155 } 00156 } 00157 00158 00159 void 00160 PluginNetworkHandler::send_unloaded(const char *plugin_name) 00161 { 00162 __subscribers.lock(); 00163 try { 00164 for (__ssit = __subscribers.begin(); __ssit != __subscribers.end(); ++__ssit) { 00165 send_unload_success(plugin_name, *__ssit); 00166 } 00167 } catch (Exception &e) { 00168 LibLogger::log_warn("PluginNetworkHandler", "Failed to send unloaded, exception follows"); 00169 LibLogger::log_warn("PluginNetworkHandler", e); 00170 } 00171 __subscribers.unlock(); 00172 } 00173 00174 00175 void 00176 PluginNetworkHandler::send_loaded(const char *plugin_name) 00177 { 00178 __subscribers.lock(); 00179 try { 00180 for (__ssit = __subscribers.begin(); __ssit != __subscribers.end(); ++__ssit) { 00181 send_load_success(plugin_name, *__ssit); 00182 } 00183 } catch (Exception &e) { 00184 LibLogger::log_warn("PluginNetworkHandler", "Failed to send loaded, exception follows"); 00185 LibLogger::log_warn("PluginNetworkHandler", e); 00186 } 00187 __subscribers.unlock(); 00188 } 00189 00190 00191 void 00192 PluginNetworkHandler::send_unload_failure(const char *plugin_name, 00193 unsigned int client_id) 00194 { 00195 try { 00196 plugin_unload_failed_msg_t *r = (plugin_unload_failed_msg_t *)calloc(1, sizeof(plugin_unload_failed_msg_t)); 00197 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH); 00198 __hub->send(client_id, FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_UNLOAD_FAILED, 00199 r, sizeof(plugin_unload_failed_msg_t)); 00200 } catch (Exception &e) { 00201 LibLogger::log_warn("PluginNetworkHandler", "Failed to send unload failure, exception follows"); 00202 LibLogger::log_warn("PluginNetworkHandler", e); 00203 } 00204 } 00205 00206 00207 void 00208 PluginNetworkHandler::send_unload_success(const char *plugin_name, unsigned int client_id) 00209 { 00210 try { 00211 plugin_unloaded_msg_t *r = (plugin_unloaded_msg_t *)calloc(1, sizeof(plugin_unloaded_msg_t)); 00212 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH); 00213 __hub->send(client_id, FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_UNLOADED, 00214 r, sizeof(plugin_unloaded_msg_t)); 00215 } catch (Exception &e) { 00216 LibLogger::log_warn("PluginNetworkHandler", "Failed to send unload success, exception follows"); 00217 LibLogger::log_warn("PluginNetworkHandler", e); 00218 } 00219 } 00220 00221 00222 00223 /** Load plugin. 00224 * The loading is interrupted if any of the plugins does not load properly. 00225 * The already loaded plugins are *not* unloaded, but kept. 00226 * @param plugin_list string containing a comma-separated list of plugins 00227 * to load. The plugin list can contain meta plugins. 00228 * @param clid Fawkes network client ID of client that gets a success message 00229 * with the exact string that was put into 00230 */ 00231 void 00232 PluginNetworkHandler::load(const char *plugin_list, unsigned int clid) 00233 { 00234 __manager->lock(); 00235 try { 00236 __manager->load(plugin_list); 00237 send_load_success(plugin_list, clid); 00238 } catch (Exception &e) { 00239 LibLogger::log_error("PluginNetworkHandler", "Failed to load plugin %s", plugin_list); 00240 LibLogger::log_error("PluginNetworkHandler", e); 00241 send_load_failure(plugin_list, clid); 00242 } 00243 __manager->unlock(); 00244 } 00245 00246 00247 /** Unload plugin. 00248 * Note that this method does not allow to pass a list of plugins, but it will 00249 * only accept a single plugin at a time. 00250 * @param plugin_name plugin to unload, can be a meta plugin. 00251 * @param clid Fawkes network client ID of client that gets a success message 00252 * with the exact string that was put into 00253 */ 00254 void 00255 PluginNetworkHandler::unload(const char *plugin_name, unsigned int clid) 00256 { 00257 __manager->lock(); 00258 try { 00259 __manager->unload(plugin_name); 00260 send_unload_success(plugin_name, clid); 00261 } catch (Exception &e) { 00262 LibLogger::log_error("PluginNetworkHandler", "Failed to unload plugin %s", plugin_name); 00263 LibLogger::log_error("PluginNetworkHandler", e); 00264 send_unload_failure(plugin_name, clid); 00265 } 00266 __manager->unlock(); 00267 } 00268 00269 00270 /** Process all network messages that have been received. 00271 */ 00272 void 00273 PluginNetworkHandler::loop() 00274 { 00275 while ( ! __inbound_queue.empty() ) { 00276 FawkesNetworkMessage *msg = __inbound_queue.front(); 00277 00278 switch (msg->msgid()) { 00279 case MSG_PLUGIN_LOAD: 00280 if ( msg->payload_size() != sizeof(plugin_load_msg_t) ) { 00281 LibLogger::log_error("PluginNetworkHandler", "Invalid load message size"); 00282 } else { 00283 plugin_load_msg_t *m = (plugin_load_msg_t *)msg->payload(); 00284 char name[PLUGIN_MSG_NAME_LENGTH + 1]; 00285 name[PLUGIN_MSG_NAME_LENGTH] = 0; 00286 strncpy(name, m->name, PLUGIN_MSG_NAME_LENGTH); 00287 00288 if ( __manager->is_loaded(name) ) { 00289 LibLogger::log_info("PluginNetworkHandler", "Client requested loading of %s which is already loaded", name); 00290 send_load_success(name, msg->clid()); 00291 } else { 00292 LibLogger::log_info("PluginNetworkHandler", "Loading plugin %s", name); 00293 load(name, msg->clid()); 00294 } 00295 } 00296 break; 00297 00298 case MSG_PLUGIN_UNLOAD: 00299 if ( msg->payload_size() != sizeof(plugin_unload_msg_t) ) { 00300 LibLogger::log_error("PluginNetworkHandler", "Invalid unload message size."); 00301 } else { 00302 plugin_unload_msg_t *m = (plugin_unload_msg_t *)msg->payload(); 00303 char name[PLUGIN_MSG_NAME_LENGTH + 1]; 00304 name[PLUGIN_MSG_NAME_LENGTH] = 0; 00305 strncpy(name, m->name, PLUGIN_MSG_NAME_LENGTH); 00306 00307 if ( !__manager->is_loaded(name) ) { 00308 LibLogger::log_info("PluginNetworkHandler", "Client requested unloading of %s which is not loaded", name); 00309 send_unload_success(name, msg->clid()); 00310 } else { 00311 LibLogger::log_info("PluginNetworkHandler", "UNloading plugin %s", name); 00312 unload(name, msg->clid()); 00313 } 00314 } 00315 break; 00316 00317 case MSG_PLUGIN_LIST_AVAIL: 00318 try { 00319 LibLogger::log_debug("PluginNetworkHandler", "Sending list of all available plugins"); 00320 PluginListMessage *plm = list_avail(); 00321 __hub->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_AVAIL_LIST, plm); 00322 } catch (Exception &e) { 00323 __hub->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_AVAIL_LIST_FAILED); 00324 } 00325 break; 00326 00327 case MSG_PLUGIN_LIST_LOADED: 00328 try { 00329 LibLogger::log_debug("PluginNetworkHandler", "Sending list of all loaded plugins"); 00330 PluginListMessage *plm = list_loaded(); 00331 __hub->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOADED_LIST, plm); 00332 } catch (Exception &e) { 00333 __hub->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOADED_LIST_FAILED); 00334 } 00335 break; 00336 00337 case MSG_PLUGIN_SUBSCRIBE_WATCH: 00338 __subscribers.lock(); 00339 __subscribers.push_back(msg->clid()); 00340 __subscribers.sort(); 00341 __subscribers.unique(); 00342 __subscribers.unlock(); 00343 break; 00344 00345 case MSG_PLUGIN_UNSUBSCRIBE_WATCH: 00346 __subscribers.remove_locked(msg->clid()); 00347 break; 00348 00349 default: 00350 // error 00351 break; 00352 } 00353 00354 msg->unref(); 00355 __inbound_queue.pop_locked(); 00356 } 00357 } 00358 00359 00360 void 00361 PluginNetworkHandler::handle_network_message(FawkesNetworkMessage *msg) 00362 { 00363 msg->ref(); 00364 __inbound_queue.push_locked(msg); 00365 wakeup(); 00366 } 00367 00368 00369 void 00370 PluginNetworkHandler::client_connected(unsigned int clid) 00371 { 00372 } 00373 00374 00375 void 00376 PluginNetworkHandler::client_disconnected(unsigned int clid) 00377 { 00378 __subscribers.remove_locked(clid); 00379 } 00380 00381 void 00382 PluginNetworkHandler::plugin_loaded(const char *plugin_name) 00383 { 00384 send_loaded(plugin_name); 00385 } 00386 00387 void 00388 PluginNetworkHandler::plugin_unloaded(const char *plugin_name) 00389 { 00390 send_unloaded(plugin_name); 00391 } 00392 00393 } // end namespace fawkes