spawn server fixes 3 (#18117)
always send back the spawn server response to the socket
Costa Tsaousis committed
Jul 11, 2024 at 21:02 UTC
47afd05e246830982f1b0263c818392b63086462
2 files changed
+107
-98
src/libnetdata/spawn_server/spawn_server.c
+96
-88
@@ -355,7 +355,7 @@ static void spawn_server_send_status_ping(int fd) {
355
nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Cannot send ping status report");
356
}
357
358
-static void spawn_server_send_status_success(int fd) {
358
+static void spawn_server_send_status_success(SPAWN_REQUEST *rq) {
359
const struct status_report sr = {
360
.status = STATUS_REPORT_STARTED,
361
.started = {
@@ -363,11 +363,11 @@ static void spawn_server_send_status_success(int fd) {
363
},
364
};
365
366
- if(write(fd, &sr, sizeof(sr)) != sizeof(sr))
366
+ if(write(rq->sock, &sr, sizeof(sr)) != sizeof(sr))
367
nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Cannot send success status report");
368
}
369
370
-static void spawn_server_send_status_failure(int fd) {
370
+static void spawn_server_send_status_failure(SPAWN_REQUEST *rq) {
371
struct status_report sr = {
372
.status = STATUS_REPORT_FAILED,
373
.failed = {
@@ -375,11 +375,11 @@ static void spawn_server_send_status_failure(int fd) {
375
},
376
};
377
378
- if(write(fd, &sr, sizeof(sr)) != sizeof(sr))
378
+ if(write(rq->sock, &sr, sizeof(sr)) != sizeof(sr))
379
nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Cannot send failure status report");
380
}
381
382
-static void spawn_server_send_status_exit(int fd, int waitpid_status) {
382
+static void spawn_server_send_status_exit(SPAWN_REQUEST *rq, int waitpid_status) {
383
struct status_report sr = {
384
.status = STATUS_REPORT_EXITED,
385
.exited = {
@@ -387,11 +387,11 @@ static void spawn_server_send_status_exit(int fd, int waitpid_status) {
387
},
388
};
389
390
- if(write(fd, &sr, sizeof(sr)) != sizeof(sr))
390
+ if(write(rq->sock, &sr, sizeof(sr)) != sizeof(sr))
391
nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Cannot send exit status report");
392
}
393
394
-static void spawn_server_run_child(SPAWN_SERVER *server, SPAWN_REQUEST *request) {
394
+static void spawn_server_run_child(SPAWN_SERVER *server, SPAWN_REQUEST *rq) {
395
// fprintf(stderr, "CHILD: running request %zu on pid %d\n", request->request_id, getpid());
396
397
// close the server sockets;
@@ -402,67 +402,67 @@ static void spawn_server_run_child(SPAWN_SERVER *server, SPAWN_REQUEST *request)
402
// set the process name
403
{
404
char buf[15];
405
- snprintfz(buf, sizeof(buf), "chld-%zu-r%zu", server->id, request->request_id);
405
+ snprintfz(buf, sizeof(buf), "chld-%zu-r%zu", server->id, rq->request_id);
406
os_setproctitle(buf, server->argc, server->argv);
407
}
408
409
// get the fds from the request
410
- int stdin_fd = request->fds[0];
411
- int stdout_fd = request->fds[1];
412
- int stderr_fd = request->fds[2];
413
- int custom_fd = request->fds[3];
410
+ int stdin_fd = rq->fds[0];
411
+ int stdout_fd = rq->fds[1];
412
+ int stderr_fd = rq->fds[2];
413
+ int custom_fd = rq->fds[3];
414
415
// change stdio fds to the ones in the request
416
if (dup2(stdin_fd, STDIN_FILENO) == -1) {
417
- spawn_server_send_status_failure(stdout_fd);
417
+ spawn_server_send_status_failure(rq);
418
exit(1);
419
}
420
if (dup2(stdout_fd, STDOUT_FILENO) == -1) {
421
- spawn_server_send_status_failure(stdout_fd);
421
+ spawn_server_send_status_failure(rq);
422
exit(1);
423
}
424
if (dup2(stderr_fd, STDERR_FILENO) == -1) {
425
- spawn_server_send_status_failure(stdout_fd);
425
+ spawn_server_send_status_failure(rq);
426
exit(1);
427
}
428
429
// close the excess fds
430
- close(stdin_fd); stdin_fd = request->fds[0] = STDIN_FILENO;
431
- close(stdout_fd); stdout_fd = request->fds[1] = STDOUT_FILENO;
432
- close(stderr_fd); stderr_fd = request->fds[2] = STDERR_FILENO;
430
+ close(stdin_fd); stdin_fd = rq->fds[0] = STDIN_FILENO;
431
+ close(stdout_fd); stdout_fd = rq->fds[1] = STDOUT_FILENO;
432
+ close(stderr_fd); stderr_fd = rq->fds[2] = STDERR_FILENO;
433
434
// overwrite the process environment
435
- environ = (char **)request->environment;
435
+ environ = (char **)rq->environment;
436
437
// Perform different actions based on the type
438
- switch (request->type) {
438
+ switch (rq->type) {
439
440
case SPAWN_INSTANCE_TYPE_EXEC:
441
- spawn_server_send_status_success(request->socket);
442
- close(request->socket); request->socket = -1;
441
+ spawn_server_send_status_success(rq);
442
+ close(rq->sock); rq->sock = -1;
443
close(custom_fd); custom_fd = -1;
444
- execvp(request->argv[0], (char **)request->argv);
444
+ execvp(rq->argv[0], (char **)rq->argv);
445
nd_log(NDLS_COLLECTORS, NDLP_ERR,
446
"SPAWN SERVER: Failed to execute command of request No %zu (argv[0] = '%s')",
447
- request->request_id, request->argv[0]);
447
+ rq->request_id, rq->argv[0]);
448
exit(1);
449
break;
450
451
case SPAWN_INSTANCE_TYPE_CALLBACK:
452
if(server->cb == NULL) {
453
errno = ENOENT;
454
- spawn_server_send_status_failure(request->socket);
455
- close(request->socket); request->socket = -1;
454
+ spawn_server_send_status_failure(rq);
455
+ close(rq->sock); rq->sock = -1;
456
exit(1);
457
}
458
- spawn_server_send_status_success(request->socket);
459
- close(request->socket); request->socket = -1;
460
- server->cb(request);
458
+ spawn_server_send_status_success(rq);
459
+ close(rq->sock); rq->sock = -1;
460
+ server->cb(rq);
461
exit(0);
462
break;
463
464
default:
465
- nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: unknown request type %u", request->type);
465
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: unknown request type %u", rq->type);
466
exit(1);
467
}
468
}
@@ -714,10 +714,10 @@ static bool spawn_server_send_request(ND_UUID *magic, SPAWN_REQUEST *request) {
714
715
memcpy(CMSG_DATA(cmsg), request->fds, sizeof(int) * SPAWN_SERVER_TRANSFER_FDS);
716
717
- int rc = sendmsg(request->socket, &msg, 0);
717
+ int rc = sendmsg(request->sock, &msg, 0);
718
719
if (rc < 0) {
720
- nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN PARENT: Failed to sendmsg() request to spawn server using socket %d.", request->socket);
720
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN PARENT: Failed to sendmsg() request to spawn server using socket %d.", request->sock);
721
goto cleanup;
722
}
723
else {
@@ -737,7 +737,7 @@ static void request_free(SPAWN_REQUEST *rq) {
737
if(rq->fds[1] != -1) close(rq->fds[1]);
738
if(rq->fds[2] != -1) close(rq->fds[2]);
739
if(rq->fds[3] != -1) close(rq->fds[3]);
740
- if(rq->socket != -1) close(rq->socket);
740
+ if(rq->sock != -1) close(rq->sock);
741
freez((void *)rq->argv);
742
freez((void *)rq->environment);
743
freez((void *)rq->data);
@@ -745,6 +745,62 @@ static void request_free(SPAWN_REQUEST *rq) {
745
freez((void *)rq);
746
}
747
748
+static void spawn_server_execute_request(SPAWN_SERVER *server, SPAWN_REQUEST *rq) {
749
+ switch(rq->type) {
750
+ case SPAWN_INSTANCE_TYPE_EXEC:
751
+ if(rq->argv) {
752
+ CLEAN_BUFFER *wb = argv_to_cmdline_buffer(rq->argv);
753
+ rq->cmdline = strdupz(buffer_tostring(wb));
754
+ }
755
+ break;
756
+
757
+ case SPAWN_INSTANCE_TYPE_CALLBACK:
758
+ rq->cmdline = strdupz("callback() function");
759
+ break;
760
+
761
+ default:
762
+ rq->cmdline = strdupz("[unknown request type]");
763
+ break;
764
+ }
765
+
766
+ pid_t pid = fork();
767
+ if (pid < 0) {
768
+ // fork failed
769
+
770
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Failed to fork() child.");
771
+ spawn_server_send_status_failure(rq);
772
+ request_free(rq);
773
+ return;
774
+ }
775
+ else if (pid == 0) {
776
+ // the child
777
+
778
+ spawn_server_run_child(server, rq);
779
+ exit(63);
780
+ }
781
+
782
+ // the parent
783
+ rq->pid = pid;
784
+
785
+ // do not keep data we don't need at the parent
786
+ freez((void *)rq->environment); rq->environment = NULL;
787
+ freez((void *)rq->argv); rq->argv = NULL;
788
+ freez((void *)rq->data); rq->data = NULL;
789
+ rq->data_size = 0;
790
+
791
+ // do not keep fds we don't need at the parent
792
+ if(rq->fds[0] != -1) { close(rq->fds[0]); rq->fds[0] = -1; }
793
+ if(rq->fds[1] != -1) { close(rq->fds[1]); rq->fds[1] = -1; }
794
+ if(rq->fds[2] != -1) { close(rq->fds[2]); rq->fds[2] = -1; }
795
+ if(rq->fds[3] != -1) { close(rq->fds[3]); rq->fds[3] = -1; }
796
+
797
+ // keep it in the list
798
+ DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(spawn_server_requests, rq, prev, next);
799
+
800
+ // do not fork this socket on other children
801
+ sock_setcloexec(rq->sock);
802
+}
803
+
804
static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
805
struct msghdr msg = {0};
806
struct iovec iov[7];
@@ -881,7 +937,7 @@ static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
937
*rq = (SPAWN_REQUEST){
938
.pid = 0,
939
.request_id = request_id,
884
- .socket = sock,
940
+ .sock = sock,
941
.fds = {
942
[0] = stdin_fd,
943
[1] = stdout_fd,
@@ -895,59 +951,11 @@ static void spawn_server_receive_request(int sock, SPAWN_SERVER *server) {
951
.type = type
952
};
953
898
- switch(rq->type) {
899
- case SPAWN_INSTANCE_TYPE_EXEC:
900
- if(rq->argv) {
901
- CLEAN_BUFFER *wb = argv_to_cmdline_buffer(rq->argv);
902
- rq->cmdline = strdupz(buffer_tostring(wb));
903
- }
904
- break;
905
-
906
- case SPAWN_INSTANCE_TYPE_CALLBACK:
907
- rq->cmdline = strdupz("callback() function");
908
- break;
909
-
910
- default:
911
- rq->cmdline = strdupz("[unknown request type]");
912
- break;
913
- }
914
-
915
- pid_t pid = fork();
916
- if (pid == 0) {
917
- // the child
918
- spawn_server_run_child(server, rq);
919
- exit(63);
920
- }
921
- else if (pid > 0) {
922
- // the parent
923
- rq->pid = pid;
924
-
925
- // do not keep data we don't need at the parent
926
- freez(envp_encoded); freez((void *)rq->environment); rq->environment = NULL;
927
- freez(argv_encoded); freez((void *)rq->argv); rq->argv = NULL;
928
- freez((void *)rq->data); rq->data = NULL;
929
- rq->data_size = 0;
930
-
931
- // do not keep fds we don't need at the parent
932
- if(rq->fds[0] != -1) { close(rq->fds[0]); rq->fds[0] = -1; }
933
- if(rq->fds[1] != -1) { close(rq->fds[1]); rq->fds[1] = -1; }
934
- if(rq->fds[2] != -1) { close(rq->fds[2]); rq->fds[2] = -1; }
935
- if(rq->fds[3] != -1) { close(rq->fds[3]); rq->fds[3] = -1; }
936
-
937
- // keep it in the list
938
- DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(spawn_server_requests, rq, prev, next);
939
-
940
- // do not fork this socket on other children
941
- sock_setcloexec(rq->socket);
942
-
943
- // done with this
944
- return;
945
- }
954
+ // all allocations given to the request are now handled by this
955
+ spawn_server_execute_request(server, rq);
956
947
- nd_log(NDLS_COLLECTORS, NDLP_ERR, "SPAWN SERVER: Failed to fork() child.");
948
- spawn_server_send_status_failure(stdout_fd);
949
- // the other allocations (envp, argv, data) will be free'd at cleanup
950
- request_free(rq);
957
+ // since we make rq->argv and rq->environment NULL when we keep it,
958
+ // we don't need these anymore.
959
freez(envp_encoded);
960
freez(argv_encoded);
961
return;
@@ -1037,7 +1045,7 @@ static void spawn_server_process_sigchld(void) {
1045
}
1046
1047
if(send_report_remove_request && rq) {
1040
- spawn_server_send_status_exit(rq->socket, status);
1048
+ spawn_server_send_status_exit(rq, status);
1049
DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(spawn_server_requests, rq, prev, next);
1050
request_free(rq);
1051
}
@@ -1398,7 +1406,7 @@ SPAWN_INSTANCE* spawn_server_exec(SPAWN_SERVER *server, int stderr_fd, int custo
1406
1407
SPAWN_REQUEST request = {
1408
.request_id = __atomic_add_fetch(&server->request_id, 1, __ATOMIC_RELAXED),
1401
- .socket = instance->client_sock,
1409
+ .sock = instance->client_sock,
1410
.fds = {
1411
[0] = pipe_stdin[0],
1412
[1] = pipe_stdout[1],
src/libnetdata/spawn_server/spawn_server.h
+11
-10
@@ -22,17 +22,18 @@ typedef enum __attribute__((packed)) {
22
// this is only used publicly for SPAWN_INSTANCE_TYPE_CALLBACK
23
// which is not available in Windows
24
typedef struct spawn_request {
25
- const char *cmdline;
26
- size_t request_id;
27
- pid_t pid;
28
- int socket;
25
+ const char *cmdline; // the cmd line of the command we should run
26
+ size_t request_id; // the incremental request id
27
+ pid_t pid; // the pid of the child
28
+ int sock; // the socket for this request
29
int fds[SPAWN_SERVER_TRANSFER_FDS]; // 0 = stdin, 1 = stdout, 2 = stderr, 3 = custom
30
- const char **environment;
31
- const char **argv;
32
- const void *data;
33
- size_t data_size;
34
- SPAWN_INSTANCE_TYPE type;
35
- struct spawn_request *prev, *next;
30
+ const char **environment; // the environment of the parent process
31
+ const char **argv; // the command line and its parameters
32
+ const void *data; // the data structure for the callback
33
+ size_t data_size; // the data structure size
34
+ SPAWN_INSTANCE_TYPE type; // the type of the request
35
+
36
+ struct spawn_request *prev, *next; // linking of active requests at the spawn server
37
} SPAWN_REQUEST;
38
39
typedef void (*spawn_request_callback_t)(SPAWN_REQUEST *request);