| Author | Andy Green <andy@warmcat.com> 2026-09-09 08:35 UTC | | Committer | Andy Green <andy@warmcat.com> 2026-09-09 08:35 UTC | | Tree | 4e6f46c509f788387aed5710931742f356f210fd Raw Patch | | | server, web: share the config helper, let lws own the generic switches | server, web: share the config helper, let lws own the generic switches
sai-server and sai-web each carried an identical copy of
sai_lws_context_from_json(). Move it to src/common/c-conf.c so both get
the lws_stub child handling added in the previous commit, since sai-web can
be configured to serve directly and then owns its own TLS termination and
certs, exactly the case lws-cert-dist-client is for.
Rearrange who fills in the context creation info: main() now zeroes it and
passes argc / argv through lws_cmdline_option_handle_builtin() before
anything logs, then the helper only adds to it. The builtin handler sets
the log level from -d, so the hand-rolled -d parsing in both mains goes,
and it also fills in info->lws_stub, which the helper keys the stub-mode
adjustments off instead of taking argc / argv itself. Doing it in that
order means the helper's former memset can no longer wipe what the
commandline set.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
diff --git a/src/common/c-conf.c b/src/common/c-conf.c
new file mode 100644
index 0000000..5cd11c9
--- /dev/null
+++ b/src/common/c-conf.c
@@ -0,0 +1,111 @@
+/*
+ * Sai - ./src/common/c-conf.c
+ *
+ * Copyright (C) 2019 - 2026 Andy Green <andy@warmcat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation:
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Create an lws context and its vhosts from an lwsws-style JSON config dir,
+ * shared by the sai daemons that are configured that way (sai-server,
+ * sai-web).
+ */
+
+#include "include/private.h"
+
+#include <string.h>
+
+#define SAI_CONFIG_STRING_SIZE (16 * 1024)
+
+/*
+ * The caller owns \p info: it has already zeroed it and passed argc / argv
+ * through lws_cmdline_option_handle_builtin(), so anything the commandline
+ * set in there (log level, argc / argv, lws_stub, option flags) is still in
+ * place when we get it. We only add to it.
+ */
+
+struct lws_context *
+sai_lws_context_from_json(const char *config_dir,
+ struct lws_context_creation_info *info,
+ const struct lws_protocols **pprotocols,
+ const char *jpol)
+{
+ int cs_len = SAI_CONFIG_STRING_SIZE - 1;
+ struct lws_context *context;
+ char *cs, *config_strings;
+
+ cs = config_strings = malloc(SAI_CONFIG_STRING_SIZE);
+ if (!config_strings) {
+ lwsl_err("Unable to allocate config strings heap\n");
+
+ return NULL;
+ }
+
+ info->external_baggage_free_on_destroy = config_strings;
+ info->pt_serv_buf_size = 8192;
+ info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+ LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+ LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE |
+ LWS_SERVER_OPTION_VALIDATE_UTF8;
+ info->pss_policies_json = jpol;
+
+ if (info->lws_stub) {
+ /*
+ * We were re-exec'd with --lws-stub=<name> by an lws plugin
+ * (eg, lws-cert-dist-client) that needs a privileged helper.
+ * We exist only to host that plugin's protocol, on the
+ * stub-dummy vhost lwsws_get_config_vhosts() creates instead
+ * of parsing our real vhosts. So none of our own protocols
+ * or the SS policy should come up, and we must keep our
+ * privileges rather than dropping to the configured uid / gid,
+ * since the stub's whole purpose is to do the privileged work.
+ */
+ lwsl_notice("%s: lws stub child '%s'\n", __func__,
+ info->lws_stub);
+ info->options |= LWS_SERVER_OPTION_VH_SKIP_PRIV_DROP;
+ info->pss_policies_json = NULL;
+ pprotocols = NULL;
+ }
+
+ lwsl_notice("Using config dir: \"%s\"\n", config_dir);
+
+ /*
+ * first go through the config for creating the outer context
+ */
+ if (lwsws_get_config_globals(info, config_dir, &cs, &cs_len))
+ goto init_failed;
+
+ context = lws_create_context(info);
+ if (context == NULL) {
+ /* config_strings freed as 'external baggage' */
+ return NULL;
+ }
+
+ info->pprotocols = pprotocols;
+
+ if (lwsws_get_config_vhosts(context, info, config_dir, &cs, &cs_len)) {
+ lwsl_err("%s: sai_lws_context_from_json failed\n", __func__);
+ lws_context_destroy(context);
+
+ return NULL;
+ }
+
+ return context;
+
+init_failed:
+ free(config_strings);
+
+ return NULL;
+}
diff --git a/src/common/include/private.h b/src/common/include/private.h
index ef1ce91..f2b1f1f 100644
--- a/src/common/include/private.h
+++ b/src/common/include/private.h
@@ -1010,3 +1010,13 @@ sai_event_db_delete_database(const char *sqlite3_path_lhs, const char *event_uui
int
sai_sqlite3_statement(struct sqlite3 *pdb, const char *cmd, const char *desc);
+/*
+ * c-conf.c: create the context and vhosts from an lwsws-style config dir.
+ * info must be zeroed and passed through lws_cmdline_option_handle_builtin()
+ * by the caller first.
+ */
+struct lws_context *
+sai_lws_context_from_json(const char *config_dir,
+ struct lws_context_creation_info *info,
+ const struct lws_protocols **pprotocols,
+ const char *jpol);
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
index 66982a4..0c13b61 100644
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -4,7 +4,6 @@ set(CPACK_DEBIAN_SERVER_PACKAGE_NAME ${SUB})
set(SRCS
s-sai.c
- s-conf.c
s-notification.c
s-comms.c
s-helpers.c
@@ -18,6 +17,7 @@ set(SRCS
s-resource.c
s-watcher.c
../common/c-utils.c
+ ../common/c-conf.c
../common/c-sqlite3.c
../common/struct-metadata.c
)
diff --git a/src/server/s-conf.c b/src/server/s-conf.c
deleted file mode 100644
index 66f0df3..0000000
--- a/src/server/s-conf.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Sai server src/server/conf.c
- *
- * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-#include <libwebsockets.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-
-#define SAI_CONFIG_STRING_SIZE (16 * 1024)
-
-extern struct lws_context *context;
-
-struct lws_context *
-sai_lws_context_from_json(const char *config_dir,
- struct lws_context_creation_info *info,
- const struct lws_protocols **pprotocols,
- const char *jpol, int argc, const char **argv)
-{
- int cs_len = SAI_CONFIG_STRING_SIZE - 1;
- struct lws_context *context;
- char *cs, *config_strings;
-
- cs = config_strings = malloc(SAI_CONFIG_STRING_SIZE);
- if (!config_strings) {
- lwsl_err("Unable to allocate config strings heap\n");
-
- return NULL;
- }
-
- memset(info, 0, sizeof(*info));
-
- info->external_baggage_free_on_destroy = config_strings;
- info->pt_serv_buf_size = 8192;
- info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
- LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
- LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE |
- LWS_SERVER_OPTION_VALIDATE_UTF8;
- info->pss_policies_json = jpol;
-
- /*
- * Let lws see our commandline: lws_cmdline_option_cx() needs it, and
- * it is how lws_stub children (lws plugins that spawn a privileged
- * helper by re-exec'ing us with --lws-stub=<name>) are recognized,
- * both by the plugins themselves and by lwsws_get_config_vhosts()
- */
- lws_cmdline_option_handle_builtin(argc, argv, info);
-
- if (info->lws_stub) {
- /*
- * We are a stub child, not a sai-server. We exist only to
- * host the plugin protocol that spawned us, on the stub-dummy
- * vhost lwsws_get_config_vhosts() creates instead of parsing
- * our real vhosts. So none of our own protocols or the SS
- * websrv listener should come up, and we must keep our
- * privileges rather than dropping to the configured uid / gid,
- * since the stub's whole purpose is to do the privileged work.
- */
- lwsl_notice("%s: lws stub child '%s'\n", __func__,
- info->lws_stub);
- info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
- LWS_SERVER_OPTION_VH_SKIP_PRIV_DROP;
- info->pss_policies_json = NULL;
- pprotocols = NULL;
- }
-
- lwsl_notice("Using config dir: \"%s\"\n", config_dir);
-
- /*
- * first go through the config for creating the outer context
- */
- if (lwsws_get_config_globals(info, config_dir, &cs, &cs_len))
- goto init_failed;
-
- context = lws_create_context(info);
- if (context == NULL) {
- /* config_strings freed as 'external baggage' */
- return NULL;
- }
-
- info->pprotocols = pprotocols;
-
- if (lwsws_get_config_vhosts(context, info, config_dir, &cs, &cs_len)) {
- lwsl_err("%s: sai_lws_context_from_json failed\n", __func__);
- lws_context_destroy(context);
-
- return NULL;
- }
-
- return context;
-
-init_failed:
- free(config_strings);
-
- return NULL;
-}
diff --git a/src/server/s-private.h b/src/server/s-private.h
index afe20be..1f812b5 100644
--- a/src/server/s-private.h
+++ b/src/server/s-private.h
@@ -273,11 +273,6 @@ struct vhd {
unsigned int viewers_are_present:1;
};
-extern struct lws_context *
-sai_lws_context_from_json(const char *config_dir,
- struct lws_context_creation_info *info,
- const struct lws_protocols **pprotocols,
- const char *jpol, int argc, const char **argv);
extern const struct lws_protocols protocol_ws, protocol_ws_power;
int
diff --git a/src/server/s-sai.c b/src/server/s-sai.c
index 84e328d..0a35bc6 100644
--- a/src/server/s-sai.c
+++ b/src/server/s-sai.c
@@ -71,23 +71,27 @@ static void sigint_handler(int sig)
int main(int argc, const char **argv)
{
- int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
const char *p, *conf = "/etc/sai/server";
struct lws_context_creation_info info;
signal(SIGINT, sigint_handler);
- if ((p = lws_cmdline_option(argc, argv, "-d")))
- logs = atoi(p);
+ /*
+ * lws owns the generic switches: -d for the log level, and
+ * --lws-stub=<name> when an lws plugin re-exec'd us as its privileged
+ * helper. This must come after zeroing info and before anything that
+ * logs, since it sets the log level as well as filling in info.
+ */
+ memset(&info, 0, sizeof(info));
+ lws_cmdline_option_handle_builtin(argc, argv, &info);
- lws_set_log_level(logs, NULL);
- lwsl_user("Sai Server - Copyright (C) 2019-2025 Andy Green <andy@warmcat.com>\n");
+ lwsl_user("Sai Server - Copyright (C) 2019-2026 Andy Green <andy@warmcat.com>\n");
if ((p = lws_cmdline_option(argc, argv, "-c")))
conf = p;
context = sai_lws_context_from_json(conf, &info, pprotocols,
- default_ss_policy, argc, argv);
+ default_ss_policy);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
diff --git a/src/web/CMakeLists.txt b/src/web/CMakeLists.txt
index f06cbfa..6d2b4bd 100644
--- a/src/web/CMakeLists.txt
+++ b/src/web/CMakeLists.txt
@@ -4,12 +4,12 @@ set(CPACK_DEBIAN_SERVER_PACKAGE_NAME ${SUB})
set(SRCS
w-sai.c
- w-conf.c
w-comms.c
w-artifact.c
w-ws-server.c
w-ws-browser.c
../common/c-utils.c
+ ../common/c-conf.c
../common/c-sqlite3.c
../common/struct-metadata.c
)
diff --git a/src/web/w-conf.c b/src/web/w-conf.c
deleted file mode 100644
index b229ace..0000000
--- a/src/web/w-conf.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Sai server src/server/conf.c
- *
- * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-#include <libwebsockets.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-
-#define SAI_CONFIG_STRING_SIZE (16 * 1024)
-
-struct lws_context *
-sai_lws_context_from_json(const char *config_dir,
- struct lws_context_creation_info *info,
- const struct lws_protocols **pprotocols,
- const char *pol)
-{
- int cs_len = SAI_CONFIG_STRING_SIZE - 1;
- struct lws_context *context;
- char *cs, *config_strings;
-
- cs = config_strings = malloc(SAI_CONFIG_STRING_SIZE);
- if (!config_strings) {
- lwsl_err("Unable to allocate config strings heap\n");
-
- return NULL;
- }
-
- memset(info, 0, sizeof(*info));
-
- info->external_baggage_free_on_destroy = config_strings;
- info->pt_serv_buf_size = 8192;
- info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
- LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
- LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE |
- LWS_SERVER_OPTION_VALIDATE_UTF8;
- info->pss_policies_json = pol;
-
- lwsl_notice("Using config dir: \"%s\"\n", config_dir);
-
- /*
- * first go through the config for creating the outer context
- */
- if (lwsws_get_config_globals(info, config_dir, &cs, &cs_len))
- goto init_failed;
-
- context = lws_create_context(info);
- if (context == NULL) {
- /* config_strings freed as 'external baggage' */
- return NULL;
- }
-
- info->pprotocols = pprotocols;
-
- if (lwsws_get_config_vhosts(context, info, config_dir, &cs, &cs_len)) {
- lwsl_err("%s: sai_lws_context_from_json failed\n", __func__);
- lws_context_destroy(context);
-
- return NULL;
- }
-
- return context;
-
-init_failed:
- free(config_strings);
-
- return NULL;
-}
diff --git a/src/web/w-private.h b/src/web/w-private.h
index cb1c24c..fd95d26 100644
--- a/src/web/w-private.h
+++ b/src/web/w-private.h
@@ -232,11 +232,6 @@ typedef struct saiw_websrv {
} saiw_websrv_t;
-extern struct lws_context *
-sai_lws_context_from_json(const char *config_dir,
- struct lws_context_creation_info *info,
- const struct lws_protocols **pprotocols,
- const char *pol);
extern const struct lws_protocols protocol_ws;
extern const lws_ss_info_t ssi_saiw_websrv;
diff --git a/src/web/w-sai.c b/src/web/w-sai.c
index 2a7f740..a85c8d3 100644
--- a/src/web/w-sai.c
+++ b/src/web/w-sai.c
@@ -66,17 +66,21 @@ static void sigint_handler(int sig)
int main(int argc, const char **argv)
{
- int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
const char *p, *conf = "/etc/sai/web";
struct lws_context_creation_info info;
signal(SIGINT, sigint_handler);
- if ((p = lws_cmdline_option(argc, argv, "-d")))
- logs = atoi(p);
+ /*
+ * lws owns the generic switches: -d for the log level, and
+ * --lws-stub=<name> when an lws plugin re-exec'd us as its privileged
+ * helper. This must come after zeroing info and before anything that
+ * logs, since it sets the log level as well as filling in info.
+ */
+ memset(&info, 0, sizeof(info));
+ lws_cmdline_option_handle_builtin(argc, argv, &info);
- lws_set_log_level(logs, NULL);
- lwsl_user("Sai Web - Copyright (C) 2019-2025 Andy Green <andy@warmcat.com>\n");
+ lwsl_user("Sai Web - Copyright (C) 2019-2026 Andy Green <andy@warmcat.com>\n");
if ((p = lws_cmdline_option(argc, argv, "-c")))
conf = p;
|