Fawkes API Fawkes Development Version
handler.cpp
1
2/***************************************************************************
3 * handler.cpp - Fawkes plugin network handler
4 *
5 * Created: Thu Feb 12 10:36:15 2009
6 * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <logging/liblogger.h>
25#include <netcomm/fawkes/component_ids.h>
26#include <netcomm/fawkes/hub.h>
27#include <plugin/manager.h>
28#include <plugin/net/handler.h>
29#include <plugin/net/list_message.h>
30#include <plugin/net/messages.h>
31
32#include <algorithm>
33#include <cerrno>
34#include <cstdlib>
35#include <cstring>
36
37namespace fawkes {
38
39/** @class PluginNetworkHandler <plugin/net/handler.h>
40 * Fawkes Plugin Network Handler.
41 * This network handler handles requests of plugin lists and for loading/unloading
42 * plugins received over the network.
43 *
44 * @author Tim Niemueller
45 */
46
47/* IMPORANT IMPLEMENTER'S NOTE
48 *
49 * If you are going to work on this code mind the following: it is assumed
50 * that only loop() will pop messages from the inbound queue. Thus the inbound
51 * queue is only locked for this pop operation, not for the whole access time.
52 * This is true as long as messages are only appended from the outside!
53 * This is necessary to ensure that handle_network_message() will not hang
54 * waiting for the queue lock.
55 */
56
57/** Constructor.
58 * @param manager plugin manager for the actual work
59 * @param hub Fawkes network hub
60 */
62: Thread("PluginNetworkHandler", Thread::OPMODE_WAITFORWAKEUP),
63 FawkesNetworkHandler(FAWKES_CID_PLUGINMANAGER)
64{
65 manager_ = manager;
66 hub_ = hub;
67
68 manager_->add_listener(this);
69 hub_->add_handler(this);
70}
71
72/** Destructor. */
74{
75 hub_->remove_handler(this);
76 manager_->remove_listener(this);
77}
78
79/** Generate list of all available plugins.
80 * All files with the extension .so in the PLUGINDIR are returned.
81 * @param num_plugins pointer to an unsigned int where the number
82 * of all plugins is stored
83 * @param plugin_list pointer to the string array where the list of
84 * all plugins is stored. Memory is allocated at this address and
85 * has to be freed by the caller!
86 */
88PluginNetworkHandler::list_avail()
89{
91
92 std::list<std::pair<std::string, std::string>> available_plugins;
93 available_plugins = manager_->get_available_plugins();
94
95 std::list<std::pair<std::string, std::string>>::iterator i;
96 for (i = available_plugins.begin(); i != available_plugins.end(); ++i) {
97 m->append(i->first.c_str(), i->first.length());
98 m->append(i->second.c_str(), i->second.length());
99 }
100 return m;
101}
102
103PluginListMessage *
104PluginNetworkHandler::list_loaded()
105{
106 PluginListMessage *m = new PluginListMessage();
107
108 std::list<std::string> loaded_plugins;
109 loaded_plugins = manager_->get_loaded_plugins();
110
111 std::list<std::string>::iterator i;
112 for (i = loaded_plugins.begin(); i != loaded_plugins.end(); ++i) {
113 m->append(i->c_str(), i->length());
114 }
115
116 return m;
117}
118
119void
120PluginNetworkHandler::send_load_failure(const char *plugin_name, unsigned int client_id)
121{
122 try {
123 plugin_load_failed_msg_t *r =
124 (plugin_load_failed_msg_t *)calloc(1, sizeof(plugin_load_failed_msg_t));
125 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH - 1);
126 hub_->send(client_id,
127 FAWKES_CID_PLUGINMANAGER,
129 r,
130 sizeof(plugin_load_failed_msg_t));
131 } catch (Exception &e) {
132 LibLogger::log_warn("PluginNetworkHandler", "Failed to send load failure, exception follows");
133 LibLogger::log_warn("PluginNetworkHandler", e);
134 }
135}
136
137void
138PluginNetworkHandler::send_load_success(const char *plugin_name, unsigned int client_id)
139{
140 try {
141 plugin_loaded_msg_t *r = (plugin_loaded_msg_t *)calloc(1, sizeof(plugin_loaded_msg_t));
142 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH - 1);
143 hub_->send(
144 client_id, FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOADED, r, sizeof(plugin_loaded_msg_t));
145 } catch (Exception &e) {
146 LibLogger::log_warn("PluginNetworkHandler", "Failed to send load success, exception follows");
147 LibLogger::log_warn("PluginNetworkHandler", e);
148 }
149}
150
151void
152PluginNetworkHandler::send_unloaded(const char *plugin_name)
153{
154 subscribers_.lock();
155 try {
156 for (ssit_ = subscribers_.begin(); ssit_ != subscribers_.end(); ++ssit_) {
157 send_unload_success(plugin_name, *ssit_);
158 }
159 } catch (Exception &e) {
160 LibLogger::log_warn("PluginNetworkHandler", "Failed to send unloaded, exception follows");
161 LibLogger::log_warn("PluginNetworkHandler", e);
162 }
163 subscribers_.unlock();
164}
165
166void
167PluginNetworkHandler::send_loaded(const char *plugin_name)
168{
169 subscribers_.lock();
170 try {
171 for (ssit_ = subscribers_.begin(); ssit_ != subscribers_.end(); ++ssit_) {
172 send_load_success(plugin_name, *ssit_);
173 }
174 } catch (Exception &e) {
175 LibLogger::log_warn("PluginNetworkHandler", "Failed to send loaded, exception follows");
176 LibLogger::log_warn("PluginNetworkHandler", e);
177 }
178 subscribers_.unlock();
179}
180
181void
182PluginNetworkHandler::send_unload_failure(const char *plugin_name, unsigned int client_id)
183{
184 try {
185 plugin_unload_failed_msg_t *r =
186 (plugin_unload_failed_msg_t *)calloc(1, sizeof(plugin_unload_failed_msg_t));
187 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH - 1);
188 hub_->send(client_id,
189 FAWKES_CID_PLUGINMANAGER,
191 r,
192 sizeof(plugin_unload_failed_msg_t));
193 } catch (Exception &e) {
194 LibLogger::log_warn("PluginNetworkHandler", "Failed to send unload failure, exception follows");
195 LibLogger::log_warn("PluginNetworkHandler", e);
196 }
197}
198
199void
200PluginNetworkHandler::send_unload_success(const char *plugin_name, unsigned int client_id)
201{
202 try {
203 plugin_unloaded_msg_t *r = (plugin_unloaded_msg_t *)calloc(1, sizeof(plugin_unloaded_msg_t));
204 strncpy(r->name, plugin_name, PLUGIN_MSG_NAME_LENGTH - 1);
205 hub_->send(
206 client_id, FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_UNLOADED, r, sizeof(plugin_unloaded_msg_t));
207 } catch (Exception &e) {
208 LibLogger::log_warn("PluginNetworkHandler", "Failed to send unload success, exception follows");
209 LibLogger::log_warn("PluginNetworkHandler", e);
210 }
211}
212
213/** Load plugin.
214 * The loading is interrupted if any of the plugins does not load properly.
215 * The already loaded plugins are *not* unloaded, but kept.
216 * @param plugin_list string containing a comma-separated list of plugins
217 * to load. The plugin list can contain meta plugins.
218 * @param clid Fawkes network client ID of client that gets a success message
219 * with the exact string that was put into
220 */
221void
222PluginNetworkHandler::load(const char *plugin_list, unsigned int clid)
223{
224 manager_->lock();
225 try {
226 manager_->load(plugin_list);
227 send_load_success(plugin_list, clid);
228 } catch (Exception &e) {
229 LibLogger::log_error("PluginNetworkHandler", "Failed to load plugin %s", plugin_list);
230 LibLogger::log_error("PluginNetworkHandler", e);
231 send_load_failure(plugin_list, clid);
232 }
233 manager_->unlock();
234}
235
236/** Unload plugin.
237 * Note that this method does not allow to pass a list of plugins, but it will
238 * only accept a single plugin at a time.
239 * @param plugin_name plugin to unload, can be a meta plugin.
240 * @param clid Fawkes network client ID of client that gets a success message
241 * with the exact string that was put into
242 */
243void
244PluginNetworkHandler::unload(const char *plugin_name, unsigned int clid)
245{
246 manager_->lock();
247 try {
248 manager_->unload(plugin_name);
249 send_unload_success(plugin_name, clid);
250 } catch (Exception &e) {
251 LibLogger::log_error("PluginNetworkHandler", "Failed to unload plugin %s", plugin_name);
252 LibLogger::log_error("PluginNetworkHandler", e);
253 send_unload_failure(plugin_name, clid);
254 }
255 manager_->unlock();
256}
257
258/** Process all network messages that have been received.
259 */
260void
262{
263 while (!inbound_queue_.empty()) {
264 FawkesNetworkMessage *msg = inbound_queue_.front();
265
266 switch (msg->msgid()) {
267 case MSG_PLUGIN_LOAD:
268 if (msg->payload_size() != sizeof(plugin_load_msg_t)) {
269 LibLogger::log_error("PluginNetworkHandler", "Invalid load message size");
270 } else {
272 char name[PLUGIN_MSG_NAME_LENGTH + 1];
273 name[PLUGIN_MSG_NAME_LENGTH] = 0;
274 strncpy(name, m->name, PLUGIN_MSG_NAME_LENGTH);
275
276 if (manager_->is_loaded(name)) {
277 LibLogger::log_info("PluginNetworkHandler",
278 "Client requested loading of %s which is already loaded",
279 name);
280 send_load_success(name, msg->clid());
281 } else {
282 LibLogger::log_info("PluginNetworkHandler", "Loading plugin %s", name);
283 load(name, msg->clid());
284 }
285 }
286 break;
287
289 if (msg->payload_size() != sizeof(plugin_unload_msg_t)) {
290 LibLogger::log_error("PluginNetworkHandler", "Invalid unload message size.");
291 } else {
293 char name[PLUGIN_MSG_NAME_LENGTH + 1];
294 name[PLUGIN_MSG_NAME_LENGTH] = 0;
295 strncpy(name, m->name, PLUGIN_MSG_NAME_LENGTH);
296
297 if (!manager_->is_loaded(name)) {
298 LibLogger::log_info("PluginNetworkHandler",
299 "Client requested unloading of %s which is not loaded",
300 name);
301 send_unload_success(name, msg->clid());
302 } else {
303 LibLogger::log_info("PluginNetworkHandler", "UNloading plugin %s", name);
304 unload(name, msg->clid());
305 }
306 }
307 break;
308
310 try {
311 //LibLogger::log_debug("PluginNetworkHandler", "Sending list of all available plugins");
312 PluginListMessage *plm = list_avail();
313 hub_->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_AVAIL_LIST, plm);
314 } catch (Exception &e) {
315 hub_->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_AVAIL_LIST_FAILED);
316 }
317 break;
318
320 try {
321 //LibLogger::log_debug("PluginNetworkHandler", "Sending list of all loaded plugins");
322 PluginListMessage *plm = list_loaded();
323 hub_->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOADED_LIST, plm);
324 } catch (Exception &e) {
325 hub_->send(msg->clid(), FAWKES_CID_PLUGINMANAGER, MSG_PLUGIN_LOADED_LIST_FAILED);
326 }
327 break;
328
330 subscribers_.lock();
331 subscribers_.push_back(msg->clid());
332 subscribers_.sort();
333 subscribers_.unique();
334 subscribers_.unlock();
335 break;
336
337 case MSG_PLUGIN_UNSUBSCRIBE_WATCH: subscribers_.remove_locked(msg->clid()); break;
338
339 default:
340 // error
341 break;
342 }
343
344 msg->unref();
345 inbound_queue_.pop_locked();
346 }
347}
348
349void
351{
352 msg->ref();
353 inbound_queue_.push_locked(msg);
354 wakeup();
355}
356
357void
359{
360}
361
362void
364{
365 subscribers_.remove_locked(clid);
366}
367
368void
370{
371 send_loaded(plugin_name);
372}
373
374void
376{
377 send_unloaded(plugin_name);
378}
379
380} // end namespace fawkes
Base class for exceptions in Fawkes.
Definition: exception.h:36
Network handler abstract base class.
Definition: handler.h:32
Fawkes Network Hub.
Definition: hub.h:34
virtual void send(FawkesNetworkMessage *msg)=0
Method to send a message to a specific client.
virtual void remove_handler(FawkesNetworkHandler *handler)=0
Remove a message handler.
virtual void add_handler(FawkesNetworkHandler *handler)=0
Add a message handler.
Representation of a message that is sent over the network.
Definition: message.h:77
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:294
unsigned int clid() const
Get client ID.
Definition: message.cpp:276
void * payload() const
Get payload buffer.
Definition: message.cpp:312
size_t payload_size() const
Get payload size.
Definition: message.cpp:303
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:156
static void log_info(const char *component, const char *format,...)
Log informational message.
Definition: liblogger.cpp:138
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:174
virtual void unlock() const
Unlock list.
Definition: lock_list.h:138
virtual void lock() const
Lock list.
Definition: lock_list.h:124
void remove_locked(const Type &x)
Remove element from list with lock protection.
Definition: lock_list.h:163
void pop_locked()
Pop element from queue with lock protection.
Definition: lock_queue.h:144
void push_locked(const Type &x)
Push element to queue with lock protection.
Definition: lock_queue.h:135
Plugin list message.
Definition: list_message.h:35
void append(const char *plugin_name, size_t len)
Append plugin name.
Fawkes Plugin Manager.
Definition: manager.h:48
void remove_listener(PluginManagerListener *listener)
Remove listener.
Definition: manager.cpp:616
bool is_loaded(const std::string &plugin_name)
Check if plugin is loaded.
Definition: manager.cpp:257
void unload(const std::string &plugin_name)
Unload plugin.
Definition: manager.cpp:427
std::list< std::pair< std::string, std::string > > get_available_plugins()
Generate list of all available plugins.
Definition: manager.cpp:218
void add_listener(PluginManagerListener *listener)
Add listener.
Definition: manager.cpp:603
void load(const std::string &plugin_list)
Load plugin.
Definition: manager.cpp:325
std::list< std::string > get_loaded_plugins()
Get list of loaded plugins.
Definition: manager.cpp:234
void unlock()
Unlock plugin manager.
Definition: manager.cpp:680
void lock()
Lock plugin manager.
Definition: manager.cpp:661
~PluginNetworkHandler()
Destructor.
Definition: handler.cpp:73
virtual void handle_network_message(FawkesNetworkMessage *msg)
Called for incoming messages that are addressed to the correct component ID.
Definition: handler.cpp:350
virtual void plugin_unloaded(const char *plugin_name)
Plugin unloaded event.
Definition: handler.cpp:375
virtual void loop()
Process all network messages that have been received.
Definition: handler.cpp:261
PluginNetworkHandler(PluginManager *manager, FawkesNetworkHub *hub)
Constructor.
Definition: handler.cpp:61
virtual void client_connected(unsigned int clid)
Called when a new client connected.
Definition: handler.cpp:358
virtual void client_disconnected(unsigned int clid)
Called when a client disconnected.
Definition: handler.cpp:363
virtual void plugin_loaded(const char *plugin_name)
Plugin loaded event.
Definition: handler.cpp:369
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
void ref()
Increment reference count.
Definition: refcount.cpp:67
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
void wakeup()
Wake up thread.
Definition: thread.cpp:995
Fawkes library namespace.
@ MSG_PLUGIN_UNLOAD
request plugin unload (plugin_unload_msg_t)
Definition: messages.h:36
@ MSG_PLUGIN_UNLOAD_FAILED
plugin unload failed (plugin_unload_failed_msg_t)
Definition: messages.h:38
@ MSG_PLUGIN_LIST_LOADED
request lif of loaded plugins
Definition: messages.h:42
@ MSG_PLUGIN_AVAIL_LIST_FAILED
listing available plugins failed
Definition: messages.h:41
@ MSG_PLUGIN_LOADED_LIST_FAILED
listing loaded plugins failed
Definition: messages.h:44
@ MSG_PLUGIN_AVAIL_LIST
list of available plugins (plugin_list_msg_t)
Definition: messages.h:40
@ MSG_PLUGIN_LOAD
request plugin load (plugin_load_msg_t)
Definition: messages.h:33
@ MSG_PLUGIN_LOAD_FAILED
plugin load failed (plugin_load_failed_msg_t)
Definition: messages.h:35
@ MSG_PLUGIN_LOADED_LIST
list of loaded plugins (plugin_list_msg_t)
Definition: messages.h:43
@ MSG_PLUGIN_LIST_AVAIL
request list of available plugins
Definition: messages.h:39
@ MSG_PLUGIN_SUBSCRIBE_WATCH
Subscribe for watching load/unload events.
Definition: messages.h:45
@ MSG_PLUGIN_UNSUBSCRIBE_WATCH
Unsubscribe from watching load/unload events.
Definition: messages.h:46
@ MSG_PLUGIN_UNLOADED
plugin unloaded (plugin_unloaded_msg_t)
Definition: messages.h:37
@ MSG_PLUGIN_LOADED
plugin loaded (plugin_loaded_msg_t)
Definition: messages.h:34
Load plugin message.
Definition: messages.h:56
char name[PLUGIN_MSG_NAME_LENGTH]
name of the plugin to load.
Definition: messages.h:57
Unload plugin message.
Definition: messages.h:64
char name[PLUGIN_MSG_NAME_LENGTH]
name of te plugin to unload.
Definition: messages.h:65