diff --git a/.sai.json b/.sai.json index 127c1c0f3..4eb140cee 100644 --- a/.sai.json +++ b/.sai.json @@ -6,37 +6,37 @@ "platforms": { "linux-debian-buster/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-debian-buster/x86-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-debian-sid/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-debian-sid/x86-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-ubuntu-1804/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-ubuntu-2004/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-fedora-32/x86_64-amd/gcc": { - "build": "rm -rf build destdir ; mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "rm -rf build destdir ; mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-gentoo/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G ZIP\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-centos-7/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-centos-8/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc": { - "build": "mkdir build;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j3 && make -j DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}", + "build": "mkdir build;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j3 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}", "default": false }, "linux-android/aarch64/llvm": { @@ -48,10 +48,10 @@ "default": false }, "netbsd-OSX-bigsur/x86_64-intel-i3/llvm": { - "build": "mkdir build destdir; cd build; export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=10.15 ; cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/opt/openssl@1.1/include -DLWS_OPENSSL_LIBRARIES=\"/usr/local/opt/openssl/lib/libssl.dylib;/usr/local/opt/openssl/lib/libcrypto.dylib\" ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir; cd build; export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=10.15 ; cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/opt/openssl@1.1/include -DLWS_OPENSSL_LIBRARIES=\"/usr/local/opt/openssl/lib/libssl.dylib;/usr/local/opt/openssl/lib/libcrypto.dylib\" ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}" }, "netbsd-OSX-bigsur/aarch64-apple-m1/llvm": { - "build": "mkdir build destdir; cd build; export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=10.15 ; cmake .. -DLWS_WITH_SUL_DEBUGGING=1 -DCMAKE_SYSTEM_PREFIX_PATH=/opt/homebrew -DLWS_OPENSSL_INCLUDE_DIRS=/opt/homebrew/Cellar/openssl@1.1/1.1.1h/include '-DLWS_OPENSSL_LIBRARIES=/opt/homebrew/Cellar/openssl@1.1/1.1.1h/lib/libssl.dylib;/opt/homebrew/Cellar/openssl@1.1/1.1.1h/lib/libcrypto.dylib' -DLWS_WITH_MINIMAL_EXAMPLES=1 ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "mkdir build destdir; cd build; export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=10.15 ; cmake .. -DLWS_WITH_SUL_DEBUGGING=1 -DCMAKE_SYSTEM_PREFIX_PATH=/opt/homebrew -DLWS_OPENSSL_INCLUDE_DIRS=/opt/homebrew/Cellar/openssl@1.1/1.1.1h/include '-DLWS_OPENSSL_LIBRARIES=/opt/homebrew/Cellar/openssl@1.1/1.1.1h/lib/libssl.dylib;/opt/homebrew/Cellar/openssl@1.1/1.1.1h/lib/libcrypto.dylib' -DLWS_WITH_MINIMAL_EXAMPLES=1 ${cmake} && make -j6 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}" }, "freertos-linkit/arm32-m4-mt7697-usi/gcc": { "build": "mkdir build;cd build;export CCACHE_DISABLE=1;cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/tmp -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-linkit.cmake -DLWS_PLAT_FREERTOS=1 -DLWS_WITH_ZLIB=0 -DLWS_WITHOUT_EXTENSIONS=1 -DLWS_WITH_ZIP_FOPS=0 -DLWS_WITH_HTTP_STREAM_COMPRESSION=0 -DLWS_WITH_MBEDTLS=1 -DLWS_WITH_FILE_OPS=0 ${cmake};make -j", @@ -80,14 +80,14 @@ "default": false }, "linux-fedora-32/riscv64-virt/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j12 && make -j12 DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}", + "build": "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j12 && rm -rf ../destdir && make -j12 DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}", "default": false }, "freebsd-12/x86_64-amd/llvm": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;cmake .. ${cmake} && make -j3 && make -j3 DESTDIR=../destdir install" + "build": "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;cmake .. ${cmake} && make -j3 && rm -rf ../destdir && make -j3 DESTDIR=../destdir install" }, "netbsd/aarch64BE-bcm2837-a53/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;cmake .. ${cmake};make -j6 && make -j6 DESTDIR=../destdir install && /usr/pkg/bin/ctest -j4 --output-on-failure", + "build": "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;cmake .. ${cmake};make -j6 && rm -rf ../destdir && make -j6 DESTDIR=../destdir install && /usr/pkg/bin/ctest -j3 --output-on-failure", "default": false } }, diff --git a/include/libwebsockets/lws-protocols-plugins.h b/include/libwebsockets/lws-protocols-plugins.h index 0c966667f..4ad813c35 100644 --- a/include/libwebsockets/lws-protocols-plugins.h +++ b/include/libwebsockets/lws-protocols-plugins.h @@ -194,7 +194,7 @@ lws_pvo_get_str(void *in, const char *name, const char **result); LWS_VISIBLE LWS_EXTERN int lws_protocol_init(struct lws_context *context); -#define LWS_PLUGIN_API_MAGIC 190 +#define LWS_PLUGIN_API_MAGIC 191 /* * Abstract plugin header for any kind of plugin class, always at top of @@ -210,6 +210,7 @@ lws_protocol_init(struct lws_context *context); typedef struct lws_plugin_header { const char *name; const char *_class; + const char *lws_build_hash; /* set to LWS_BUILD_HASH */ unsigned int api_magic; /* set to LWS_PLUGIN_API_MAGIC at plugin build time */ diff --git a/lib/core-net/vhost.c b/lib/core-net/vhost.c index 12198de48..27862abb5 100644 --- a/lib/core-net/vhost.c +++ b/lib/core-net/vhost.c @@ -237,6 +237,9 @@ lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, { int n = 0; + if (!vhost || !prot) + return NULL; + /* allocate the vh priv array only on demand */ if (!vhost->protocol_vh_privs) { vhost->protocol_vh_privs = (void **)lws_zalloc( @@ -377,7 +380,7 @@ lws_protocol_init_vhost(struct lws_vhost *vh, int *any) if (vh->protocols[n].callback((struct lws *)plwsa, LWS_CALLBACK_PROTOCOL_INIT, NULL, (void *)pvo, 0)) { - if (vh->protocol_vh_privs[n]) { + if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) { lws_free(vh->protocol_vh_privs[n]); vh->protocol_vh_privs[n] = NULL; } @@ -401,14 +404,14 @@ int lws_protocol_init(struct lws_context *context) { struct lws_vhost *vh = context->vhost_list; - int any = 0; + int any = 0, r = 0; if (context->doing_protocol_init) return 0; context->doing_protocol_init = 1; - lwsl_info("%s\n", __func__); + lwsl_notice("%s\n", __func__); while (vh) { @@ -417,18 +420,26 @@ lws_protocol_init(struct lws_context *context) (lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT))) goto next; - if (lws_protocol_init_vhost(vh, &any)) - return 1; + if (lws_protocol_init_vhost(vh, &any)) { + lwsl_warn("%s: init vhost %s failed\n", __func__, vh->name); + r = -1; + } next: vh = vh->vhost_next; } context->doing_protocol_init = 0; - if (!context->protocol_init_done && lws_finalize_startup(context)) - return 1; + if (r) + lwsl_warn("%s: some protocols did not init\n", __func__); - context->protocol_init_done = 1; + if (!context->protocol_init_done) { + + context->protocol_init_done = 1; + lws_finalize_startup(context); + + return 0; + } #if defined(LWS_WITH_SERVER) if (any) { diff --git a/lib/core/context.c b/lib/core/context.c index 3be5f1617..a2f62fb26 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -486,47 +486,7 @@ lws_create_context(const struct lws_context_creation_info *info) if (!lws_check_opt(info->options, map[n].flag)) continue; - /* - * Check LD_LIBRARY_PATH override path first if present - */ - - if (ld_env) { - char temp[128]; - struct lws_tokenize ts; - const char * tok[2] = { temp, NULL }; - - memset(&ts, 0, sizeof(ts)); - ts.start = ld_env; - ts.len = strlen(ld_env); - ts.flags = LWS_TOKENIZE_F_SLASH_NONTERM | - LWS_TOKENIZE_F_DOT_NONTERM | - LWS_TOKENIZE_F_MINUS_NONTERM | - LWS_TOKENIZE_F_NO_INTEGERS | - LWS_TOKENIZE_F_NO_FLOATS; - - do { - ts.e = (int8_t)lws_tokenize(&ts); - if (ts.e != LWS_TOKZE_TOKEN) - continue; - - lws_strnncpy(temp, ts.token, - ts.token_len, - sizeof(temp)); - - if (!lws_plugins_init( - &evlib_plugin_list, tok, - "lws_evlib_plugin", - map[n].name, - NULL, NULL)) { - ok = 1; - break; - } - - } while (ts.e > 0); - } - - if (!ok && - !lws_plugins_init(&evlib_plugin_list, + if (!lws_plugins_init(&evlib_plugin_list, dlist, "lws_evlib_plugin", map[n].name, NULL, NULL)) ok = 1; @@ -918,7 +878,7 @@ lws_create_context(const struct lws_context_creation_info *info) context->timeout_secs = info->timeout_secs; else #endif - context->timeout_secs = 10; + context->timeout_secs = 15; #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) if (info->max_http_header_data) diff --git a/lib/event-libs/glib/glib.c b/lib/event-libs/glib/glib.c index c34108c4d..8ff3703a8 100644 --- a/lib/event-libs/glib/glib.c +++ b/lib/event-libs/glib/glib.c @@ -506,6 +506,7 @@ const lws_plugin_evlib_t evlib_glib = { .hdr = { "glib event loop", "lws_evlib_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c index ae71ee4ff..a8583b8f5 100644 --- a/lib/event-libs/libev/libev.c +++ b/lib/event-libs/libev/libev.c @@ -439,6 +439,7 @@ const lws_plugin_evlib_t evlib_ev = { .hdr = { "libev event loop", "lws_evlib_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index 2c99b777d..0311b9ca0 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -516,6 +516,7 @@ const lws_plugin_evlib_t evlib_event = { .hdr = { "libevent event loop", "lws_evlib_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index b9fae034a..3e371c1b4 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -895,6 +895,7 @@ const lws_plugin_evlib_t evlib_uv = { .hdr = { "libuv event loop", "lws_evlib_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/lib/event-libs/poll/poll.c b/lib/event-libs/poll/poll.c index 006d0f5ef..f3685bf28 100644 --- a/lib/event-libs/poll/poll.c +++ b/lib/event-libs/poll/poll.c @@ -53,6 +53,7 @@ const lws_plugin_evlib_t evlib_poll = { .hdr = { "poll", "lws_evlib_plugin", + "n/a", LWS_PLUGIN_API_MAGIC }, diff --git a/lib/event-libs/sdevent/sdevent.c b/lib/event-libs/sdevent/sdevent.c index 3f49fe01a..a89395863 100644 --- a/lib/event-libs/sdevent/sdevent.c +++ b/lib/event-libs/sdevent/sdevent.c @@ -424,6 +424,7 @@ const lws_plugin_evlib_t evlib_sd = { .hdr = { "systemd event loop", "lws_evlib_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/lib/misc/dir.c b/lib/misc/dir.c index c0a4f7718..7d113c27e 100644 --- a/lib/misc/dir.c +++ b/lib/misc/dir.c @@ -326,7 +326,6 @@ lws_plugins_dir_cb(const char *dirpath, void *user, struct lws_dir_entry *lde) return 0; /* keep going */ lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name); - lwsl_notice(" %s\n", path); pl = lws_plat_dlopen(pa->pplugin, path, base, pa->_class, pa->each, pa->each_user); @@ -347,6 +346,7 @@ lws_plugins_init(struct lws_plugin **pplugin, const char * const *d, each_plugin_cb_t each, void *each_user) { struct lws_plugins_args pa; + char *ld_env; int ret = 1; pa.pplugin = pplugin; @@ -355,6 +355,40 @@ lws_plugins_init(struct lws_plugin **pplugin, const char * const *d, pa.each_user = each_user; pa.filter = filter; + /* + * Check LD_LIBRARY_PATH override path first if present + */ + + ld_env = getenv("LD_LIBRARY_PATH"); + if (ld_env) { + char temp[128]; + struct lws_tokenize ts; + + memset(&ts, 0, sizeof(ts)); + ts.start = ld_env; + ts.len = strlen(ld_env); + ts.flags = LWS_TOKENIZE_F_SLASH_NONTERM | + LWS_TOKENIZE_F_DOT_NONTERM | + LWS_TOKENIZE_F_MINUS_NONTERM | + LWS_TOKENIZE_F_NO_INTEGERS | + LWS_TOKENIZE_F_NO_FLOATS; + + do { + ts.e = (int8_t)lws_tokenize(&ts); + if (ts.e != LWS_TOKZE_TOKEN) + continue; + + lws_strnncpy(temp, ts.token, + ts.token_len, + sizeof(temp)); + + lwsl_info("%s: trying %s\n", __func__, temp); + if (!lws_dir(temp, &pa, lws_plugins_dir_cb)) + ret = 0; + + } while (ts.e > 0); + } + while (d && *d) { lwsl_info("%s: trying %s\n", __func__, *d); if (!lws_dir(*d, &pa, lws_plugins_dir_cb)) diff --git a/lib/plat/unix/unix-init.c b/lib/plat/unix/unix-init.c index 98de12145..64cec8a53 100644 --- a/lib/plat/unix/unix-init.c +++ b/lib/plat/unix/unix-init.c @@ -152,10 +152,23 @@ lws_plat_init(struct lws_context *context, } #if defined(LWS_WITH_PLUGINS) - if (info->plugin_dirs) - lws_plugins_init(&context->plugin_list, info->plugin_dirs, - "lws_protocol_plugin", NULL, - protocol_plugin_cb, context); + { + char *ld_env = getenv("LD_LIBRARY_PATH"); + + if (ld_env) { + const char *pp[2] = { ld_env, NULL }; + + lws_plugins_init(&context->plugin_list, pp, + "lws_protocol_plugin", NULL, + protocol_plugin_cb, context); + } + + if (info->plugin_dirs) + lws_plugins_init(&context->plugin_list, + info->plugin_dirs, + "lws_protocol_plugin", NULL, + protocol_plugin_cb, context); + } #endif diff --git a/lib/plat/unix/unix-plugins.c b/lib/plat/unix/unix-plugins.c index c3d9663ba..43e9d018f 100644 --- a/lib/plat/unix/unix-plugins.c +++ b/lib/plat/unix/unix-plugins.c @@ -46,6 +46,8 @@ lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, /* [lib]...[.so] */ return NULL; + lwsl_info(" trying %s\n", libpath); + l = dlopen(libpath, RTLD_NOW); if (!l) { lwsl_err("%s: Error loading DSO: %s\n", __func__, dlerror()); @@ -62,21 +64,39 @@ lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, hdr = (const lws_plugin_header_t *)dlsym(l, sym); if (!hdr) { - lwsl_err("%s: Failed to get export '%s' from %s: %s\n", + lwsl_warn("%s: Failed to get export '%s' from %s: %s\n", __func__, sym, libpath, dlerror()); goto bail; } if (hdr->api_magic != LWS_PLUGIN_API_MAGIC) { - lwsl_err("%s: plugin %s has outdated api %d (vs %d)\n", + lwsl_info("%s: plugin %s has outdated api %d (vs %d)\n", __func__, libpath, hdr->api_magic, LWS_PLUGIN_API_MAGIC); goto bail; } + if (strcmp(hdr->lws_build_hash, LWS_BUILD_HASH)) + goto bail; + if (strcmp(hdr->_class, _class)) goto bail; + /* + * We don't already have one of these, right? + */ + + pin = *pplugin; + while (pin) { + if (!strcmp(pin->hdr->name, hdr->name)) + goto bail; + pin = pin->list; + } + + /* + * OK let's bring it in + */ + pin = lws_malloc(sizeof(*pin), __func__); if (!pin) goto bail; @@ -90,6 +110,8 @@ lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, if (each) each(pin, each_user); + lwsl_notice(" %s\n", libpath); + return hdr; bail: diff --git a/lib/plat/unix/unix-service.c b/lib/plat/unix/unix-service.c index e076a8871..c11bbad80 100644 --- a/lib/plat/unix/unix-service.c +++ b/lib/plat/unix/unix-service.c @@ -135,6 +135,9 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) timeout_us /= LWS_US_PER_MS; /* ms now */ +#if defined(LWS_WITH_SYS_METRICS) + a = lws_now_usecs() - b; +#endif vpt->inside_poll = 1; lws_memory_barrier(); n = poll(pt->fds, pt->fds_count, (int)timeout_us /* ms now */ ); diff --git a/lib/plat/windows/windows-plugins.c b/lib/plat/windows/windows-plugins.c index 98e84593d..b2153d677 100644 --- a/lib/plat/windows/windows-plugins.c +++ b/lib/plat/windows/windows-plugins.c @@ -72,15 +72,33 @@ lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, hdr = (const lws_plugin_header_t *)v; if (hdr->api_magic != LWS_PLUGIN_API_MAGIC) { - lwsl_err("%s: plugin %s has outdated api %d (vs %d)\n", + lwsl_info("%s: plugin %s has outdated api %d (vs %d)\n", __func__, libpath, hdr->api_magic, LWS_PLUGIN_API_MAGIC); goto bail; } + if (strcmp(hdr->lws_build_hash, LWS_BUILD_HASH)) + goto bail; + if (strcmp(hdr->_class, _class)) goto bail; + /* + * We don't already have one of these, right? + */ + + pin = *pplugin; + while (pin) { + if (!strcmp(pin->hdr->name, hdr->name)) + goto bail; + pin = pin->list; + } + + /* + * OK let's bring it in + */ + pin = lws_malloc(sizeof(*pin), __func__); if (!pin) goto bail; diff --git a/minimal-examples/http-client/minimal-http-client-multi/CMakeLists.txt b/minimal-examples/http-client/minimal-http-client-multi/CMakeLists.txt index 6e623c6c3..2544b6e94 100644 --- a/minimal-examples/http-client/minimal-http-client-multi/CMakeLists.txt +++ b/minimal-examples/http-client/minimal-http-client-multi/CMakeLists.txt @@ -109,7 +109,7 @@ endif() # add_test(NAME http-client-multi COMMAND lws-minimal-http-client-multi - -l --port ${PORT_HCM_SRV}) + -l --port ${PORT_HCM_SRV} -d 1151) add_test(NAME http-client-multi-h1 COMMAND lws-minimal-http-client-multi --h1 -l --port ${PORT_HCM_SRV} -d1151) add_test(NAME http-client-multi-pipe COMMAND lws-minimal-http-client-multi diff --git a/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c b/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c index c9fb05540..626e28049 100644 --- a/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c +++ b/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c @@ -285,6 +285,7 @@ lws_try_client_connection(struct lws_client_connect_info *i, int m) if (!lws_client_connect_via_info(i)) { failed++; + lwsl_user("%s: failed: conn idx %d\n", __func__, m); if (++completed == count) { lwsl_user("Done: failed: %d\n", failed); lws_context_destroy(context); diff --git a/minimal-examples/http-client/minimal-http-client-post/CMakeLists.txt b/minimal-examples/http-client/minimal-http-client-post/CMakeLists.txt index c02fe8a46..f67ef8ef0 100644 --- a/minimal-examples/http-client/minimal-http-client-post/CMakeLists.txt +++ b/minimal-examples/http-client/minimal-http-client-post/CMakeLists.txt @@ -14,6 +14,7 @@ require_lws_config(LWS_WITH_CLIENT 1 requirements) if (requirements) add_executable(${SAMP} ${SRCS}) + find_program(VALGRIND "valgrind") # # instantiate the server per sai builder instance, they are running in the same @@ -44,15 +45,27 @@ if (WIN32) add_test(NAME st_hcp_srv COMMAND cmd.exe /c start /b $ -s --port ${PORT_HCP_SRV}) add_test(NAME ki_hcp_srv COMMAND taskkill /F /IM $ /T) else() - add_test(NAME st_hcp_srv COMMAND - ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh - hcp_srv - $ - -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/ - -s --port ${PORT_HCP_SRV} ) - add_test(NAME ki_hcp_srv COMMAND - ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh hcp_srv - $ --port ${PORT_HCP_SRV}) + if (VALGRIND) + add_test(NAME st_hcp_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh + hcp_srv ${VALGRIND} --tool=memcheck + $ + -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/ + -s --port ${PORT_HCP_SRV} -d1151) + add_test(NAME ki_hcp_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh hcp_srv ${VALGRIND} + $ --port ${PORT_HCP_SRV}) + else() + add_test(NAME st_hcp_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh + hcp_srv + $ + -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/ + -s --port ${PORT_HCP_SRV} ) + add_test(NAME ki_hcp_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh hcp_srv + $ --port ${PORT_HCP_SRV}) + endif() endif() set_tests_properties(st_hcp_srv PROPERTIES diff --git a/minimal-examples/ws-client/minimal-ws-client-spam/CMakeLists.txt b/minimal-examples/ws-client/minimal-ws-client-spam/CMakeLists.txt index 71996761b..34164e148 100644 --- a/minimal-examples/ws-client/minimal-ws-client-spam/CMakeLists.txt +++ b/minimal-examples/ws-client/minimal-ws-client-spam/CMakeLists.txt @@ -17,6 +17,7 @@ require_lws_config(LWS_WITH_TLS 1 requirements) if (requirements) add_executable(${SAMP} ${SRCS}) + find_program(VALGRIND "valgrind") # # instantiate the server per sai builder instance, they are running in the same # machine context in parallel so they can tread on each other otherwise @@ -44,14 +45,25 @@ if (WIN32) add_test(NAME st_wcs_srv COMMAND cmd.exe /c start /b $ -s --port ${PORT_WCS_SRV}) add_test(NAME ki_wcs_srv COMMAND taskkill /F /IM $ /T) else() - add_test(NAME st_wcs_srv COMMAND - ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh - wcs_srv $ - -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/ - -s --port ${PORT_WCS_SRV} ) - add_test(NAME ki_wcs_srv COMMAND - ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh - wcs_srv $ --port ${PORT_WCS_SRV}) + if (VALGRIND) + add_test(NAME st_wcs_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh + wcs_srv ${VALGRIND} --tool=memcheck $ + -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/ + -s --port ${PORT_WCS_SRV} ) + add_test(NAME ki_wcs_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh + wcs_srv ${VALGRIND} $ --port ${PORT_WCS_SRV}) + else() + add_test(NAME st_wcs_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh + wcs_srv $ + -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/ + -s --port ${PORT_WCS_SRV} ) + add_test(NAME ki_wcs_srv COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh + wcs_srv $ --port ${PORT_WCS_SRV}) + endif() endif() set_tests_properties(st_wcs_srv PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP wcs_srv TIMEOUT 800) diff --git a/plugin-standalone/protocol_example_standalone.c b/plugin-standalone/protocol_example_standalone.c index b8ec2ef54..35f46a597 100644 --- a/plugin-standalone/protocol_example_standalone.c +++ b/plugin-standalone/protocol_example_standalone.c @@ -131,6 +131,7 @@ LWS_VISIBLE const lws_plugin_protocol_t protocol_example_standalone = { .hdr = { "standalone", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c index afd64a054..b6561485f 100644 --- a/plugins/acme-client/protocol_lws_acme_client.c +++ b/plugins/acme-client/protocol_lws_acme_client.c @@ -791,6 +791,9 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__lws_acme_client)); + if (vhd) + return 0; + vhd->context = lws_get_context(wsi); vhd->protocol = lws_get_protocol(wsi); vhd->vhost = lws_get_vhost(wsi); @@ -1634,6 +1637,7 @@ LWS_VISIBLE const lws_plugin_protocol_t protocol_lws_acme_client = { .hdr = { "acme client", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/deaddrop/protocol_lws_deaddrop.c b/plugins/deaddrop/protocol_lws_deaddrop.c index 713f82bb7..c64b19669 100644 --- a/plugins/deaddrop/protocol_lws_deaddrop.c +++ b/plugins/deaddrop/protocol_lws_deaddrop.c @@ -394,6 +394,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, vhd = (struct vhd_deaddrop *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); + if (!vhd) + return 0; vhd->context = lws_get_context(wsi); vhd->vh = lws_get_vhost(wsi); @@ -403,8 +405,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, if (!lws_pvo_get_str(in, "max-size", &cp)) vhd->max_size = (unsigned long long)atoll(cp); if (lws_pvo_get_str(in, "upload-dir", &vhd->upload_dir)) { - lwsl_err("%s: requires 'upload-dir' pvo\n", __func__); - return -1; + lwsl_warn("%s: requires 'upload-dir' pvo\n", __func__); + return 0; } scan_upload_dir(vhd); @@ -415,7 +417,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_PROTOCOL_DESTROY: - lwsac_free(&vhd->lwsac_head); + if (vhd) + lwsac_free(&vhd->lwsac_head); break; /* WS-related */ @@ -696,6 +699,7 @@ LWS_VISIBLE const lws_plugin_protocol_t deaddrop = { .hdr = { "deaddrop", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_client_loopback_test.c b/plugins/protocol_client_loopback_test.c index d86380c9c..5e1466822 100644 --- a/plugins/protocol_client_loopback_test.c +++ b/plugins/protocol_client_loopback_test.c @@ -177,6 +177,7 @@ LWS_VISIBLE const lws_plugin_protocol_t client_loopback_test = { .hdr = { "client loopback test", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_dumb_increment.c b/plugins/protocol_dumb_increment.c index fa7326380..312ff27da 100644 --- a/plugins/protocol_dumb_increment.c +++ b/plugins/protocol_dumb_increment.c @@ -55,7 +55,7 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, lws_get_protocol(wsi), sizeof(struct vhd__dumb_increment)); if (!vhd) - return -1; + return 0; if ((opt = lws_pvo_search( (const struct lws_protocol_vhost_options *)in, "options"))) @@ -125,6 +125,7 @@ LWS_VISIBLE const lws_plugin_protocol_t dumb_increment = { .hdr = { "dumb increment", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_fulltext_demo.c b/plugins/protocol_fulltext_demo.c index 1fe167c38..bcb5573b9 100644 --- a/plugins/protocol_fulltext_demo.c +++ b/plugins/protocol_fulltext_demo.c @@ -74,7 +74,7 @@ callback_fts(struct lws *wsi, enum lws_callback_reasons reason, void *user, vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi),sizeof(struct vhd_fts_demo)); if (!vhd) - return 1; + return 0; if (lws_pvo_get_str(in, "indexpath", (const char **)&vhd->indexpath)) return 1; @@ -270,6 +270,7 @@ LWS_VISIBLE const lws_plugin_protocol_t fulltext_demo = { .hdr = { "fulltext demo", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_lws_mirror.c b/plugins/protocol_lws_mirror.c index 249f82f55..2088118e4 100644 --- a/plugins/protocol_lws_mirror.c +++ b/plugins/protocol_lws_mirror.c @@ -348,6 +348,8 @@ bail1: v = (struct per_vhost_data__lws_mirror *) lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); + if (!v) + return 0; lws_pthread_mutex_init(&v->lock); } break; @@ -486,6 +488,7 @@ LWS_VISIBLE const lws_plugin_protocol_t lws_mirror = { .hdr = { "lws mirror", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_lws_raw_test.c b/plugins/protocol_lws_raw_test.c index ed65d1703..bf310ec90 100644 --- a/plugins/protocol_lws_raw_test.c +++ b/plugins/protocol_lws_raw_test.c @@ -110,6 +110,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user, vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__raw_test)); + if (!vhd) + return 0; vhd->context = lws_get_context(wsi); vhd->protocol = lws_get_protocol(wsi); vhd->vhost = lws_get_vhost(wsi); @@ -123,7 +125,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user, pvo = pvo->next; } if (vhd->fifo_path[0] == '\0') { - lwsl_err("%s: Missing pvo \"fifo-path\", " + lwsl_warn("%s: Missing pvo \"fifo-path\", " "raw file fd testing disabled\n", __func__); break; @@ -285,6 +287,7 @@ LWS_VISIBLE const lws_plugin_protocol_t lws_raw_test = { .hdr = { "lws raw test", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_lws_sshd_demo.c b/plugins/protocol_lws_sshd_demo.c index 277085459..6a0d5dfe1 100644 --- a/plugins/protocol_lws_sshd_demo.c +++ b/plugins/protocol_lws_sshd_demo.c @@ -392,6 +392,8 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason, vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__lws_sshd_demo)); + if (!vhd) + return 0; /* * During this we still have the privs / caps we were started * with. So open an fd on the server key, either just for read @@ -404,14 +406,15 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason, vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_CREAT | O_TRUNC | O_RDWR, 0600); if (vhd->privileged_fd == -1) { - lwsl_err("%s: Can't open %s\n", __func__, + lwsl_warn("%s: Can't open %s\n", __func__, TEST_SERVER_KEY_PATH); - return -1; + return 0; } break; case LWS_CALLBACK_PROTOCOL_DESTROY: - close(vhd->privileged_fd); + if (vhd) + close(vhd->privileged_fd); break; case LWS_CALLBACK_VHOST_CERT_AGING: @@ -460,6 +463,7 @@ LWS_VISIBLE const lws_plugin_protocol_t lws_sshd_demo = { .hdr = { "lws sshd demo", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_lws_status.c b/plugins/protocol_lws_status.c index 520cb18ae..c2e9e5862 100644 --- a/plugins/protocol_lws_status.c +++ b/plugins/protocol_lws_status.c @@ -98,6 +98,8 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason, vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__lws_status)); + if (!vhd) + return 0; vhd->context = lws_get_context(wsi); vhd->protocol = lws_get_protocol(wsi); vhd->vhost = lws_get_vhost(wsi); @@ -249,6 +251,7 @@ LWS_VISIBLE const lws_plugin_protocol_t lws_status = { .hdr = { "lws status", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/protocol_post_demo.c b/plugins/protocol_post_demo.c index b6c6b9317..ec090350f 100644 --- a/plugins/protocol_post_demo.c +++ b/plugins/protocol_post_demo.c @@ -291,6 +291,7 @@ LWS_VISIBLE const lws_plugin_protocol_t post_demo = { .hdr = { "post demo", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/raw-proxy/protocol_lws_raw_proxy.c b/plugins/raw-proxy/protocol_lws_raw_proxy.c index cef5f9363..c8b38579e 100644 --- a/plugins/raw-proxy/protocol_lws_raw_proxy.c +++ b/plugins/raw-proxy/protocol_lws_raw_proxy.c @@ -187,6 +187,8 @@ callback_raw_proxy(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct raw_vhd)); + if (!vhd) + return 0; if (lws_pvo_get_str(in, "onward", &cp)) { lwsl_err("%s: vh %s: pvo 'onward' required\n", __func__, lws_get_vhost_name(lws_get_vhost(wsi))); @@ -566,6 +568,7 @@ LWS_VISIBLE const lws_plugin_protocol_t lws_raw_proxy = { .hdr = { "raw proxy", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC }, diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index a4a0a3a0a..9205b8f8f 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -1997,6 +1997,8 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason, vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__sshd)); + if (!vhd) + return 0; vhd->context = lws_get_context(wsi); vhd->protocol = lws_get_protocol(wsi); vhd->vhost = lws_get_vhost(wsi); @@ -2028,8 +2030,8 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason, } if (!vhd->ops) { - lwsl_err("ssh pvo \"ops\" is mandatory\n"); - return 1; + lwsl_warn("ssh pvo \"ops\" is mandatory\n"); + return 0; } /* * The user code ops api_version has to be current @@ -2570,6 +2572,7 @@ LWS_VISIBLE const lws_plugin_protocol_t lws_ssh_base = { .hdr = { "ssh base", "lws_protocol_plugin", + LWS_BUILD_HASH, LWS_PLUGIN_API_MAGIC },