root/src/noit_module.c

Revision 7afb4e334fa8390d0543fc8d916d5c6b861511a9, 16.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

fixes #219

This is "significant" as it requires adding a module section to
stratcon.conf and not using the <stomp> stanza, but instead using
<mq type="stomp">. I've tested it with ActiveMQ and RabbitMQ and
both work fine.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include <stdio.h>
36 #include <dlfcn.h>
37
38 #include <libxml/parser.h>
39 #include <libxslt/xslt.h>
40 #include <libxslt/xsltInternals.h>
41 #include <libxslt/transform.h>
42
43 #include "noit_module.h"
44 #include "noit_conf.h"
45 #include "utils/noit_hash.h"
46 #include "utils/noit_log.h"
47
48 static noit_module_t *
49 noit_load_module_image(noit_module_loader_t *loader,
50                        char *module_name,
51                        noit_conf_section_t section);
52
53 noit_module_loader_t __noit_image_loader = {
54   {
55     NOIT_LOADER_MAGIC,
56     NOIT_LOADER_ABI_VERSION,
57     "image",
58     "Basic binary image loader",
59     NULL
60   },
61   NULL,
62   NULL,
63   noit_load_module_image
64 };
65 struct __extended_image_data {
66   void *userdata;
67 };
68
69 static noit_hash_table loaders = NOIT_HASH_EMPTY;
70 static noit_hash_table modules = NOIT_HASH_EMPTY;
71 static noit_hash_table generics = NOIT_HASH_EMPTY;
72
73 noit_module_loader_t * noit_loader_lookup(const char *name) {
74   void *vloader;
75
76   if(noit_hash_retrieve(&loaders, name, strlen(name), &vloader))
77     return (noit_module_loader_t *)vloader;
78   return NULL;
79 }
80
81 noit_module_t * noit_module_lookup(const char *name) {
82   void *vmodule;
83
84   if(noit_hash_retrieve(&modules, name, strlen(name), &vmodule))
85     return (noit_module_t *)vmodule;
86   return NULL;
87 }
88
89 noit_module_generic_t * noit_module_generic_lookup(const char *name) {
90   void *vmodule;
91
92   if(noit_hash_retrieve(&generics, name, strlen(name), &vmodule))
93     return (noit_module_generic_t *)vmodule;
94   return NULL;
95 }
96
97 static int noit_module_validate_magic(noit_image_t *obj) {
98   if (NOIT_IMAGE_MAGIC(obj) != NOIT_MODULE_MAGIC) return -1;
99   if (NOIT_IMAGE_VERSION(obj) != NOIT_MODULE_ABI_VERSION) return -1;
100   return 0;
101 }
102
103 static int noit_module_generic_validate_magic(noit_image_t *obj) {
104   if (NOIT_IMAGE_MAGIC(obj) != NOIT_GENERIC_MAGIC) return -1;
105   if (NOIT_IMAGE_VERSION(obj) != NOIT_GENERIC_ABI_VERSION) return -1;
106   return 0;
107 }
108
109 static int noit_module_loader_validate_magic(noit_image_t *obj) {
110   if (NOIT_IMAGE_MAGIC(obj) != NOIT_LOADER_MAGIC) return -1;
111   if (NOIT_IMAGE_VERSION(obj) != NOIT_LOADER_ABI_VERSION) return -1;
112   return 0;
113 }
114
115 noit_module_t *noit_blank_module() {
116   noit_module_t *obj;
117   obj = calloc(1, sizeof(*obj));
118   obj->hdr.opaque_handle = calloc(1, sizeof(struct __extended_image_data));
119   return obj;
120 }
121
122 int noit_register_module(noit_module_t *mod) {
123   noit_hash_store(&modules, mod->hdr.name, strlen(mod->hdr.name), mod);
124   return 0;
125 }
126
127 int noit_load_image(const char *file, const char *name,
128                     noit_hash_table *registry,
129                     int (*validate)(noit_image_t *),
130                     size_t obj_size) {
131   char module_file[PATH_MAX];
132   char *base;
133   void *dlhandle;
134   void *dlsymbol;
135   noit_image_t *obj;
136
137   if(!noit_conf_get_string(NULL, "//modules/@directory", &base))
138     base = strdup("");
139
140   if(file[0] == '/')
141     strlcpy(module_file, file, sizeof(module_file));
142   else
143     snprintf(module_file, sizeof(module_file), "%s/%s.%s",
144              base, file, MODULEEXT);
145   free(base);
146
147   dlhandle = dlopen(module_file, RTLD_LAZY | RTLD_GLOBAL);
148   if(!dlhandle) {
149     noitL(noit_stderr, "Cannot open image '%s': %s\n",
150           module_file, dlerror());
151     return -1;
152   }
153
154   dlsymbol = dlsym(dlhandle, name);
155   if(!dlsymbol) {
156     noitL(noit_stderr, "Cannot find '%s' in image '%s': %s\n",
157           name, module_file, dlerror());
158     dlclose(dlhandle);
159     return -1;
160   }
161
162   if(validate(dlsymbol) == -1) {
163     noitL(noit_stderr, "I can't understand image %s\n", name);
164     dlclose(dlhandle);
165     return -1;
166   }
167
168   obj = calloc(1, obj_size);
169   memcpy(obj, dlsymbol, obj_size);
170   obj->opaque_handle = calloc(1, sizeof(struct __extended_image_data));
171
172   if(obj->onload && obj->onload(obj)) {
173     free(obj);
174     return -1;
175   }
176   noit_hash_store(registry, obj->name, strlen(obj->name), obj);
177   return 0;
178 }
179
180 static noit_module_generic_t *
181 noit_load_generic_image(noit_module_loader_t *loader,
182                         char *g_name,
183                         noit_conf_section_t section) {
184   char g_file[PATH_MAX];
185
186   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
187                               g_file, sizeof(g_file))) {
188     noitL(noit_stderr, "No image defined for %s\n", g_name);
189     return NULL;
190   }
191   if(noit_load_image(g_file, g_name, &generics,
192                      noit_module_generic_validate_magic,
193                      sizeof(noit_module_generic_t))) {
194     noitL(noit_stderr, "Could not load %s:%s\n", g_file, g_name);
195     return NULL;
196   }
197   return noit_module_generic_lookup(g_name);
198 }
199
200 static noit_module_loader_t *
201 noit_load_loader_image(noit_module_loader_t *loader,
202                        char *loader_name,
203                        noit_conf_section_t section) {
204   char loader_file[PATH_MAX];
205
206   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
207                               loader_file, sizeof(loader_file))) {
208     noitL(noit_stderr, "No image defined for %s\n", loader_name);
209     return NULL;
210   }
211   if(noit_load_image(loader_file, loader_name, &loaders,
212                      noit_module_loader_validate_magic,
213                      sizeof(noit_module_loader_t))) {
214     noitL(noit_stderr, "Could not load %s:%s\n", loader_file, loader_name);
215     return NULL;
216   }
217   return noit_loader_lookup(loader_name);
218 }
219
220 static noit_module_t *
221 noit_load_module_image(noit_module_loader_t *loader,
222                        char *module_name,
223                        noit_conf_section_t section) {
224   char module_file[PATH_MAX];
225
226   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
227                               module_file, sizeof(module_file))) {
228     noitL(noit_stderr, "No image defined for %s\n", module_name);
229     return NULL;
230   }
231   if(noit_load_image(module_file, module_name, &modules,
232                      noit_module_validate_magic, sizeof(noit_module_t))) {
233     noitL(noit_stderr, "Could not load %s:%s\n", module_file, module_name);
234     return NULL;
235   }
236   return noit_module_lookup(module_name);
237 }
238
239 #include "module-online.h"
240
241 void noit_module_print_help(noit_console_closure_t ncct,
242                             noit_module_t *module, int examples) {
243   const char *params[3] = { NULL };
244   xmlDocPtr help = NULL, output = NULL;
245   xmlOutputBufferPtr out;
246   xmlCharEncodingHandlerPtr enc;
247   static xmlDocPtr helpStyleDoc = NULL;
248   static xsltStylesheetPtr helpStyle = NULL;
249   if(!helpStyle) {
250     if(!helpStyleDoc)
251       helpStyleDoc = xmlParseMemory(helpStyleXML, strlen(helpStyleXML));
252     if(!helpStyleDoc) {
253       nc_printf(ncct, "Invalid XML for style XML\n");
254       return;
255     }
256     helpStyle = xsltParseStylesheetDoc(helpStyleDoc);
257   }
258   if(!helpStyle) {
259     nc_printf(ncct, "no available stylesheet.\n");
260     return;
261   }
262   if(!module) {
263     nc_printf(ncct, "no module\n");
264     return;
265   }
266   if(!module->hdr.xml_description) {
267     nc_printf(ncct, "%s is undocumented, complain to the vendor.\n",
268               module->hdr.name);
269     return;
270   }
271   help = xmlParseMemory(module->hdr.xml_description,
272                         strlen(module->hdr.xml_description));
273   if(!help) {
274     nc_printf(ncct, "%s module has invalid XML documentation.\n",
275               module->hdr.name);
276     return;
277   }
278
279   if(examples) {
280     params[0] = "example";
281     params[1] = "'1'";
282     params[2] = NULL;
283   }
284   output = xsltApplyStylesheet(helpStyle, help, params);
285   if(!output) {
286     nc_printf(ncct, "formatting failed.\n");
287     goto out;
288   }
289
290   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
291   out = xmlOutputBufferCreateIO(noit_console_write_xml,
292                                 noit_console_close_xml,
293                                 ncct, enc);
294   xmlSaveFormatFileTo(out, output, "utf8", 1);
295
296  out:
297   if(help) xmlFreeDoc(help);
298   if(output) xmlFreeDoc(output);
299 }
300
301 char *
302 noit_module_options(noit_console_closure_t ncct,
303                     noit_console_state_stack_t *stack,
304                     noit_console_state_t *state,
305                     int argc, char **argv, int idx) {
306   if(argc == 1) {
307     /* List modules */
308     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
309     const char *name;
310     int klen, i = 0;
311     void *vhdr;
312
313     while(noit_hash_next(&loaders, &iter, (const char **)&name, &klen,
314                          &vhdr)) {
315       noit_image_t *hdr = (noit_image_t *)vhdr;
316       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
317         if(idx == i) return strdup(hdr->name);
318         i++;
319       }
320     }
321     memset(&iter, 0, sizeof(iter));
322     while(noit_hash_next(&modules, &iter, (const char **)&name, &klen,
323                          &vhdr)) {
324       noit_image_t *hdr = (noit_image_t *)vhdr;
325       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
326         if(idx == i) return strdup(hdr->name);
327         i++;
328       }
329     }
330     return NULL;
331   }
332   if(argc == 2) {
333     if(!strncmp("examples", argv[1], strlen(argv[1])))
334       if(idx == 0) return strdup("examples");
335   }
336   return NULL;
337 }
338 int
339 noit_module_help(noit_console_closure_t ncct,
340                  int argc, char **argv,
341                  noit_console_state_t *state, void *closure) {
342   if(argc == 0) {
343     /* List modules */
344     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
345     const char *name;
346     int klen;
347     void *vhdr;
348
349     nc_printf(ncct, "= Loaders and Modules =\n");
350     while(noit_hash_next(&loaders, &iter, (const char **)&name, &klen,
351                          &vhdr)) {
352       noit_image_t *hdr = (noit_image_t *)vhdr;;
353       nc_printf(ncct, "  %s\n", hdr->name);
354     }
355     memset(&iter, 0, sizeof(iter));
356     while(noit_hash_next(&modules, &iter, (const char **)&name, &klen,
357                          &vhdr)) {
358       noit_image_t *hdr = (noit_image_t *)vhdr;;
359       nc_printf(ncct, "  %s\n", hdr->name);
360     }
361     return 0;
362   }
363   else if(argc == 1 ||
364           (argc == 2 && !strcmp(argv[1], "examples"))) {
365     /* help for a specific module */
366     noit_module_t *mod;
367     mod = noit_module_lookup(argv[0]);
368     noit_module_print_help(ncct, mod, argc == 2);
369     return 0;
370   }
371   nc_printf(ncct, "help module [ <modulename> [ examples ] ]\n");
372   return -1;
373 }
374
375 void noit_module_init() {
376   noit_conf_section_t *sections;
377   int i, cnt = 0;
378
379   noit_console_add_help("module", noit_module_help, noit_module_options);
380
381   /* Load our generic modules */
382   sections = noit_conf_get_sections(NULL, "//modules//generic", &cnt);
383   for(i=0; i<cnt; i++) {
384     char g_name[256];
385     noit_module_generic_t *gen;
386
387     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
388                                 g_name, sizeof(g_name))) {
389       noitL(noit_stderr, "No name defined in generic stanza %d\n", i+1);
390       continue;
391     }
392     gen = noit_load_generic_image(&__noit_image_loader, g_name,
393                                   sections[i]);
394     if(!gen) {
395       noitL(noit_stderr, "Failed to load generic %s\n", g_name);
396       continue;
397     }
398     if(gen->config) {
399       int rv;
400       noit_hash_table *config;
401       config = noit_conf_get_hash(sections[i], "config");
402       rv = gen->config(gen, config);
403       if(rv == 0) {
404         noit_hash_destroy(config, free, free);
405         free(config);
406       }
407       else if(rv < 0) {
408         noitL(noit_stderr, "Failed to config generic %s\n", g_name);
409         continue;
410       }
411     }
412     if(gen->init && gen->init(gen))
413       noitL(noit_stderr, "Failed to init generic %s\n", g_name);
414     else
415       noitL(noit_stderr, "Generic module %s successfully loaded.\n", g_name);
416   }
417   if(sections) free(sections);
418   /* Load our module loaders */
419   sections = noit_conf_get_sections(NULL, "//modules//loader", &cnt);
420   for(i=0; i<cnt; i++) {
421     char loader_name[256];
422     noit_module_loader_t *loader;
423
424     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
425                                 loader_name, sizeof(loader_name))) {
426       noitL(noit_stderr, "No name defined in loader stanza %d\n", i+1);
427       continue;
428     }
429     loader = noit_load_loader_image(&__noit_image_loader, loader_name,
430                                     sections[i]);
431     if(!loader) {
432       noitL(noit_stderr, "Failed to load loader %s\n", loader_name);
433       continue;
434     }
435     if(loader->config) {
436       int rv;
437       noit_hash_table *config;
438       config = noit_conf_get_hash(sections[i], "config");
439       rv = loader->config(loader, config);
440       if(rv == 0) {
441         noit_hash_destroy(config, free, free);
442         free(config);
443       }
444       else if(rv < 0) {
445         noitL(noit_stderr, "Failed to config loader %s\n", loader_name);
446         continue;
447       }
448     }
449     if(loader->init && loader->init(loader))
450       noitL(noit_stderr, "Failed to init loader %s\n", loader_name);
451   }
452   if(sections) free(sections);
453
454   /* Load the modules (these *are* specific to the /noit/ root) */
455   sections = noit_conf_get_sections(NULL, "/noit/modules//module", &cnt);
456   if(!sections) return;
457   for(i=0; i<cnt; i++) {
458     noit_module_loader_t *loader = &__noit_image_loader;
459     noit_hash_table *config;
460     noit_module_t *module;
461     char loader_name[256];
462     char module_name[256];
463
464     /* If no loader is specified, we should use the image loader */
465     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
466                                 module_name, sizeof(module_name))) {
467       noitL(noit_stderr, "No name defined in module stanza %d\n", i+1);
468       continue;
469     }
470
471     if(noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@loader",
472                                 loader_name, sizeof(loader_name))) {
473       loader = noit_loader_lookup(loader_name);
474       if(!loader) {
475         noitL(noit_stderr, "No '%s' loader found.\n", loader_name);
476         continue;
477       }
478     } else {
479       strlcpy(loader_name, "image", sizeof(loader_name));
480     }
481
482     module = loader->load(loader, module_name, sections[i]);
483     if(!module) {
484       noitL(noit_stderr, "Loader '%s' failed to load '%s'.\n",
485             loader_name, module_name);
486       continue;
487     }
488     config = noit_conf_get_hash(sections[i], "config");
489     if(module->config) {
490       int rv;
491       rv = module->config(module, config);
492       if(rv == 0) {
493         /* Not an error,
494          * but the module didn't take responsibility for the config.
495          */
496         noit_hash_destroy(config, free, free);
497         free(config);
498       }
499       else if(rv < 0) {
500         noitL(noit_stderr,
501               "Configure failed on %s\n", module_name);
502         continue;
503       }
504     }
505     if(module->init && module->init(module)) {
506       noitL(noit_stderr,
507             "Initialized failed on %s\n", module_name);
508       continue;
509     }
510     noitL(noit_stderr, "Module %s successfully loaded.\n", module_name);
511   }
512   free(sections);
513 }
514
515 #define userdata_accessors(type, field) \
516 void *noit_##type##_get_userdata(noit_##type##_t *mod) { \
517   return ((struct __extended_image_data *)mod->field)->userdata; \
518 } \
519 void noit_##type##_set_userdata(noit_##type##_t *mod, void *newdata) { \
520   ((struct __extended_image_data *)mod->field)->userdata = newdata; \
521 }
522
523 userdata_accessors(image, opaque_handle)
524 userdata_accessors(module_loader, hdr.opaque_handle)
525 userdata_accessors(module, hdr.opaque_handle)
Note: See TracBrowser for help on using the browser.