From 0a183545b29b6a91c41e29ce8fb7fc6c810e493e Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sat, 9 Apr 2016 07:22:40 +0800 Subject: [PATCH] lwsws conf and plugins convert to libuv apis 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 --- CMakeLists.txt | 8 ++- lib/libuv.c | 131 ++++++++++++++++++++++++++++++++++++++++++++ lib/libwebsockets.h | 11 ++++ lib/lws-plat-unix.c | 9 ++- lib/private-libwebsockets.h | 6 ++ lwsws/conf.c | 37 +++++++++++++ 6 files changed, 198 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b5d2ac..b74913e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/lib/libuv.c b/lib/libuv.c index 3cf4a94..89ee690 100644 --- a/lib/libuv.c +++ b/lib/libuv.c @@ -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 + diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 36a1d40..13d8bcc 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -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 diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index c726e9e..eb2f762 100644 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -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 diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 4ab471f..35f3ed6 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -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), diff --git a/lwsws/conf.c b/lwsws/conf.c index 0f02360..c720d86 100644 --- a/lwsws/conf.c +++ b/lwsws/conf.c @@ -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) -- 2.7.4