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