plugin_tool.cpp

00001
00002 /***************************************************************************
00003  *  plugin_tool.cpp - Fawkes plugin tool
00004  *
00005  *  Created: Mon Dec 04 14:43:23 2006
00006  *  Copyright  2006  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.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022
00023 #include <tools/plugin/plugin_tool.h>
00024
00025 #include <netcomm/fawkes/client.h>
00026 #include <plugin/net/messages.h>
00027 #include <plugin/net/list_message.h>
00028 #include <utils/system/argparser.h>
00029
00030 #include <cstdio>
00031 #include <cstdlib>
00032 #include <cstring>
00033
00034 using namespace fawkes;
00035 
00036 /** @class PluginTool tools/plugin/plugin_tool.h
00037  * Program to communicate with plugin manager via Fawkes network.
00038  */
00039 
00040 /** Constructor.
00041  * @param argp argument parser, three arguments are handled:
00042  * - -l plugin_name load plugin named plugin_name
00043  * - -u plugin_name unload plugin named plugin_name
00044  * - -w watch for changes
00045  * @param c FawkesNetworkClient with established connection
00046  */
00047 PluginTool::PluginTool(ArgumentParser *argp, FawkesNetworkClient *c)
00048 {
00049   this->c     = c;
00050   plugin_name = NULL;
00051   quit        = false;
00052
00053   if ( argp->has_arg("l") ) {
00054     opmode = M_LOAD;
00055     plugin_name = argp->arg("l");
00056   } else if ( argp->has_arg("u") ) {
00057     opmode = M_UNLOAD;
00058     plugin_name = argp->arg("u");
00059   } else if ( argp->has_arg("r") ) {
00060     opmode = M_RELOAD;
00061     plugin_name = argp->arg("r");
00062   } else if ( argp->has_arg("w") ) {
00063     opmode = M_WATCH;
00064   } else if ( argp->has_arg("a") ) {
00065     opmode = M_LIST_AVAIL;
00066   } else {
00067     opmode = M_LIST_LOADED;
00068   }
00069
00070   __program_name = argp->program_name();
00071
00072   list_found = false;
00073 }
00074
00075 
00076 /** Constructor.
00077  * This constructor just set the Fawkes network client. A run() call will
00078  * fail if not one of set_load_plugin(), set_unload_plugin(), set_watch_mode()
00079  * or set_list_mode() has been called before.
00080  * @param c Fawkes network client with established connection
00081  */
00082 PluginTool::PluginTool(FawkesNetworkClient *c)
00083 {
00084   this->c     = c;
00085   plugin_name = NULL;
00086   quit        = false;
00087   opmode      = M_UNKNOWN;
00088   list_found  = false;
00089 }
00090 
00091 /** Destructor */
00092 PluginTool::~PluginTool()
00093 {
00094 }
00095
00096 
00097 /** Print usage.
00098  * @param program_name program name
00099  */
00100 void
00101 PluginTool::print_usage(const char *program_name)
00102 {
00103     printf("Usage: %s [-l plugin/-u plugin/-w/-a/-L]\n"
00104            "  -l plugin      Load plugin with given name\n"
00105            "  -u plugin      Unload plugin with given name\n"
00106            "  -w             Watch all load/unload operations\n"
00107            "  -a             List available plugins\n"
00108            "  -L             List loaded plugins (default)\n\n"
00109            "  If called without any option list currently loaded plugins\n\n",
00110            program_name);
00111 }
00112 
00113 /** Load plugin on next run.
00114  * The next time run is called a LOAD_PLUGIN message is sent for the
00115  * given plugin name.
00116  * @param plugin_name name of the plugin to load
00117  */
00118 void
00119 PluginTool::set_load_plugin(const char *plugin_name)
00120 {
00121   this->plugin_name = plugin_name;
00122   opmode = M_LOAD;
00123 }
00124
00125 
00126 /** Unload plugin on next run.
00127  * The next time run is called a UNLOAD_PLUGIN message is sent for the
00128  * given plugin name.
00129  * @param plugin_name name of the plugin to unload
00130  */
00131 void
00132 PluginTool::set_unload_plugin(const char *plugin_name)
00133 {
00134   this->plugin_name = plugin_name;
00135   opmode = M_UNLOAD;
00136 }
00137
00138 
00139 /** Set watch mode.
00140  * On next run() call the client will watch for new events.
00141  */
00142 void
00143 PluginTool::set_watch_mode()
00144 {
00145   opmode = M_WATCH;
00146 }
00147
00148 
00149 /** Set list mode.
00150  * On next run() call the client will list all loaded plugins once.
00151  */
00152 void
00153 PluginTool::set_list_mode()
00154 {
00155   opmode = M_LIST_LOADED;
00156 }
00157
00158 
00159 /** Handle signals.
00160  * @param signum signal number of received signal
00161  */
00162 void
00163 PluginTool::handle_signal(int signum)
00164 {
00165   c->wake(FAWKES_CID_PLUGINMANAGER);
00166   quit = true;
00167 }
00168
00169 
00170 /** Execute load operation. */
00171 void
00172 PluginTool::load()
00173 {
00174   printf("Requesting loading of plugin %s\n", plugin_name);
00175   plugin_load_msg_t *l = (plugin_load_msg_t *)calloc(1, sizeof(plugin_load_msg_t));
00176   strncpy(l->name, plugin_name, PLUGIN_MSG_NAME_LENGTH);
00177
00178   FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00179                                                        MSG_PLUGIN_LOAD,
00180                                                        l, sizeof(plugin_load_msg_t));
00181   c->enqueue(msg);
00182   msg->unref();
00183
00184   while ( ! quit ) {
00185     c->wait(FAWKES_CID_PLUGINMANAGER);
00186   }
00187 }
00188
00189 
00190 /** Execute unload operation. */
00191 void
00192 PluginTool::unload()
00193 {
00194   printf("Requesting unloading of plugin %s\n", plugin_name);
00195   plugin_unload_msg_t *m = (plugin_unload_msg_t *)calloc(1, sizeof(plugin_unload_msg_t));
00196   strncpy(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH);
00197
00198   FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00199                                                        MSG_PLUGIN_UNLOAD,
00200                                                        m, sizeof(plugin_unload_msg_t));
00201   c->enqueue(msg);
00202   msg->unref();
00203
00204   while ( ! quit ) {
00205     c->wait(FAWKES_CID_PLUGINMANAGER);
00206   }
00207 }
00208
00209 
00210 /** Execute list available operation. */
00211 void
00212 PluginTool::list_avail()
00213 {
00214   printf("Request the list of all available plugins\n");
00215   FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00216                                                        MSG_PLUGIN_LIST_AVAIL);
00217   c->enqueue(msg);
00218   msg->unref();
00219
00220   while ( ! quit ) {
00221     c->wait(FAWKES_CID_PLUGINMANAGER);
00222   }
00223 }
00224
00225 
00226 /** Execute list operation. */
00227 void
00228 PluginTool::list_loaded()
00229 {
00230   // we got a list of loaded messages during startup, show them
00231   printf("Request the list of all loaded plugins\n");
00232   FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00233                                                        MSG_PLUGIN_LIST_LOADED);
00234   c->enqueue(msg);
00235   msg->unref();
00236
00237   while ( ! quit ) {
00238     c->wait(FAWKES_CID_PLUGINMANAGER);
00239   }
00240 }
00241
00242 
00243 /** Watch for plugin manager events. */
00244 void
00245 PluginTool::watch()
00246 {
00247   FawkesNetworkMessage *msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER,
00248                                                        MSG_PLUGIN_SUBSCRIBE_WATCH);
00249   c->enqueue(msg);
00250   msg->unref();
00251   printf("Watching for plugin events\n");
00252   printf("%-10s   %-40s\n", "Event", "Plugin Name/ID");
00253   while ( ! quit ) {
00254     c->wait(FAWKES_CID_PLUGINMANAGER);
00255   }
00256
00257   // unsubscribe
00258   msg = new FawkesNetworkMessage(FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_UNSUBSCRIBE_WATCH);
00259   c->enqueue(msg);
00260   msg->unref();
00261 }
00262
00263 
00264 /** Handler has been deregistered.
00265  */
00266 void
00267 PluginTool::deregistered(unsigned int id) throw()
00268 {
00269   quit = true;
00270 }
00271
00272 
00273 /** Inbound message received.
00274  * @param msg message.
00275  */
00276 void
00277 PluginTool::inbound_received(FawkesNetworkMessage *msg,
00278                              unsigned int id) throw()
00279 {
00280   if (msg->cid() != FAWKES_CID_PLUGINMANAGER)  return;
00281
00282   if ( msg->msgid() == MSG_PLUGIN_LOADED ) {
00283     if ( msg->payload_size() != sizeof(plugin_loaded_msg_t) ) {
00284       printf("Invalid message size (load succeeded)\n");
00285     } else {
00286       plugin_loaded_msg_t *m = (plugin_loaded_msg_t *)msg->payload();
00287       if ( opmode == M_WATCH ) {
00288         printf("%-10s   %s\n", "loaded", m->name);
00289       } else {
00290         if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
00291           printf("Loading of %s succeeded\n", plugin_name);
00292           quit = true;
00293         }
00294       }
00295     }
00296   } else if ( msg->msgid() == MSG_PLUGIN_LOAD_FAILED) {
00297     if ( msg->payload_size() != sizeof(plugin_load_failed_msg_t) ) {
00298       printf("Invalid message size (load failed)\n");
00299     } else {
00300       plugin_load_failed_msg_t *m = (plugin_load_failed_msg_t *)msg->payload();
00301       if ( opmode == M_WATCH ) {
00302         printf("%-10s   %s\n", "loadfail", m->name);
00303       } else {
00304         if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
00305           printf("Loading of %s failed, see log for reason\n", plugin_name);
00306           quit = true;
00307         }
00308       }
00309     }
00310   } else if ( msg->msgid() == MSG_PLUGIN_UNLOADED ) {
00311     if ( msg->payload_size() != sizeof(plugin_unloaded_msg_t) ) {
00312       printf("Invalid message size (unload succeeded)\n");
00313     } else {
00314       plugin_unloaded_msg_t *m = (plugin_unloaded_msg_t *)msg->payload();
00315       if ( opmode == M_WATCH ) {
00316         printf("%-10s   %s\n", "unloaded", m->name);
00317       } else {
00318         if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
00319           printf("Unloading of %s succeeded\n", plugin_name);
00320           quit = true;
00321         }
00322       }
00323     }
00324   } else if ( msg->msgid() == MSG_PLUGIN_UNLOAD_FAILED) {
00325     if ( msg->payload_size() != sizeof(plugin_unload_failed_msg_t) ) {
00326       printf("Invalid message size (unload failed)\n");
00327     } else {
00328       plugin_unload_failed_msg_t *m = (plugin_unload_failed_msg_t *)msg->payload();
00329       if ( opmode == M_WATCH ) {
00330         printf("%-10s   %s\n", "unloadfail", m->name);
00331       } else {
00332         if ( strncmp(m->name, plugin_name, PLUGIN_MSG_NAME_LENGTH) == 0 ) {
00333           printf("Unloading of %s failed, see log for reason\n", plugin_name);
00334           quit = true;
00335         }
00336       }
00337     }
00338   } else if (msg->msgid() == MSG_PLUGIN_AVAIL_LIST ) {
00339     PluginListMessage *plm = msg->msgc<PluginListMessage>();
00340     if ( plm->has_next() ) {
00341       printf("Available plugins:\n");
00342       while ( plm->has_next() ) {
00343         char *plugin_name = plm->next();
00344         char *plugin_desc = NULL;
00345         if ( plm->has_next() ) {
00346           plugin_desc = plm->next();
00347         } else {
00348           throw Exception("Invalid plugin list received");
00349         }
00350         printf(" %-16s (%s)\n", plugin_name, plugin_desc);
00351         free(plugin_name);
00352         free(plugin_desc);
00353       }
00354     } else {
00355       printf("No plugins available\n");
00356     }
00357     quit = true;
00358     delete plm;
00359   } else if (msg->msgid() == MSG_PLUGIN_LOADED_LIST ) {
00360     PluginListMessage *plm = msg->msgc<PluginListMessage>();
00361     if ( plm->has_next() ) {
00362       printf("Loaded plugins:\n");
00363       while ( plm->has_next() ) {
00364         char *p = plm->next();
00365         printf("  %s\n", p);
00366         free(p);
00367       }
00368     } else {
00369       printf("No plugins loaded\n");
00370     }
00371     quit = true;
00372     delete plm;
00373   } else if ( msg->msgid() == MSG_PLUGIN_AVAIL_LIST_FAILED) {
00374     printf("Obtaining list of available plugins failed\n");
00375   } else if ( msg->msgid() == MSG_PLUGIN_LOADED_LIST_FAILED) {
00376     printf("Obtaining list of loaded plugins failed\n");
00377   }
00378 }
00379
00380
00381 void
00382 PluginTool::connection_established(unsigned int id) throw()
00383 {
00384   // ignored, client has to be connected already
00385 }
00386
00387
00388 void
00389 PluginTool::connection_died(unsigned int id) throw()
00390 {
00391   printf("Connection died, exiting\n");
00392   quit = true;
00393 }
00394 
00395 /** Run opmode as requested determined by the arguments. */
00396 void
00397 PluginTool:: run()
00398 {
00399   c->register_handler(this, FAWKES_CID_PLUGINMANAGER);
00400
00401   switch (opmode) {
00402   case M_LOAD:
00403     load();
00404     break;
00405
00406   case M_UNLOAD:
00407     unload();
00408     break;
00409
00410   case M_RELOAD:
00411     unload();
00412     quit = false;
00413     load();
00414     break;
00415
00416   case M_LIST_AVAIL:
00417     list_avail();
00418     break;
00419
00420   case M_LIST_LOADED:
00421     list_loaded();
00422     break;
00423
00424   case M_WATCH:
00425     watch();
00426     break;
00427
00428   default:
00429     print_usage(__program_name);
00430   }
00431
00432   c->deregister_handler(FAWKES_CID_PLUGINMANAGER);
00433 }