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 <andy@warmcat.com>
This commit is contained in:
Andy Green 2016-04-09 07:22:40 +08:00
parent e01a551a17
commit 0a183545b2
6 changed files with 198 additions and 4 deletions

View 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()

View 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

View 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

View 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

View 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),

View 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)