lwsws conf and plugins convert to libuv apis
authorAndy Green <andy@warmcat.com>
Fri, 8 Apr 2016 23:22:40 +0000 (07:22 +0800)
committerAndy Green <andy@warmcat.com>
Wed, 13 Apr 2016 03:53:40 +0000 (11:53 +0800)
After discussion here

https://libwebsockets.org/pipermail/libwebsockets/2016-April/002268.html

scandir usage in

 - lwsws conf.c
 - lws plugin support

and

 - lws plugin apis for dl

are converted to us libuv apis so they can work cross-platform easily.

lws itself remains not requiring libuv, although it's an option.

 - LWS_WITH_LWSWS
 - LWS_WITH_PLUGINS

now force LWS_WITH_LIBUV if selected... both of these are new features
only in master atm and both are off by default in CMake.

There's a complication libuv can be too old to offer the necessary apis,
this is the case in Travis Trusty instance.  In that case, UV_VERSION_MAJOR ==0,
then the unix-only plugin implementation is used instead.

Signed-off-by: Andy Green <andy@warmcat.com>
CMakeLists.txt
lib/libuv.c
lib/libwebsockets.h
lib/lws-plat-unix.c
lib/private-libwebsockets.h
lwsws/conf.c

index 9b5d2ac..b74913e 100644 (file)
@@ -100,6 +100,11 @@ if (LWS_WITH_LWSWS)
  set(LWS_WITH_LIBUV 1)
 endif()
 
+if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV)
+message(STATUS "LWS_WITH_PLUGINS --> Enabling LWS_WITH_LIBUV")
+ set(LWS_WITH_LIBUV 1)
+endif()
+
 if (DEFINED YOTTA_WEBSOCKETS_VERSION_STRING)
 
 set(LWS_WITH_SHARED OFF)
@@ -118,9 +123,6 @@ endif()
 if (WIN32)
 # this implies no pthreads in the lib
 set(LWS_MAX_SMP 1)
-
-# plugin stuff not implemented in win32 plat
-set (LWS_WITH_PLUGINS OFF)
 endif()
 
 
index 3cf4a94..89ee690 100644 (file)
@@ -408,3 +408,134 @@ lws_libuv_closehandle(struct lws *wsi)
        if (context->requested_kill && context->count_wsi_allocated == 0)
                lws_libuv_kill(context);
 }
+
+#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
+
+LWS_VISIBLE int
+lws_plat_plugins_init(struct lws_context * context, const char *d)
+{
+       struct lws_plugin_capability lcaps;
+       struct lws_plugin *plugin;
+       lws_plugin_init_func initfunc;
+       int m, ret = 0;
+       void *v;
+       uv_dirent_t dent;
+       uv_fs_t req;
+       char path[256];
+       uv_loop_t loop;
+       uv_lib_t lib;
+
+       lib.errmsg = NULL;
+       lib.handle = NULL;
+
+       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);
+
+               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);
+       }
+
+bail:
+       uv_fs_req_cleanup(&req);
+       uv_loop_close(&loop);
+
+       return ret;
+
+}
+
+LWS_VISIBLE int
+lws_plat_plugins_destroy(struct lws_context * context)
+{
+       struct lws_plugin *plugin = context->plugin_list, *p;
+       lws_plugin_destroy_func func;
+       char path[256];
+       void *v;
+       int m;
+
+       if (!plugin)
+               return 0;
+
+       lwsl_notice("%s\n", __func__);
+
+       while (plugin) {
+               p = plugin;
+               m = snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
+               path[m - 3] = '\0';
+
+               if (uv_dlsym(&plugin->lib, path, &v)) {
+                       uv_dlerror(&plugin->lib);
+                       lwsl_err("Failed to get init on %s: %s",
+                                       plugin->name, plugin->lib.errmsg);
+               } else {
+                       func = (lws_plugin_destroy_func)v;
+                       m = func(context);
+                       if (m)
+                               lwsl_err("Destroying %s failed %d\n",
+                                               plugin->name, m);
+               }
+
+               uv_dlclose(&p->lib);
+               plugin = p->list;
+               p->list = NULL;
+               free(p);
+       }
+
+       context->plugin_list = NULL;
+
+       return 0;
+}
+
+#endif
+
index 36a1d40..13d8bcc 100644 (file)
@@ -1305,6 +1305,11 @@ struct lws_extension {
         * This is part of the ABI, don't needlessly break compatibility */
 };
 
+
+#ifdef LWS_WITH_PLUGINS
+
+/* PLUGINS implies LIBUV */
+
 #define LWS_PLUGIN_API_MAGIC 180
 
 struct lws_plugin_capability {
@@ -1320,11 +1325,17 @@ typedef int (*lws_plugin_init_func)(struct lws_context *,
 typedef int (*lws_plugin_destroy_func)(struct lws_context *);
 struct lws_plugin {
        struct lws_plugin *list;
+#if (UV_VERSION_MAJOR > 0)
+       uv_lib_t lib;
+#else
        void *l;
+#endif
        char name[64];
        struct lws_plugin_capability caps;
 };
 
+#endif
+
 /*
  * The internal exts are part of the public abi
  * If we add more extensions, publish the callback here  ------v
index c726e9e..eb2f762 100644 (file)
@@ -300,6 +300,12 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
 
 #ifdef LWS_WITH_PLUGINS
 
+#if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
+
+/* libuv.c implements these in a cross-platform way */
+
+#else
+
 static int filter(const struct dirent *ent)
 {
        if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
@@ -322,7 +328,7 @@ lws_plat_plugins_init(struct lws_context * context, const char *d)
 
        n = scandir(d, &namelist, filter, alphasort);
        if (n < 0) {
-               lwsl_err("Scandir on %d failed\n", d);
+               lwsl_err("Scandir on %s failed\n", d);
                return 1;
        }
 
@@ -431,6 +437,7 @@ next:
 }
 
 #endif
+#endif
 
 
 static void
index 4ab471f..35f3ed6 100644 (file)
@@ -763,6 +763,12 @@ lws_close_free_wsi_final(struct lws *wsi);
 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_VISIBLE LWS_EXTERN int
+lws_plat_plugins_destroy(struct lws_context * context);
+
 enum {
        LWS_EV_READ = (1 << 0),
        LWS_EV_WRITE = (1 << 1),
index 0f02360..c720d86 100644 (file)
@@ -345,6 +345,41 @@ lwsws_get_config(void *user, const char *f, const char * const *paths,
        return 0;
 }
 
+#if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
+
+static int
+lwsws_get_config_d(void *user, const char *d, const char * const *paths,
+                  int count_paths, lejp_callback cb)
+{
+       uv_dirent_t dent;
+       uv_fs_t req;
+       char path[256];
+       int ret = 0;
+       uv_loop_t loop;
+
+       uv_loop_init(&loop);
+
+       if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
+               lwsl_err("Scandir on %s failed\n", d);
+               return 1;
+       }
+
+       while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
+               snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
+               ret = lwsws_get_config(user, path, paths, count_paths, cb);
+               if (ret)
+                       goto bail;
+       }
+
+bail:
+       uv_fs_req_cleanup(&req);
+       uv_loop_close(&loop);
+
+       return ret;
+}
+
+#else
+
 #ifndef _WIN32
 static int filter(const struct dirent *ent)
 {
@@ -390,6 +425,8 @@ bail:
 #endif
 }
 
+#endif
+
 int
 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
                         char **cs, int *len)