Skip to content

Commit cf2c3b1

Browse files
committed
lws_stub: improvements
1 parent d335c58 commit cf2c3b1

6 files changed

Lines changed: 198 additions & 112 deletions

File tree

include/libwebsockets/lws-stub.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ lws_stub_request(struct lws_stub_manager *mgr,
106106
LWS_VISIBLE LWS_EXTERN void
107107
lws_stub_destroy(struct lws_stub_manager **_mgr);
108108

109+
/**
110+
* lws_stub_get_secret() - Retrieve the generated secret for a stub manager
111+
*
112+
* \param mgr: The manager returned by lws_stub_spawn
113+
*
114+
* Returns pointer to the 128-char secret string, or NULL if mgr is invalid.
115+
*/
116+
LWS_VISIBLE LWS_EXTERN const char *
117+
lws_stub_get_secret(struct lws_stub_manager *mgr);
118+
109119

110120
LWS_VISIBLE LWS_EXTERN int
111121
lws_callback_stub_client(struct lws *wsi, enum lws_callback_reasons reason,

lib/core-net/stub.c

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct lws_stub_manager {
5757
struct lws_context *cx;
5858
struct lws_vhost *vh;
5959
char uds_path[256];
60+
char stub_name[128];
6061
char secret[129];
6162
struct lws_spawn_piped *lsp;
6263
struct lws_stub_config config;
@@ -92,7 +93,12 @@ lws_stub_spawn(const struct lws_stub_config *config)
9293
mgr->cx = config->cx;
9394
mgr->vh = config->vh;
9495
memcpy(&mgr->config, config, sizeof(mgr->config));
95-
lws_strncpy(mgr->uds_path, config->uds_path, sizeof(mgr->uds_path));
96+
if (config->uds_path)
97+
lws_strncpy(mgr->uds_path, config->uds_path, sizeof(mgr->uds_path));
98+
mgr->config.uds_path = mgr->uds_path;
99+
if (config->stub_name)
100+
lws_strncpy(mgr->stub_name, config->stub_name, sizeof(mgr->stub_name));
101+
mgr->config.stub_name = mgr->stub_name;
96102
mgr->protocols = config->protocols;
97103

98104
/* Generate a secure 128-char secret */
@@ -147,7 +153,7 @@ lws_stub_spawn(const struct lws_stub_config *config)
147153
#endif
148154

149155
mgr->exec_array[n++] = exe_path;
150-
lwsl_notice("%s: Spawning stub with exe: %s\n", __func__, exe_path);
156+
lwsl_vhost_notice(mgr->vh, "%s: Spawning stub '%s' with exe: %s\n", __func__, config->stub_name, exe_path);
151157
/* Construct the stub argument dynamically */
152158
lws_snprintf(mgr->stub_arg, sizeof(mgr->stub_arg), "--lws-stub=%s", config->stub_name);
153159
mgr->exec_array[n++] = mgr->stub_arg;
@@ -165,43 +171,43 @@ lws_stub_spawn(const struct lws_stub_config *config)
165171
if (stdin_fd) {
166172
DWORD bw;
167173
if (!WriteFile(stdin_fd, mgr->secret, 128, &bw, NULL)) {
168-
lwsl_err("%s: Failed writing secret to pipe\n", __func__);
174+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' failed writing secret to pipe\n", __func__, config->stub_name);
169175
goto spawn_fail;
170176
}
171177
if (config->extra_payload && config->extra_payload_len) {
172178
if (!WriteFile(stdin_fd, config->extra_payload, (DWORD)config->extra_payload_len, &bw, NULL)) {
173-
lwsl_err("%s: Failed writing extra payload to pipe\n", __func__);
179+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' failed writing extra payload to pipe\n", __func__, config->stub_name);
174180
goto spawn_fail;
175181
}
176182
}
177183
} else {
178-
lwsl_err("%s: No stdin pipe available\n", __func__);
184+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' no stdin pipe available\n", __func__, config->stub_name);
179185
goto spawn_fail;
180186
}
181187
#else
182188
if (stdin_fd >= 0) {
183189
if (write(stdin_fd, mgr->secret, 128) < 0) {
184-
lwsl_err("%s: Failed writing secret to pipe\n", __func__);
190+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' failed writing secret to pipe\n", __func__, config->stub_name);
185191
goto spawn_fail;
186192
}
187193
if (config->extra_payload && config->extra_payload_len) {
188194
if (write(stdin_fd, config->extra_payload, (unsigned int)config->extra_payload_len) < 0) {
189-
lwsl_err("%s: Failed writing extra payload to pipe\n", __func__);
195+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' failed writing extra payload to pipe\n", __func__, config->stub_name);
190196
goto spawn_fail;
191197
}
192198
}
193199
} else {
194-
lwsl_err("%s: No stdin pipe available\n", __func__);
200+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' no stdin pipe available\n", __func__, config->stub_name);
195201
goto spawn_fail;
196202
}
197203
#endif
198204
} else {
199-
lwsl_vhost_err(mgr->vh, "%s: Failed to spawn stub %s\n", __func__, config->stub_name);
205+
lwsl_vhost_err(mgr->vh, "%s: Failed to spawn stub '%s'\n", __func__, config->stub_name);
200206
lws_free(mgr);
201207
return NULL;
202208
}
203209

204-
lwsl_vhost_notice(mgr->vh, "%s: Spawned stub %s\n", __func__, config->stub_name);
210+
lwsl_vhost_notice(mgr->vh, "%s: Spawned stub '%s'\n", __func__, config->stub_name);
205211

206212
if (!mgr->sul.list.owner && !mgr->wsi_client)
207213
lws_stub_client_connect(mgr);
@@ -210,7 +216,7 @@ lws_stub_spawn(const struct lws_stub_config *config)
210216

211217
spawn_fail:
212218
lws_spawn_piped_kill_child_process(mgr->lsp);
213-
lwsl_vhost_err(mgr->vh, "%s: Failed to initialize spawned stub %s\n", __func__, config->stub_name);
219+
lwsl_vhost_err(mgr->vh, "%s: Failed to initialize spawned stub '%s'\n", __func__, config->stub_name);
214220
lws_free(mgr);
215221
return NULL;
216222
}
@@ -238,7 +244,7 @@ lws_stub_server_init(const struct lws_stub_config *config, char *secret_out, voi
238244
}
239245

240246
if (rx < 64) {
241-
lwsl_err("%s: Failed to read secret from stdin\n", __func__);
247+
lwsl_err("%s: stub '%s': Failed to read secret from stdin\n", __func__, config->stub_name ? config->stub_name : "unknown");
242248
return -1;
243249
}
244250
secret_out[128] = '\0';
@@ -249,7 +255,7 @@ lws_stub_server_init(const struct lws_stub_config *config, char *secret_out, voi
249255
* and unknown to the child, and the pipe remains open for future IPC. */
250256
ssize_t n = read(0, (void *)extra_out, (unsigned int)extra_len);
251257
if (n < 0) {
252-
lwsl_err("%s: Failed to read extra payload\n", __func__);
258+
lwsl_err("%s: stub '%s': Failed to read extra payload\n", __func__, config->stub_name ? config->stub_name : "unknown");
253259
/* Non-fatal */
254260
}
255261
}
@@ -265,7 +271,7 @@ lws_stub_server_init(const struct lws_stub_config *config, char *secret_out, voi
265271
unlink(info.iface);
266272
vh_uds = lws_create_vhost(config->cx, &info);
267273
if (!vh_uds) {
268-
lwsl_err("%s: Failed to create UDS vhost\n", __func__);
274+
lwsl_err("%s: stub '%s': Failed to create UDS vhost\n", __func__, config->stub_name ? config->stub_name : "unknown");
269275
return -1;
270276
}
271277

@@ -295,6 +301,23 @@ static const lws_retry_bo_t stub_retry = {
295301
static void
296302
stub_retry_cb(lws_sorted_usec_list_t *sul);
297303

304+
static int
305+
lws_stub_child_is_alive(struct lws_stub_manager *mgr)
306+
{
307+
if (!mgr || !mgr->lsp)
308+
return 0;
309+
310+
#if !defined(WIN32)
311+
if (mgr->lsp->child_pid <= 0)
312+
return 0;
313+
if (kill(mgr->lsp->child_pid, 0) == 0 || errno == EPERM)
314+
return 1;
315+
return 0;
316+
#else
317+
return 1;
318+
#endif
319+
}
320+
298321
static int
299322
lws_stub_client_connect(struct lws_stub_manager *mgr)
300323
{
@@ -317,16 +340,22 @@ lws_stub_client_connect(struct lws_stub_manager *mgr)
317340
i.retry_and_idle_policy = &stub_retry;
318341
i.method = "RAW"; /* RAW connection */
319342

320-
lwsl_vhost_notice(mgr->vh, "protocol %s, addr %s\n", i.protocol, i.address);
343+
lwsl_vhost_notice(mgr->vh, "%s: stub '%s', protocol %s, addr %s\n", __func__, mgr->config.stub_name, i.protocol, i.address);
321344
mgr->wsi_client = lws_client_connect_via_info(&i);
322345
if (!mgr->wsi_client) {
323346
if (mgr->ctry < 10) {
324347
uint32_t ms = stub_retry.retry_ms_table[
325348
mgr->ctry < stub_retry.retry_ms_table_count ?
326349
mgr->ctry : stub_retry.retry_ms_table_count - 1];
327350
mgr->ctry++;
328-
if (mgr->ctry > 1)
329-
lwsl_notice("%s: Synchronous connect failed (errno %d), retrying in %u ms (attempt %d)\n", __func__, LWS_ERRNO, (unsigned int)ms, mgr->ctry);
351+
if (mgr->ctry > 1) {
352+
int alive = lws_stub_child_is_alive(mgr);
353+
lwsl_vhost_notice(mgr->vh, "%s: stub '%s': Synchronous connect failed (errno %d), stub process %s (PID %d), retrying in %u ms (attempt %d)\n",
354+
__func__, mgr->config.stub_name, LWS_ERRNO,
355+
alive ? "is alive" : "has DIED/DOES NOT EXIST",
356+
mgr->lsp ? (int)mgr->lsp->child_pid : -1,
357+
(unsigned int)ms, mgr->ctry);
358+
}
330359
lws_sul_schedule(mgr->cx, 0, &mgr->sul, stub_retry_cb, ms * 1000);
331360
}
332361

@@ -354,14 +383,19 @@ lws_callback_stub_client(struct lws *wsi, enum lws_callback_reasons reason,
354383
return 0;
355384

356385
switch (reason) {
357-
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
358-
lwsl_err("%s: Client connection failed\n", __func__);
386+
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
387+
int alive = lws_stub_child_is_alive(mgr);
388+
lwsl_vhost_err(mgr->vh, "%s: stub '%s': Client connection failed (stub process %s, PID %d)\n",
389+
__func__, mgr->config.stub_name,
390+
alive ? "is alive" : "has DIED/DOES NOT EXIST",
391+
mgr->lsp ? (int)mgr->lsp->child_pid : -1);
359392
mgr->wsi_client = NULL;
360393
lws_retry_sul_schedule(mgr->cx, 0, &mgr->sul, &stub_retry, stub_retry_cb, &mgr->ctry);
361394
break;
395+
}
362396

363397
case LWS_CALLBACK_RAW_CONNECTED:
364-
lwsl_notice("%s: UDS connected to stub\n", __func__);
398+
lwsl_vhost_notice(mgr->vh, "%s: stub '%s': UDS connected\n", __func__, mgr->config.stub_name);
365399
mgr->ctry = 0; /* Reset retry counter on success */
366400
if (mgr->config.connected_cb)
367401
mgr->config.connected_cb(mgr);
@@ -409,7 +443,7 @@ lws_callback_stub_client(struct lws *wsi, enum lws_callback_reasons reason,
409443
if (req->rx_cb) {
410444
int m = lejp_parse(&req->jctx, (uint8_t *)in, (int)len);
411445
if (m < 0 && m != LEJP_CONTINUE) {
412-
lwsl_err("%s: lejp parse failed: %d\n", __func__, m);
446+
lwsl_vhost_err(mgr->vh, "%s: stub '%s' lejp parse failed: %d\n", __func__, mgr->config.stub_name, m);
413447
lws_dll2_remove(&req->list);
414448
lws_free(req->tx_buf);
415449
lejp_destruct(&req->jctx);
@@ -509,4 +543,12 @@ lws_stub_destroy(struct lws_stub_manager **_mgr)
509543
lws_free(mgr);
510544
*_mgr = NULL;
511545
}
546+
547+
const char *
548+
lws_stub_get_secret(struct lws_stub_manager *mgr)
549+
{
550+
if (!mgr)
551+
return NULL;
552+
return mgr->secret;
553+
}
512554
#endif

lib/roles/http/server/lejp-conf.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,12 +1438,13 @@ lwsws_get_config_vhosts(struct lws_context *context,
14381438
struct jpargs a;
14391439
char dd[128];
14401440

1441-
if (lws_cmdline_option_cx(context, "--lws-dht-dnssec-monitor-root")) {
1441+
if (lws_cmdline_option_cx(context, "--lws-dht-dnssec-monitor-root") ||
1442+
lws_cmdline_option_cx(context, "--lws-stub")) {
14421443
struct lws_context_creation_info i;
14431444

1444-
lwsl_notice("%s: monitor process: skipping vhost parsing\n", __func__);
1445+
lwsl_notice("%s: stub/monitor process: skipping vhost parsing\n", __func__);
14451446
memset(&i, 0, sizeof(i));
1446-
i.vhost_name = "root-monitor-dummy";
1447+
i.vhost_name = "stub-dummy";
14471448
i.port = CONTEXT_PORT_NO_LISTEN;
14481449
i.options = info->options | LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_VH_INSTANTIATE_ALL_PROTOCOLS;
14491450
i.protocols = info->protocols;

plugins/protocol_lws_cert_dist_client/protocol_lws_cert_dist_client.c

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -609,17 +609,16 @@ callback_cert_dist_client(struct lws *wsi, enum lws_callback_reasons reason,
609609
break;
610610
}
611611

612-
/* Build UDS payload */
613-
/* Expected by stub: {"secret":"...","subdomain":"...","fullchain":"...","privkey":"..."} */
614-
int est_len = (pss->cert_len * 2) + (pss->key_len * 2) + (int)strlen(pss->subdomain) + (int)strlen(vhd->secret) + 128;
612+
const char *sec = lws_stub_get_secret(vhd->stub_mgr);
613+
int est_len = (pss->cert_len * 2) + (pss->key_len * 2) + (int)strlen(pss->subdomain) + (sec ? (int)strlen(sec) : 0) + 128;
615614
pss->uds_tx = malloc((size_t)est_len + LWS_PRE);
616615
if (!pss->uds_tx) {
617616
lwsl_err("%s: OOM alloc uds tx\n", __func__);
618617
break;
619618
}
620619
pss->uds_tx_len = lws_snprintf(pss->uds_tx + LWS_PRE, (size_t)est_len,
621620
"{\"secret\":\"%s\",\"subdomain\":\"%s\",\"fullchain\":\"",
622-
vhd->secret, pss->subdomain);
621+
sec ? sec : "", pss->subdomain);
623622

624623
char *p = pss->uds_tx + LWS_PRE + pss->uds_tx_len;
625624
char *src = pss->cert;
@@ -704,21 +703,46 @@ callback_cert_dist_client(struct lws *wsi, enum lws_callback_reasons reason,
704703
case LWS_CALLBACK_PROTOCOL_INIT:
705704
{
706705
const char *stub = lws_cmdline_option_cx(lws_get_context(wsi), "--lws-stub");
707-
char uds_path[256];
708-
char stub_name[256];
709-
710-
if (!in)
711-
return 0;
712-
713-
const char *vh_name = lws_get_vhost_name(lws_get_vhost(wsi));
714706

715707
if (stub) {
716-
char expected_stub[256];
717-
lws_snprintf(expected_stub, sizeof(expected_stub), "stub-%s", vh_name);
718-
if (strcmp(stub, expected_stub))
708+
if (strncmp(stub, "stub-client-", 12) && strncmp(stub, "stub-", 5))
719709
return 0;
710+
711+
const char *orig_vh = strncmp(stub, "stub-client-", 12) == 0 ? stub + 12 : stub + 5;
712+
char uds_path[256];
713+
lws_snprintf(uds_path, sizeof(uds_path), "/var/run/lws-cert-dist-stub-%s.sock", orig_vh);
714+
715+
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
716+
lws_get_protocol(wsi),
717+
sizeof(struct vhd_cert_dist_client));
718+
if (!vhd) return -1;
719+
vhd->cx = lws_get_context(wsi);
720+
vhd->vh = lws_get_vhost(wsi);
721+
vhd->protocol = lws_get_protocol(wsi);
722+
lws_strncpy(vhd->vh_name, orig_vh, sizeof(vhd->vh_name));
723+
vhd->is_stub = 1;
724+
725+
struct lws_stub_config sc;
726+
memset(&sc, 0, sizeof(sc));
727+
sc.cx = vhd->cx;
728+
sc.vh = vhd->vh;
729+
sc.stub_name = stub;
730+
sc.uds_path = uds_path;
731+
sc.protocols = stub_protocols;
732+
733+
lws_dll2_add_tail(&vhd->list_vhd, &active_client_vhds);
734+
if (lws_stub_server_init(&sc, vhd->secret, vhd->reload_cmd, sizeof(vhd->reload_cmd))) {
735+
lws_dll2_remove(&vhd->list_vhd);
736+
return -1;
737+
}
738+
return 0;
720739
}
721740

741+
if (!in)
742+
return 0;
743+
744+
const char *vh_name = lws_get_vhost_name(lws_get_vhost(wsi));
745+
722746
vhd = lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi));
723747
if (vhd)
724748
return 0;
@@ -731,9 +755,11 @@ callback_cert_dist_client(struct lws *wsi, enum lws_callback_reasons reason,
731755
return -1;
732756
}
733757

758+
char uds_path[256];
759+
char stub_name[256];
734760
lws_strncpy(vhd->vh_name, vh_name, sizeof(vhd->vh_name));
735761
lws_snprintf(uds_path, sizeof(uds_path), "/var/run/lws-cert-dist-stub-%s.sock", vh_name);
736-
lws_snprintf(stub_name, sizeof(stub_name), "stub-%s", vh_name);
762+
lws_snprintf(stub_name, sizeof(stub_name), "stub-client-%s", vh_name);
737763

738764
lwsl_notice("%s: allocated vhd\n", __func__);
739765

@@ -764,26 +790,6 @@ callback_cert_dist_client(struct lws *wsi, enum lws_callback_reasons reason,
764790
pvo = pvo->next;
765791
}
766792

767-
768-
if (stub) {
769-
struct lws_stub_config sc;
770-
771-
vhd->is_stub = 1;
772-
memset(&sc, 0, sizeof(sc));
773-
sc.cx = vhd->cx;
774-
sc.vh = vhd->vh;
775-
sc.stub_name = stub_name;
776-
sc.uds_path = uds_path;
777-
sc.protocols = stub_protocols;
778-
779-
lws_dll2_add_tail(&vhd->list_vhd, &active_client_vhds);
780-
if (lws_stub_server_init(&sc, vhd->secret, vhd->reload_cmd, sizeof(vhd->reload_cmd))) {
781-
lws_dll2_remove(&vhd->list_vhd);
782-
return -1;
783-
}
784-
return 0;
785-
}
786-
787793
lwsl_vhost_notice(lws_get_vhost(wsi), "%s: Protocol init. euid=%d\n", __func__, (int)getuid());
788794

789795
struct vhd_cert_dist_client *old_vhd = NULL;

0 commit comments

Comments
 (0)