plugins_dir convert to array
authorAndy Green <andy@warmcat.com>
Mon, 2 May 2016 02:03:25 +0000 (10:03 +0800)
committerAndy Green <andy@warmcat.com>
Mon, 2 May 2016 02:03:25 +0000 (10:03 +0800)
If OOT lws plugins will be packaged as separate projects,
they're going to want to install their plugins somewhere
that makes sense for the package instead of one big lws
plugin dir.

This patch changes info to have a const char ** to a NULL
terminated array of directories it should search for
plugins.  lwsws knows about this and you can add to the
dir array using config fragments like

{
  "global": {
   "plugin-dir": "/usr/local/share/coherent-timeline/plugins"
  }
}

if the config fragment in /etc/lwsws/conf.d/ is also managed by the
package with the plugin, it can very cleanly add and remove itself
from lwsws based on package install status.

Signed-off-by: Andy Green <andy@warmcat.com>
README.lwsws.md
lib/libuv.c
lib/libwebsockets.h
lib/lws-plat-unix.c
lib/private-libwebsockets.h
lwsws/conf.c
lwsws/main.c
test-server/test-server-v2.0.c

index 28cf5c14ccf5b839c83d2b850fc13cbbdb050efe..63b026686ecb7ba24fd91cefc23081a2627bc49b 100644 (file)
@@ -284,6 +284,19 @@ To help that happen conveniently, there are some new apis
 dumb increment, mirror and status protocol plugins are provided as examples.
 
 
+Additional plugin search paths
+------------------------------
+
+Packages that have their own lws plugins can install them in their own
+preferred dir and ask lwsws to scan there by using a config fragment
+like this, in its own conf.d/ file managed by the other package
+
+{
+  "global": {
+   "plugin-dir": "/usr/local/share/coherent-timeline/plugins"
+  }
+}
+
 
 lws-server-status plugin
 ------------------------
index b00d2a8783fae575e4a22d825a2ec226fbe0aea3..a230b57fb8062ab9088df7587cb3eed68af8b4f3 100644 (file)
@@ -416,7 +416,7 @@ lws_libuv_closehandle(struct lws *wsi)
 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
 
 LWS_VISIBLE int
-lws_plat_plugins_init(struct lws_context * context, const char *d)
+lws_plat_plugins_init(struct lws_context * context, const char * const *d)
 {
        struct lws_plugin_capability lcaps;
        struct lws_plugin *plugin;
@@ -434,65 +434,71 @@ lws_plat_plugins_init(struct lws_context * context, const char *d)
 
        uv_loop_init(&loop);
 
-       if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
-               lwsl_err("Scandir on %s failed\n", d);
-               return 1;
-       }
-
        lwsl_notice("  Plugins:\n");
 
-       while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
-               if (strlen(dent.name) < 7)
-                       continue;
-
-               lwsl_notice("   %s\n", dent.name);
+       while (d && *d) {
 
-               snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
-               if (uv_dlopen(path, &lib)) {
-                       uv_dlerror(&lib);
-                       lwsl_err("Error loading DSO: %s\n", lib.errmsg);
-                       goto bail;
-               }
-               /* we could open it, can we get his init function? */
-               m = snprintf(path, sizeof(path) - 1, "init_%s",
-                            dent.name + 3 /* snip lib... */);
-               path[m - 3] = '\0'; /* snip the .so */
-               if (uv_dlsym(&lib, path, &v)) {
-                       uv_dlerror(&lib);
-                       lwsl_err("Failed to get init on %s: %s",
-                                       dent.name, lib.errmsg);
-                       goto bail;
-               }
-               initfunc = (lws_plugin_init_func)v;
-               lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
-               m = initfunc(context, &lcaps);
-               if (m) {
-                       lwsl_err("Initializing %s failed %d\n", dent.name, m);
-                       goto skip;
+               lwsl_notice("  Scanning %s\n", *d);
+               m =uv_fs_scandir(&loop, &req, *d, 0, NULL);
+               if (m < 1) {
+                       lwsl_err("Scandir on %s failed\n", *d);
+                       return 1;
                }
 
-               plugin = lws_malloc(sizeof(*plugin));
-               if (!plugin) {
-                       lwsl_err("OOM\n");
-                       goto bail;
-               }
-               plugin->list = context->plugin_list;
-               context->plugin_list = plugin;
-               strncpy(plugin->name, dent.name, sizeof(plugin->name) - 1);
-               plugin->name[sizeof(plugin->name) - 1] = '\0';
-               plugin->lib = lib;
-               plugin->caps = lcaps;
-               context->plugin_protocol_count += lcaps.count_protocols;
-               context->plugin_extension_count += lcaps.count_extensions;
+               while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
+                       if (strlen(dent.name) < 7)
+                               continue;
 
-               continue;
+                       lwsl_notice("   %s\n", dent.name);
+
+                       snprintf(path, sizeof(path) - 1, "%s/%s", *d, dent.name);
+                       if (uv_dlopen(path, &lib)) {
+                               uv_dlerror(&lib);
+                               lwsl_err("Error loading DSO: %s\n", lib.errmsg);
+                               goto bail;
+                       }
+                       /* we could open it, can we get his init function? */
+                       m = snprintf(path, sizeof(path) - 1, "init_%s",
+                                    dent.name + 3 /* snip lib... */);
+                       path[m - 3] = '\0'; /* snip the .so */
+                       if (uv_dlsym(&lib, path, &v)) {
+                               uv_dlerror(&lib);
+                               lwsl_err("Failed to get init on %s: %s",
+                                               dent.name, lib.errmsg);
+                               goto bail;
+                       }
+                       initfunc = (lws_plugin_init_func)v;
+                       lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
+                       m = initfunc(context, &lcaps);
+                       if (m) {
+                               lwsl_err("Initializing %s failed %d\n", dent.name, m);
+                               goto skip;
+                       }
+
+                       plugin = lws_malloc(sizeof(*plugin));
+                       if (!plugin) {
+                               lwsl_err("OOM\n");
+                               goto bail;
+                       }
+                       plugin->list = context->plugin_list;
+                       context->plugin_list = plugin;
+                       strncpy(plugin->name, dent.name, sizeof(plugin->name) - 1);
+                       plugin->name[sizeof(plugin->name) - 1] = '\0';
+                       plugin->lib = lib;
+                       plugin->caps = lcaps;
+                       context->plugin_protocol_count += lcaps.count_protocols;
+                       context->plugin_extension_count += lcaps.count_extensions;
+
+                       continue;
 
 skip:
-               uv_dlclose(&lib);
+                       uv_dlclose(&lib);
+               }
+bail:
+               uv_fs_req_cleanup(&req);
+               d++;
        }
 
-bail:
-       uv_fs_req_cleanup(&req);
        uv_loop_close(&loop);
 
        return ret;
index 1f6934614dcfd99a9297bfc5934eb572337db054..82ed98d922a3f9f0a1dac28f1c32b6f544e3ead5 100644 (file)
@@ -1478,8 +1478,8 @@ struct lws_http_mount {
  * @vhost_name: VHOST: name of vhost, must match external DNS name used to
  *             access the site, like "warmcat.com" as it's used to match
  *             Host: header and / or SNI name for SSL.
- * @plugins_dir: CONTEXT: directory to scan for lws protocol plugins at
- *             context creation time
+ * @plugin_dirs: CONTEXT: NULL, or NULL-terminated array of directories to
+ *             scan for lws protocol plugins at context creation time
  * @pvo:       VHOST: pointer to optional linked list of per-vhost
  *             options made accessible to protocols
  * @keepalive_timeout: VHOST: (default = 0 = 60s) seconds to allow remote
@@ -1525,7 +1525,7 @@ struct lws_context_creation_info {
        unsigned int timeout_secs;                      /* VH */
        const char *ecdh_curve;                         /* VH */
        const char *vhost_name;                         /* VH */
-       const char *plugins_dir;                        /* context */
+       const char * const *plugin_dirs;                /* context */
        const struct lws_protocol_vhost_options *pvo;   /* VH */
        int keepalive_timeout;                          /* VH */
        const char *log_filepath;                       /* VH */
index e4894fa01e0b4c760a1296c6d931f96fab961ce9..98b6c588fc10995eaed878771472ff2a7f5d69c9 100644 (file)
@@ -306,7 +306,7 @@ static int filter(const struct dirent *ent)
 }
 
 LWS_VISIBLE int
-lws_plat_plugins_init(struct lws_context * context, const char *d)
+lws_plat_plugins_init(struct lws_context * context, const char * const *d)
 {
        struct lws_plugin_capability lcaps;
        struct lws_plugin *plugin;
@@ -316,70 +316,73 @@ lws_plat_plugins_init(struct lws_context * context, const char *d)
        char path[256];
        void *l;
 
+       lwsl_notice("  Plugins:\n");
 
-       n = scandir(d, &namelist, filter, alphasort);
-       if (n < 0) {
-               lwsl_err("Scandir on %s failed\n", d);
-               return 1;
-       }
+       while (d && *d) {
+               n = scandir(*d, &namelist, filter, alphasort);
+               if (n < 0) {
+                       lwsl_err("Scandir on %s failed\n", *d);
+                       return 1;
+               }
 
-       lwsl_notice("  Plugins:\n");
+               for (i = 0; i < n; i++) {
+                       if (strlen(namelist[i]->d_name) < 7)
+                               goto inval;
 
-       for (i = 0; i < n; i++) {
-               if (strlen(namelist[i]->d_name) < 7)
-                       goto inval;
+                       lwsl_notice("   %s\n", namelist[i]->d_name);
 
-               lwsl_notice("   %s\n", namelist[i]->d_name);
+                       snprintf(path, sizeof(path) - 1, "%s/%s", *d,
+                                namelist[i]->d_name);
+                       l = dlopen(path, RTLD_NOW);
+                       if (!l) {
+                               lwsl_err("Error loading DSO: %s\n", dlerror());
+                               while (i++ < n)
+                                       free(namelist[i]);
+                               goto bail;
+                       }
+                       /* we could open it, can we get his init function? */
+                       m = snprintf(path, sizeof(path) - 1, "init_%s",
+                                    namelist[i]->d_name + 3 /* snip lib... */);
+                       path[m - 3] = '\0'; /* snip the .so */
+                       initfunc = dlsym(l, path);
+                       if (!initfunc) {
+                               lwsl_err("Failed to get init on %s: %s",
+                                               namelist[i]->d_name, dlerror());
+                               dlclose(l);
+                       }
+                       lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
+                       m = initfunc(context, &lcaps);
+                       if (m) {
+                               lwsl_err("Initializing %s failed %d\n",
+                                       namelist[i]->d_name, m);
+                               dlclose(l);
+                               goto skip;
+                       }
 
-               snprintf(path, sizeof(path) - 1, "%s/%s", d,
-                        namelist[i]->d_name);
-               l = dlopen(path, RTLD_NOW);
-               if (!l) {
-                       lwsl_err("Error loading DSO: %s\n", dlerror());
-                       while (i++ < n)
-                               free(namelist[i]);
-                       goto bail;
-               }
-               /* we could open it, can we get his init function? */
-               m = snprintf(path, sizeof(path) - 1, "init_%s",
-                            namelist[i]->d_name + 3 /* snip lib... */);
-               path[m - 3] = '\0'; /* snip the .so */
-               initfunc = dlsym(l, path);
-               if (!initfunc) {
-                       lwsl_err("Failed to get init on %s: %s",
-                                       namelist[i]->d_name, dlerror());
-                       dlclose(l);
-               }
-               lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
-               m = initfunc(context, &lcaps);
-               if (m) {
-                       lwsl_err("Initializing %s failed %d\n",
-                               namelist[i]->d_name, m);
-                       dlclose(l);
-                       goto skip;
-               }
+                       plugin = lws_malloc(sizeof(*plugin));
+                       if (!plugin) {
+                               lwsl_err("OOM\n");
+                               goto bail;
+                       }
+                       plugin->list = context->plugin_list;
+                       context->plugin_list = plugin;
+                       strncpy(plugin->name, namelist[i]->d_name, sizeof(plugin->name) - 1);
+                       plugin->name[sizeof(plugin->name) - 1] = '\0';
+                       plugin->l = l;
+                       plugin->caps = lcaps;
+                       context->plugin_protocol_count += lcaps.count_protocols;
+                       context->plugin_extension_count += lcaps.count_extensions;
+
+                       free(namelist[i]);
+                       continue;
 
-               plugin = lws_malloc(sizeof(*plugin));
-               if (!plugin) {
-                       lwsl_err("OOM\n");
-                       goto bail;
+       skip:
+                       dlclose(l);
+       inval:
+                       free(namelist[i]);
                }
-               plugin->list = context->plugin_list;
-               context->plugin_list = plugin;
-               strncpy(plugin->name, namelist[i]->d_name, sizeof(plugin->name) - 1);
-               plugin->name[sizeof(plugin->name) - 1] = '\0';
-               plugin->l = l;
-               plugin->caps = lcaps;
-               context->plugin_protocol_count += lcaps.count_protocols;
-               context->plugin_extension_count += lcaps.count_extensions;
-
-               free(namelist[i]);
-               continue;
-
-skip:
-               dlclose(l);
-inval:
-               free(namelist[i]);
+               free(namelist);
+               d++;
        }
 
 bail:
@@ -707,8 +710,8 @@ lws_plat_init(struct lws_context *context,
        context->fops.write     = _lws_plat_file_write;
 
 #ifdef LWS_WITH_PLUGINS
-       if (info->plugins_dir)
-               lws_plat_plugins_init(context, info->plugins_dir);
+       if (info->plugin_dirs)
+               lws_plat_plugins_init(context, info->plugin_dirs);
 #endif
 
        return 0;
index 91f4d7578e69fde5aed24f530c4fe8c88ad243df..df2bbf647921ba81baa599dcd6ef14e1fab9153d 100644 (file)
@@ -770,7 +770,7 @@ LWS_EXTERN void
 lws_libuv_closehandle(struct lws *wsi);
 
 LWS_VISIBLE LWS_EXTERN int
-lws_plat_plugins_init(struct lws_context * context, const char *d);
+lws_plat_plugins_init(struct lws_context * context, const char * const *d);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_plat_plugins_destroy(struct lws_context * context);
index 31d38f85f1c2846ab7f2476c43a11b866b62b23c..f222ed640b1042991337c23caa3b267e77d8b00d 100644 (file)
@@ -27,6 +27,7 @@ static const char * const paths_global[] = {
        "global.count-threads",
        "global.init-ssl",
        "global.server-string",
+       "global.plugin-dir"
 };
 
 enum lejp_global_paths {
@@ -35,6 +36,7 @@ enum lejp_global_paths {
        LEJPGP_COUNT_THREADS,
        LWJPGP_INIT_SSL,
        LEJPGP_SERVER_STRING,
+       LEJPGP_PLUGIN_DIR
 };
 
 static const char * const paths_vhosts[] = {
@@ -91,6 +93,8 @@ enum lejp_vhost_paths {
        LEJPVP_KEEPALIVE_TIMEOUT,
 };
 
+#define MAX_PLUGIN_DIRS 10
+
 struct jpargs {
        struct lws_context_creation_info *info;
        struct lws_context *context;
@@ -101,6 +105,8 @@ struct jpargs {
 
        struct lws_protocol_vhost_options *pvo;
        struct lws_http_mount m;
+       const char **plugin_dirs;
+       int count_plugin_dirs;
 };
 
 static void *
@@ -154,6 +160,13 @@ lejp_globals_cb(struct lejp_ctx *ctx, char reason)
        case LEJPGP_SERVER_STRING:
                a->info->server_string = a->p;
                break;
+       case LEJPGP_PLUGIN_DIR:
+               if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
+                       lwsl_err("Too many plugin dirs\n");
+                       return -1;
+               }
+               a->plugin_dirs[a->count_plugin_dirs++] = a->p;
+               break;
 
        default:
                return 0;
@@ -537,12 +550,27 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
                         char **cs, int *len)
 {
        struct jpargs a;
+       const char * const *old = info->plugin_dirs;
+
+       memset(&a, 0, sizeof(a));
 
        a.info = info;
        a.p = *cs;
        a.end = (a.p + *len) - 1;
        a.valid = 0;
 
+       lwsws_align(&a);
+       info->plugin_dirs = (void *)a.p;
+       a.plugin_dirs = (void *)a.p; /* writeable version */
+       a.p += MAX_PLUGIN_DIRS * sizeof(void *);
+
+       /* copy any default paths */
+
+       while (old && *old) {
+               a.plugin_dirs[a.count_plugin_dirs++] = *old;
+               old++;
+       }
+
        if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
                             ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
                return 1;
@@ -550,6 +578,8 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
                               ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
                return 1;
 
+       a.plugin_dirs[a.count_plugin_dirs] = NULL;
+
        *cs = a.p;
        *len = a.end - a.p;
 
@@ -563,6 +593,8 @@ lwsws_get_config_vhosts(struct lws_context *context,
 {
        struct jpargs a;
 
+       memset(&a, 0, sizeof(a));
+
        a.info = info;
        a.p = *cs;
        a.end = a.p + *len;
index 8d84552b84cbdc701ee146bb76ef9fc44773d74c..2a7579fc25f1c2b13eeb01e23ae984fa6ca61623 100644 (file)
@@ -80,6 +80,11 @@ static const struct lws_extension exts[] = {
        { NULL, NULL, NULL /* terminator */ }
 };
 
+static const char * const plugin_dirs[] = {
+               INSTALL_DATADIR"/libwebsockets-test-server/plugins/",
+               NULL
+};
+
 static struct option options[] = {
        { "help",       no_argument,            NULL, 'h' },
        { "debug",      required_argument,      NULL, 'd' },
@@ -107,6 +112,8 @@ void signal_cb(uv_signal_t *watcher, int signum)
 }
 #endif
 
+
+
 int main(int argc, char **argv)
 {
        struct lws_context_creation_info info;
@@ -184,8 +191,7 @@ int main(int argc, char **argv)
                              LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
                              LWS_SERVER_OPTION_LIBUV;
 
-       info.plugins_dir = INSTALL_DATADIR"/libwebsockets-test-server/plugins/";
-
+       info.plugin_dirs = plugin_dirs;
        lwsl_notice("Using config dir: \"%s\"\n", config_dir);
 
        /*
index 28a9264a52cae7c4ae6f3572ab4dbbdd510a566e..8702049bbf26fb849e993179745dbb0fbd9fc44f 100644 (file)
@@ -155,6 +155,11 @@ static const struct option options[] = {
        { NULL, 0, 0, 0 }
 };
 
+static const char * const plugin_dirs[] = {
+               INSTALL_DATADIR"/libwebsockets-test-server/plugins/",
+               NULL
+};
+
 int main(int argc, char **argv)
 {
        struct lws_context_creation_info info;
@@ -344,7 +349,7 @@ int main(int argc, char **argv)
                               "!AES256-SHA256";
 
        /* tell lws to look for protocol plugins here */
-       info.plugins_dir = INSTALL_DATADIR"/libwebsockets-test-server/plugins/";
+       info.plugin_dirs = plugin_dirs;
 
        /* tell lws about our mount we want */
        info.mounts = &mount;