diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-06-23 14:23:50 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-06-23 14:23:50 +0000 |
commit | 13a7da212738f9c76c0772ca7726f91885e588d2 (patch) | |
tree | b0f5472ade2ac23c955adf9d064e289d17c1734e | |
parent | 539288eab5294b4c29c1d43cb6f085cc88ce077c (diff) | |
download | gnunet-13a7da212738f9c76c0772ca7726f91885e588d2.tar.gz gnunet-13a7da212738f9c76c0772ca7726f91885e588d2.zip |
listen socket passing support for ARM
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | src/arm/arm_api.c | 3 | ||||
-rw-r--r-- | src/arm/do_start_process.c | 6 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm.c | 34 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm.h | 13 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm_interceptor.c | 86 | ||||
-rw-r--r-- | src/include/gnunet_network_lib.h | 1 | ||||
-rw-r--r-- | src/include/gnunet_os_lib.h | 5 | ||||
-rw-r--r-- | src/util/os_priority.c | 74 |
9 files changed, 196 insertions, 31 deletions
@@ -1,3 +1,8 @@ | |||
1 | Wed Jun 23 16:34:38 CEST 2010 | ||
2 | Added support for systemd-compatible passing of listen-sockets | ||
3 | by ARM to services as well as systemd compatibility for gnunet-service-arm | ||
4 | itself. At least for non-MINGW systems this should work. | ||
5 | |||
1 | Sat Jun 5 18:08:39 CEST 2010 | 6 | Sat Jun 5 18:08:39 CEST 2010 |
2 | Added support for UNIX domain sockets, code also defaults to | 7 | Added support for UNIX domain sockets, code also defaults to |
3 | them when available. | 8 | them when available. |
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c index 083031e78..6c2b53a71 100644 --- a/src/arm/arm_api.c +++ b/src/arm/arm_api.c | |||
@@ -434,7 +434,8 @@ arm_service_report (void *cls, | |||
434 | GNUNET_free (lopostfix); | 434 | GNUNET_free (lopostfix); |
435 | return; | 435 | return; |
436 | } | 436 | } |
437 | pid = do_start_process (loprefix, | 437 | pid = do_start_process (NULL, |
438 | loprefix, | ||
438 | binary, | 439 | binary, |
439 | "-c", config, | 440 | "-c", config, |
440 | #if DEBUG_ARM | 441 | #if DEBUG_ARM |
diff --git a/src/arm/do_start_process.c b/src/arm/do_start_process.c index 357d39920..d616ac2b7 100644 --- a/src/arm/do_start_process.c +++ b/src/arm/do_start_process.c | |||
@@ -7,12 +7,14 @@ | |||
7 | * limitation that it does NOT allow passing command line arguments | 7 | * limitation that it does NOT allow passing command line arguments |
8 | * with spaces to the new process. | 8 | * with spaces to the new process. |
9 | * | 9 | * |
10 | * @param lsocks array of listen sockets to dup starting at fd3 (systemd-style), or NULL | ||
10 | * @param first_arg first argument for argv (may be an empty string) | 11 | * @param first_arg first argument for argv (may be an empty string) |
11 | * @param ... more arguments, NULL terminated | 12 | * @param ... more arguments, NULL terminated |
12 | * @return PID of the started process, -1 on error | 13 | * @return PID of the started process, -1 on error |
13 | */ | 14 | */ |
14 | static pid_t | 15 | static pid_t |
15 | do_start_process (const char *first_arg, ...) | 16 | do_start_process (const int *lsocks, |
17 | const char *first_arg, ...) | ||
16 | { | 18 | { |
17 | va_list ap; | 19 | va_list ap; |
18 | char **argv; | 20 | char **argv; |
@@ -86,7 +88,7 @@ do_start_process (const char *first_arg, ...) | |||
86 | while (NULL != (arg = (va_arg (ap, const char*)))); | 88 | while (NULL != (arg = (va_arg (ap, const char*)))); |
87 | va_end (ap); | 89 | va_end (ap); |
88 | argv[argv_size] = NULL; | 90 | argv[argv_size] = NULL; |
89 | pid = GNUNET_OS_start_process_v (argv[0], argv); | 91 | pid = GNUNET_OS_start_process_v (lsocks, argv[0], argv); |
90 | while (argv_size > 0) | 92 | while (argv_size > 0) |
91 | GNUNET_free (argv[--argv_size]); | 93 | GNUNET_free (argv[--argv_size]); |
92 | GNUNET_free (argv); | 94 | GNUNET_free (argv); |
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index ab96906a7..59f48a58c 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c | |||
@@ -344,7 +344,8 @@ free_entry (struct ServiceList *pos) | |||
344 | * @param sl identifies service to start | 344 | * @param sl identifies service to start |
345 | */ | 345 | */ |
346 | static void | 346 | static void |
347 | start_process (struct ServiceList *sl) | 347 | start_process (struct ServiceList *sl, |
348 | const int *lsocks) | ||
348 | { | 349 | { |
349 | char *loprefix; | 350 | char *loprefix; |
350 | char *options; | 351 | char *options; |
@@ -415,14 +416,16 @@ start_process (struct ServiceList *sl) | |||
415 | sl->name, sl->binary, sl->config); | 416 | sl->name, sl->binary, sl->config); |
416 | #endif | 417 | #endif |
417 | if (GNUNET_YES == use_debug) | 418 | if (GNUNET_YES == use_debug) |
418 | sl->pid = do_start_process (loprefix, | 419 | sl->pid = do_start_process (lsocks, |
420 | loprefix, | ||
419 | sl->binary, | 421 | sl->binary, |
420 | "-c", sl->config, | 422 | "-c", sl->config, |
421 | "-L", "DEBUG", | 423 | "-L", "DEBUG", |
422 | options, | 424 | options, |
423 | NULL); | 425 | NULL); |
424 | else | 426 | else |
425 | sl->pid = do_start_process (loprefix, | 427 | sl->pid = do_start_process (lsocks, |
428 | loprefix, | ||
426 | sl->binary, | 429 | sl->binary, |
427 | "-c", sl->config, | 430 | "-c", sl->config, |
428 | options, | 431 | options, |
@@ -442,9 +445,13 @@ start_process (struct ServiceList *sl) | |||
442 | * | 445 | * |
443 | * @param client who is asking for this | 446 | * @param client who is asking for this |
444 | * @param servicename name of the service to start | 447 | * @param servicename name of the service to start |
448 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL | ||
449 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | ||
445 | */ | 450 | */ |
446 | void | 451 | int |
447 | start_service (struct GNUNET_SERVER_Client *client, const char *servicename) | 452 | start_service (struct GNUNET_SERVER_Client *client, |
453 | const char *servicename, | ||
454 | const int *lsocks) | ||
448 | { | 455 | { |
449 | struct ServiceList *sl; | 456 | struct ServiceList *sl; |
450 | char *binary; | 457 | char *binary; |
@@ -457,7 +464,7 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename) | |||
457 | _("ARM is shutting down, service `%s' not started.\n"), | 464 | _("ARM is shutting down, service `%s' not started.\n"), |
458 | servicename); | 465 | servicename); |
459 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); | 466 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); |
460 | return; | 467 | return GNUNET_SYSERR; |
461 | } | 468 | } |
462 | sl = find_name (servicename); | 469 | sl = find_name (servicename); |
463 | if (sl != NULL) | 470 | if (sl != NULL) |
@@ -467,7 +474,7 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename) | |||
467 | sl->next = running; | 474 | sl->next = running; |
468 | running = sl; | 475 | running = sl; |
469 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP); | 476 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP); |
470 | return; | 477 | return GNUNET_SYSERR; |
471 | } | 478 | } |
472 | if (GNUNET_OK != | 479 | if (GNUNET_OK != |
473 | GNUNET_CONFIGURATION_get_value_string (cfg, | 480 | GNUNET_CONFIGURATION_get_value_string (cfg, |
@@ -477,7 +484,7 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename) | |||
477 | _("Binary implementing service `%s' not known!\n"), | 484 | _("Binary implementing service `%s' not known!\n"), |
478 | servicename); | 485 | servicename); |
479 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); | 486 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); |
480 | return; | 487 | return GNUNET_SYSERR; |
481 | } | 488 | } |
482 | if ((GNUNET_OK != | 489 | if ((GNUNET_OK != |
483 | GNUNET_CONFIGURATION_get_value_filename (cfg, | 490 | GNUNET_CONFIGURATION_get_value_filename (cfg, |
@@ -492,7 +499,7 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename) | |||
492 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); | 499 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_DOWN); |
493 | GNUNET_free (binary); | 500 | GNUNET_free (binary); |
494 | GNUNET_free_non_null (config); | 501 | GNUNET_free_non_null (config); |
495 | return; | 502 | return GNUNET_SYSERR; |
496 | } | 503 | } |
497 | (void) stop_listening (servicename); | 504 | (void) stop_listening (servicename); |
498 | sl = GNUNET_malloc (sizeof (struct ServiceList)); | 505 | sl = GNUNET_malloc (sizeof (struct ServiceList)); |
@@ -505,9 +512,10 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename) | |||
505 | sl->restartAt = GNUNET_TIME_UNIT_FOREVER_ABS; | 512 | sl->restartAt = GNUNET_TIME_UNIT_FOREVER_ABS; |
506 | 513 | ||
507 | running = sl; | 514 | running = sl; |
508 | start_process (sl); | 515 | start_process (sl, lsocks); |
509 | if (NULL != client) | 516 | if (NULL != client) |
510 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP); | 517 | signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP); |
518 | return GNUNET_OK; | ||
511 | } | 519 | } |
512 | 520 | ||
513 | 521 | ||
@@ -610,7 +618,7 @@ handle_start (void *cls, | |||
610 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 618 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
611 | return; | 619 | return; |
612 | } | 620 | } |
613 | start_service (client, servicename); | 621 | start_service (client, servicename, NULL); |
614 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 622 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
615 | } | 623 | } |
616 | 624 | ||
@@ -776,7 +784,7 @@ delayed_restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
776 | { | 784 | { |
777 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 785 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
778 | _("Restarting service `%s'.\n"), pos->name); | 786 | _("Restarting service `%s'.\n"), pos->name); |
779 | start_process (pos); | 787 | start_process (pos, NULL); |
780 | } | 788 | } |
781 | else | 789 | else |
782 | { | 790 | { |
@@ -1071,7 +1079,7 @@ run (void *cls, | |||
1071 | pos = strtok (defaultservices, " "); | 1079 | pos = strtok (defaultservices, " "); |
1072 | while (pos != NULL) | 1080 | while (pos != NULL) |
1073 | { | 1081 | { |
1074 | start_service (NULL, pos); | 1082 | start_service (NULL, pos, NULL); |
1075 | pos = strtok (NULL, " "); | 1083 | pos = strtok (NULL, " "); |
1076 | } | 1084 | } |
1077 | } | 1085 | } |
diff --git a/src/arm/gnunet-service-arm.h b/src/arm/gnunet-service-arm.h index 77dfb8c6c..632b46b09 100644 --- a/src/arm/gnunet-service-arm.h +++ b/src/arm/gnunet-service-arm.h | |||
@@ -27,8 +27,17 @@ | |||
27 | #ifndef GNUNET_SERVICE_ARM__H | 27 | #ifndef GNUNET_SERVICE_ARM__H |
28 | #define GNUNET_SERVICE_ARM__H | 28 | #define GNUNET_SERVICE_ARM__H |
29 | 29 | ||
30 | void start_service (struct GNUNET_SERVER_Client *client, | 30 | /** |
31 | const char *servicename); | 31 | * Start the specified service. |
32 | * | ||
33 | * @param client who is asking for this | ||
34 | * @param servicename name of the service to start | ||
35 | * @param lsocks -1 terminated list of listen sockets to pass (systemd style), or NULL | ||
36 | * @return GNUNET_OK on success | ||
37 | */ | ||
38 | int start_service (struct GNUNET_SERVER_Client *client, | ||
39 | const char *servicename, | ||
40 | const int *lsocks); | ||
32 | 41 | ||
33 | /** | 42 | /** |
34 | * Stop listening for connections to a service. | 43 | * Stop listening for connections to a service. |
diff --git a/src/arm/gnunet-service-arm_interceptor.c b/src/arm/gnunet-service-arm_interceptor.c index 9380a8deb..bc8db396b 100644 --- a/src/arm/gnunet-service-arm_interceptor.c +++ b/src/arm/gnunet-service-arm_interceptor.c | |||
@@ -847,7 +847,6 @@ stop_listening (const char *serviceName) | |||
847 | return ret; | 847 | return ret; |
848 | } | 848 | } |
849 | 849 | ||
850 | |||
851 | /** | 850 | /** |
852 | * First connection has come to the listening socket associated with the service, | 851 | * First connection has come to the listening socket associated with the service, |
853 | * create the service in order to relay the incoming connection to it | 852 | * create the service in order to relay the incoming connection to it |
@@ -856,14 +855,15 @@ stop_listening (const char *serviceName) | |||
856 | * @param tc context | 855 | * @param tc context |
857 | */ | 856 | */ |
858 | static void | 857 | static void |
859 | acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 858 | acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); |
859 | |||
860 | |||
861 | #if MINGW | ||
862 | static void | ||
863 | accept_and_forward (struct ServiceListeningInfo *serviceListeningInfo) | ||
860 | { | 864 | { |
861 | struct ServiceListeningInfo *serviceListeningInfo = cls; | ||
862 | struct ForwardedConnection *fc; | 865 | struct ForwardedConnection *fc; |
863 | 866 | ||
864 | serviceListeningInfo->acceptTask = GNUNET_SCHEDULER_NO_TASK; | ||
865 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) | ||
866 | return; | ||
867 | fc = GNUNET_malloc (sizeof (struct ForwardedConnection)); | 867 | fc = GNUNET_malloc (sizeof (struct ForwardedConnection)); |
868 | fc->listen_info = serviceListeningInfo; | 868 | fc->listen_info = serviceListeningInfo; |
869 | fc->service_to_client_bufferPos = fc->service_to_client_buffer; | 869 | fc->service_to_client_bufferPos = fc->service_to_client_buffer; |
@@ -879,6 +879,9 @@ acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
879 | serviceListeningInfo->serviceName, | 879 | serviceListeningInfo->serviceName, |
880 | STRERROR (errno)); | 880 | STRERROR (errno)); |
881 | GNUNET_free (fc); | 881 | GNUNET_free (fc); |
882 | GNUNET_CONTAINER_DLL_insert (serviceListeningInfoList_head, | ||
883 | serviceListeningInfoList_tail, | ||
884 | serviceListeningInfo); | ||
882 | serviceListeningInfo->acceptTask = | 885 | serviceListeningInfo->acceptTask = |
883 | GNUNET_SCHEDULER_add_read_net (scheduler, | 886 | GNUNET_SCHEDULER_add_read_net (scheduler, |
884 | GNUNET_TIME_UNIT_FOREVER_REL, | 887 | GNUNET_TIME_UNIT_FOREVER_REL, |
@@ -889,10 +892,7 @@ acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
889 | } | 892 | } |
890 | GNUNET_break (GNUNET_OK == | 893 | GNUNET_break (GNUNET_OK == |
891 | GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket)); | 894 | GNUNET_NETWORK_socket_close (serviceListeningInfo->listeningSocket)); |
892 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | 895 | start_service (NULL, serviceListeningInfo->serviceName, NULL); |
893 | serviceListeningInfoList_tail, | ||
894 | serviceListeningInfo); | ||
895 | start_service (NULL, serviceListeningInfo->serviceName); | ||
896 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 896 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
897 | _("Service `%s' started\n"), | 897 | _("Service `%s' started\n"), |
898 | fc->listen_info->serviceName); | 898 | fc->listen_info->serviceName); |
@@ -909,6 +909,72 @@ acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
909 | &start_forwarding, | 909 | &start_forwarding, |
910 | fc); | 910 | fc); |
911 | } | 911 | } |
912 | #endif | ||
913 | |||
914 | |||
915 | /** | ||
916 | * First connection has come to the listening socket associated with the service, | ||
917 | * create the service in order to relay the incoming connection to it | ||
918 | * | ||
919 | * @param cls callback data, struct ServiceListeningInfo describing a listen socket | ||
920 | * @param tc context | ||
921 | */ | ||
922 | static void | ||
923 | acceptConnection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
924 | { | ||
925 | struct ServiceListeningInfo *sli = cls; | ||
926 | struct ServiceListeningInfo *pos; | ||
927 | struct ServiceListeningInfo *next; | ||
928 | int *lsocks; | ||
929 | unsigned int ls; | ||
930 | |||
931 | sli->acceptTask = GNUNET_SCHEDULER_NO_TASK; | ||
932 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) | ||
933 | return; | ||
934 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
935 | serviceListeningInfoList_tail, | ||
936 | sli); | ||
937 | #ifndef MINGW | ||
938 | lsocks = NULL; | ||
939 | ls = 0; | ||
940 | next = serviceListeningInfoList_head; | ||
941 | while (NULL != (pos = next)) | ||
942 | { | ||
943 | next = pos->next; | ||
944 | if (0 == strcmp (pos->serviceName, | ||
945 | sli->serviceName)) | ||
946 | { | ||
947 | GNUNET_array_append (lsocks, ls, | ||
948 | GNUNET_NETWORK_get_fd (pos->listeningSocket)); | ||
949 | GNUNET_free (pos->listeningSocket); /* deliberately no closing! */ | ||
950 | GNUNET_free (pos->service_addr); | ||
951 | GNUNET_free (pos->serviceName); | ||
952 | GNUNET_SCHEDULER_cancel (scheduler, | ||
953 | pos->acceptTask); | ||
954 | GNUNET_CONTAINER_DLL_remove (serviceListeningInfoList_head, | ||
955 | serviceListeningInfoList_tail, | ||
956 | pos); | ||
957 | GNUNET_free (pos); | ||
958 | } | ||
959 | } | ||
960 | GNUNET_array_append (lsocks, ls, | ||
961 | GNUNET_NETWORK_get_fd (sli->listeningSocket)); | ||
962 | GNUNET_free (sli->listeningSocket); /* deliberately no closing! */ | ||
963 | GNUNET_free (sli->service_addr); | ||
964 | GNUNET_array_append (lsocks, ls, -1); | ||
965 | start_service (NULL, | ||
966 | sli->serviceName, | ||
967 | lsocks); | ||
968 | ls = 0; | ||
969 | while (lsocks[ls] != -1) | ||
970 | GNUNET_break (0 == close (lsocks[ls++])); | ||
971 | GNUNET_array_grow (lsocks, ls, 0); | ||
972 | GNUNET_free (sli->serviceName); | ||
973 | GNUNET_free (sli); | ||
974 | #else | ||
975 | accept_and_forward (sli); | ||
976 | #endif | ||
977 | } | ||
912 | 978 | ||
913 | 979 | ||
914 | /** | 980 | /** |
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h index d7d3acbf0..19fd234ee 100644 --- a/src/include/gnunet_network_lib.h +++ b/src/include/gnunet_network_lib.h | |||
@@ -199,6 +199,7 @@ int GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
199 | ssize_t GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc, | 199 | ssize_t GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc, |
200 | const void *buffer, size_t length); | 200 | const void *buffer, size_t length); |
201 | 201 | ||
202 | |||
202 | /** | 203 | /** |
203 | * Send data to a particular destination (always non-blocking). | 204 | * Send data to a particular destination (always non-blocking). |
204 | * This function only works for UDP sockets. | 205 | * This function only works for UDP sockets. |
diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h index 3aa1f1bad..87d9a8fb1 100644 --- a/src/include/gnunet_os_lib.h +++ b/src/include/gnunet_os_lib.h | |||
@@ -216,12 +216,15 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin, | |||
216 | /** | 216 | /** |
217 | * Start a process. | 217 | * Start a process. |
218 | * | 218 | * |
219 | * @param lsocks array of listen sockets to dup systemd-style (or NULL); | ||
220 | * must be NULL on platforms where dup is not supported | ||
219 | * @param filename name of the binary | 221 | * @param filename name of the binary |
220 | * @param argv NULL-terminated list of arguments to the process, | 222 | * @param argv NULL-terminated list of arguments to the process, |
221 | * including the process name as the first argument | 223 | * including the process name as the first argument |
222 | * @return process ID of the new process, -1 on error | 224 | * @return process ID of the new process, -1 on error |
223 | */ | 225 | */ |
224 | pid_t GNUNET_OS_start_process_v (const char *filename, char *const argv[]); | 226 | pid_t GNUNET_OS_start_process_v (const int *lsocks, |
227 | const char *filename, char *const argv[]); | ||
225 | 228 | ||
226 | 229 | ||
227 | /** | 230 | /** |
diff --git a/src/util/os_priority.c b/src/util/os_priority.c index b354ad995..7a6f0d65d 100644 --- a/src/util/os_priority.c +++ b/src/util/os_priority.c | |||
@@ -329,16 +329,43 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin, | |||
329 | /** | 329 | /** |
330 | * Start a process. | 330 | * Start a process. |
331 | * | 331 | * |
332 | * @param lsocks array of listen sockets to dup systemd-style (or NULL); | ||
333 | * must be NULL on platforms where dup is not supported | ||
332 | * @param filename name of the binary | 334 | * @param filename name of the binary |
333 | * @param argv NULL-terminated list of arguments to the process | 335 | * @param argv NULL-terminated list of arguments to the process |
334 | * @return process ID of the new process, -1 on error | 336 | * @return process ID of the new process, -1 on error |
335 | */ | 337 | */ |
336 | pid_t | 338 | pid_t |
337 | GNUNET_OS_start_process_v (const char *filename, char *const argv[]) | 339 | GNUNET_OS_start_process_v (const int *lsocks, |
340 | const char *filename, char *const argv[]) | ||
338 | { | 341 | { |
339 | #ifndef MINGW | 342 | #ifndef MINGW |
340 | pid_t ret; | 343 | pid_t ret; |
341 | 344 | char lpid[16]; | |
345 | char fds[16]; | ||
346 | int i; | ||
347 | int j; | ||
348 | int k; | ||
349 | int tgt; | ||
350 | int flags; | ||
351 | int *lscp; | ||
352 | unsigned int ls; | ||
353 | |||
354 | lscp = NULL; | ||
355 | ls = 0; | ||
356 | if (lsocks != NULL) | ||
357 | { | ||
358 | i = 0; | ||
359 | while (-1 != (k = lsocks[i++])) | ||
360 | { | ||
361 | flags = fcntl (k, F_GETFD); | ||
362 | GNUNET_assert (flags >= 0); | ||
363 | flags &= ~FD_CLOEXEC; | ||
364 | (void) fcntl (k, F_SETFD, flags); | ||
365 | GNUNET_array_append (lscp, ls, k); | ||
366 | } | ||
367 | GNUNET_array_append (lscp, ls, -1); | ||
368 | } | ||
342 | #if HAVE_WORKING_VFORK | 369 | #if HAVE_WORKING_VFORK |
343 | ret = vfork (); | 370 | ret = vfork (); |
344 | #else | 371 | #else |
@@ -366,6 +393,48 @@ GNUNET_OS_start_process_v (const char *filename, char *const argv[]) | |||
366 | } | 393 | } |
367 | return ret; | 394 | return ret; |
368 | } | 395 | } |
396 | if (lscp != NULL) | ||
397 | { | ||
398 | /* read systemd documentation... */ | ||
399 | GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid()); | ||
400 | setenv ("LISTEN_PID", lpid, 1); | ||
401 | i = 0; | ||
402 | tgt = 3; | ||
403 | while (-1 != lscp[i]) | ||
404 | { | ||
405 | j = i + 1; | ||
406 | while (-1 != lscp[j]) | ||
407 | { | ||
408 | if (lscp[j] == tgt) | ||
409 | { | ||
410 | /* dup away */ | ||
411 | k = dup (lscp[j]); | ||
412 | GNUNET_assert (-1 != k); | ||
413 | GNUNET_assert (0 == close (lscp[j])); | ||
414 | lscp[j] = k; | ||
415 | break; | ||
416 | } | ||
417 | j++; | ||
418 | } | ||
419 | if (lscp[i] != tgt) | ||
420 | { | ||
421 | /* Bury any existing FD, no matter what; they should all be closed | ||
422 | on exec anyway and the important onces have been dup'ed away */ | ||
423 | (void) close (tgt); | ||
424 | GNUNET_assert (-1 != dup2 (lscp[i], tgt)); | ||
425 | } | ||
426 | /* set close-on-exec flag */ | ||
427 | flags = fcntl (tgt, F_GETFD); | ||
428 | GNUNET_assert (flags >= 0); | ||
429 | flags &= ~FD_CLOEXEC; | ||
430 | (void) fcntl (tgt, F_SETFD, flags); | ||
431 | tgt++; | ||
432 | i++; | ||
433 | } | ||
434 | GNUNET_snprintf (fds, sizeof (fds), "%u", i); | ||
435 | setenv ("LISTEN_FDS", fds, 1); | ||
436 | } | ||
437 | GNUNET_array_grow (lscp, ls, 0); | ||
369 | execvp (filename, argv); | 438 | execvp (filename, argv); |
370 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); | 439 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); |
371 | _exit (1); | 440 | _exit (1); |
@@ -379,6 +448,7 @@ GNUNET_OS_start_process_v (const char *filename, char *const argv[]) | |||
379 | char *non_const_filename = NULL; | 448 | char *non_const_filename = NULL; |
380 | int filenamelen = 0; | 449 | int filenamelen = 0; |
381 | 450 | ||
451 | GNUNET_assert (lsocks == NULL); | ||
382 | /* Count the number of arguments */ | 452 | /* Count the number of arguments */ |
383 | arg = argv; | 453 | arg = argv; |
384 | while (*arg) | 454 | while (*arg) |