GNUnet 0.21.1
gnunet-service-arm.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2011, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
29#include "gnunet_protocols.h"
30#include "arm.h"
31
32#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
33
34#define LOG_STRERROR(kind, syscall) \
35 GNUNET_log_from_strerror (kind, "util", syscall)
36
37
38#if HAVE_WAIT4
42static char *wait_filename;
43
47static FILE *wait_file;
48#endif
49
50
56#define MAX_NOTIFY_QUEUE 1024
57
58
62struct ServiceList;
63
64
69{
74
79
83 struct sockaddr *service_addr;
84
88 struct ServiceList *sl;
89
94
99
104};
105
106
111{
116
121
126
131
135 char *name;
136
140 char *binary;
141
145 char *config;
146
152
157
162
167
172
177
183
190
196
201};
202
207
212
216static const struct GNUNET_CONFIGURATION_Handle *cfg;
217
221static char *prefix_command;
222
226static char *final_option;
227
232
238
243
247static int in_shutdown;
248
252static int global_ret;
253
258
263
275
280
281
292static void
293add_unixpath (struct sockaddr **saddrs,
294 socklen_t *saddrlens,
295 const char *unixpath,
296 int abstract)
297{
298#ifdef AF_UNIX
299 struct sockaddr_un *un;
300
301 un = GNUNET_new (struct sockaddr_un);
302 un->sun_family = AF_UNIX;
303 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
304#ifdef __linux__
305 if (GNUNET_YES == abstract)
306 un->sun_path[0] = '\0';
307#endif
308#if HAVE_SOCKADDR_UN_SUN_LEN
309 un->sun_len = (u_char) sizeof(struct sockaddr_un);
310#endif
311 *saddrs = (struct sockaddr *) un;
312 *saddrlens = sizeof(struct sockaddr_un);
313#else
314 /* this function should never be called
315 * unless AF_UNIX is defined! */
316 GNUNET_assert (0);
317#endif
318}
319
320
341static int
343 const struct GNUNET_CONFIGURATION_Handle *cfg,
344 struct sockaddr ***addrs,
345 socklen_t **addr_lens)
346{
347 int disablev6;
348 struct GNUNET_NETWORK_Handle *desc;
349 unsigned long long port;
350 char *unixpath;
351 struct addrinfo hints;
352 struct addrinfo *res;
353 struct addrinfo *pos;
354 struct addrinfo *next;
355 unsigned int i;
356 int resi;
357 int ret;
358 int abstract;
359 struct sockaddr **saddrs;
360 socklen_t *saddrlens;
361 char *hostname;
362
363 *addrs = NULL;
364 *addr_lens = NULL;
365 desc = NULL;
367 {
368 if (GNUNET_SYSERR ==
371 "DISABLEV6")))
372 return GNUNET_SYSERR;
373 }
374 else
375 disablev6 = GNUNET_NO;
376
377 if (! disablev6)
378 {
379 /* probe IPv6 support */
380 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
381 if (NULL == desc)
382 {
383 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
384 (EACCES == errno))
385 {
387 return GNUNET_SYSERR;
388 }
390 _ (
391 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
393 strerror (errno));
394 disablev6 = GNUNET_YES;
395 }
396 else
397 {
399 desc = NULL;
400 }
401 }
402
403 port = 0;
405 {
408 "PORT",
409 &port))
410 {
412 _ ("Require valid port number for service `%s' in configuration!\n"),
414 }
415 if (port > 65535)
416 {
418 _ ("Require valid port number for service `%s' in configuration!\n"),
420 return GNUNET_SYSERR;
421 }
422 }
423
425 {
429 "BINDTO",
430 &hostname));
431 }
432 else
433 hostname = NULL;
434
435 unixpath = NULL;
436 abstract = GNUNET_NO;
437#ifdef AF_UNIX
438 if ((GNUNET_YES ==
442 "UNIXPATH",
443 &unixpath)) &&
444 (0 < strlen (unixpath)))
445 {
446 /* probe UNIX support */
447 struct sockaddr_un s_un;
448
449 if (strlen (unixpath) >= sizeof(s_un.sun_path))
450 {
452 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
453 unixpath,
454 (unsigned long long) sizeof(s_un.sun_path));
455 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
456 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
457 }
458#ifdef __linux__
460 "TESTING",
461 "USE_ABSTRACT_SOCKETS");
462 if (GNUNET_SYSERR == abstract)
463 abstract = GNUNET_NO;
464#endif
465 if ((GNUNET_YES != abstract) &&
468 }
469 if (NULL != unixpath)
470 {
471 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
472 if (NULL == desc)
473 {
474 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
475 (EACCES == errno))
476 {
478 GNUNET_free (hostname);
479 GNUNET_free (unixpath);
480 return GNUNET_SYSERR;
481 }
483 _ (
484 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
486 strerror (errno));
487 GNUNET_free (unixpath);
488 unixpath = NULL;
489 }
490 else
491 {
493 desc = NULL;
494 }
495 }
496#endif
497
498 if ((0 == port) && (NULL == unixpath))
499 {
502 "START_ON_DEMAND"))
504 _ (
505 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
507 GNUNET_free (hostname);
508 return GNUNET_SYSERR;
509 }
510 if (0 == port)
511 {
512 saddrs = GNUNET_new_array (2, struct sockaddr *);
513 saddrlens = GNUNET_new_array (2, socklen_t);
514 add_unixpath (saddrs, saddrlens, unixpath, abstract);
515 GNUNET_free (unixpath);
516 GNUNET_free (hostname);
517 *addrs = saddrs;
518 *addr_lens = saddrlens;
519 return 1;
520 }
521
522 if (NULL != hostname)
523 {
525 "Resolving `%s' since that is where `%s' will bind to.\n",
526 hostname,
528 memset (&hints, 0, sizeof(struct addrinfo));
529 if (disablev6)
530 hints.ai_family = AF_INET;
531 hints.ai_protocol = IPPROTO_TCP;
532 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
533 (NULL == res))
534 {
536 _ ("Failed to resolve `%s': %s\n"),
537 hostname,
538 gai_strerror (ret));
539 GNUNET_free (hostname);
540 GNUNET_free (unixpath);
541 return GNUNET_SYSERR;
542 }
543 next = res;
544 i = 0;
545 while (NULL != (pos = next))
546 {
547 next = pos->ai_next;
548 if ((disablev6) && (pos->ai_family == AF_INET6))
549 continue;
550 i++;
551 }
552 if (0 == i)
553 {
555 _ ("Failed to find %saddress for `%s'.\n"),
556 disablev6 ? "IPv4 " : "",
557 hostname);
558 freeaddrinfo (res);
559 GNUNET_free (hostname);
560 GNUNET_free (unixpath);
561 return GNUNET_SYSERR;
562 }
563 resi = i;
564 if (NULL != unixpath)
565 resi++;
566 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
567 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
568 i = 0;
569 if (NULL != unixpath)
570 {
571 add_unixpath (saddrs, saddrlens, unixpath, abstract);
572 i++;
573 }
574 next = res;
575 while (NULL != (pos = next))
576 {
577 next = pos->ai_next;
578 if ((disablev6) && (AF_INET6 == pos->ai_family))
579 continue;
580 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
581 continue; /* not TCP */
582 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
583 continue; /* huh? */
585 "Service `%s' will bind to `%s'\n",
587 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
588 if (AF_INET == pos->ai_family)
589 {
590 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
591 saddrlens[i] = pos->ai_addrlen;
592 saddrs[i] = GNUNET_malloc (saddrlens[i]);
593 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
594 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
595 }
596 else
597 {
598 GNUNET_assert (AF_INET6 == pos->ai_family);
599 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
600 saddrlens[i] = pos->ai_addrlen;
601 saddrs[i] = GNUNET_malloc (saddrlens[i]);
602 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
603 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
604 }
605 i++;
606 }
607 GNUNET_free (hostname);
608 freeaddrinfo (res);
609 resi = i;
610 }
611 else
612 {
613 /* will bind against everything, just set port */
614 if (disablev6)
615 {
616 /* V4-only */
617 resi = 1;
618 if (NULL != unixpath)
619 resi++;
620 i = 0;
621 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
622 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
623 if (NULL != unixpath)
624 {
625 add_unixpath (saddrs, saddrlens, unixpath, abstract);
626 i++;
627 }
628 saddrlens[i] = sizeof(struct sockaddr_in);
629 saddrs[i] = GNUNET_malloc (saddrlens[i]);
630#if HAVE_SOCKADDR_IN_SIN_LEN
631 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
632#endif
633 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
634 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
635 }
636 else
637 {
638 /* dual stack */
639 resi = 2;
640 if (NULL != unixpath)
641 resi++;
642 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
643 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
644 i = 0;
645 if (NULL != unixpath)
646 {
647 add_unixpath (saddrs, saddrlens, unixpath, abstract);
648 i++;
649 }
650 saddrlens[i] = sizeof(struct sockaddr_in6);
651 saddrs[i] = GNUNET_malloc (saddrlens[i]);
652#if HAVE_SOCKADDR_IN_SIN_LEN
653 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
654#endif
655 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
656 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
657 i++;
658 saddrlens[i] = sizeof(struct sockaddr_in);
659 saddrs[i] = GNUNET_malloc (saddrlens[i]);
660#if HAVE_SOCKADDR_IN_SIN_LEN
661 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
662#endif
663 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
664 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
665 }
666 }
667 GNUNET_free (unixpath);
668 *addrs = saddrs;
669 *addr_lens = saddrlens;
670 return resi;
671}
672
673
684static void
686 const char *name,
687 uint64_t request_id,
689{
690 struct GNUNET_MQ_Envelope *env;
692
693 (void) name;
695 msg->result = htonl (result);
696 msg->arm_msg.request_id = GNUNET_htonll (request_id);
698}
699
700
709static void
712 struct GNUNET_SERVICE_Client *unicast)
713{
714 struct GNUNET_MQ_Envelope *env;
716 size_t namelen;
717
719 "Sending status %u of service `%s' to client\n",
720 (unsigned int) status,
721 name);
722 namelen = strlen (name) + 1;
724 msg->status = htonl ((uint32_t) (status));
725 GNUNET_memcpy ((char *) &msg[1], name, namelen);
726 if (NULL == unicast)
727 {
728 if (NULL != notifier)
730 &msg->header,
731 GNUNET_YES);
733 }
734 else
735 {
737 }
738}
739
740
749static void
751 struct GNUNET_SERVICE_Client *client,
752 uint64_t request_id)
753{
754 char *loprefix;
755 char *options;
756 int use_debug;
757 int is_simple_service;
758 struct ServiceListeningInfo *sli;
759 int *lsocks;
760 unsigned int ls;
761 char *binary;
762 char *quotedbinary;
763
764 /* calculate listen socket list */
765 lsocks = NULL;
766 ls = 0;
767 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
768 {
769 GNUNET_array_append (lsocks,
770 ls,
772 if (NULL != sli->accept_task)
773 {
775 sli->accept_task = NULL;
776 }
777 }
778
779 GNUNET_array_append (lsocks, ls, -1);
780
781 /* obtain configuration */
783 sl->name,
784 "PREFIX",
785 &loprefix))
786 loprefix = GNUNET_strdup (prefix_command);
787 else
788 loprefix = GNUNET_CONFIGURATION_expand_dollar (cfg, loprefix);
790 sl->name,
791 "OPTIONS",
792 &options))
793 options = NULL;
794 else
796 {
797 char *new_options;
798 char *optpos;
799 char *fin_options;
800
801 fin_options = GNUNET_strdup (final_option);
802 /* replace '{}' with service name */
803 while (NULL != (optpos = strstr (fin_options, "{}")))
804 {
805 /* terminate string at opening parenthesis */
806 *optpos = 0;
807 GNUNET_asprintf (&new_options,
808 "%s%s%s",
809 fin_options,
810 sl->name,
811 optpos + 2);
812 GNUNET_free (fin_options);
813 fin_options = new_options;
814 }
815 if (NULL != options)
816 {
817 /* combine "fin_options" with "options" */
818 optpos = options;
819 GNUNET_asprintf (&options, "%s %s", fin_options, optpos);
820 GNUNET_free (fin_options);
821 GNUNET_free (optpos);
822 }
823 else
824 {
825 /* only have "fin_options", use that */
826 options = fin_options;
827 }
828 }
830 use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
831 {
832 const char *service_type = NULL;
833 const char *choices[] = { "GNUNET", "SIMPLE", NULL };
834
835 is_simple_service = GNUNET_NO;
837 sl->name,
838 "TYPE",
839 choices,
840 &service_type)) &&
841 (0 == strcasecmp (service_type, "SIMPLE")))
842 is_simple_service = GNUNET_YES;
843 }
844
845 GNUNET_assert (NULL == sl->proc);
846 if (GNUNET_YES == is_simple_service)
847 {
848 /* A simple service will receive no GNUnet specific
849 command line options. */
850 binary = GNUNET_strdup (sl->binary);
851 binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
852 GNUNET_asprintf (&quotedbinary, "\"%s\"", sl->binary);
854 "Starting simple service `%s' using binary `%s'\n",
855 sl->name,
856 sl->binary);
857 /* FIXME: dollar expansion should only be done outside
858 * of ''-quoted strings, escaping should be considered. */
859 if (NULL != options)
865 lsocks,
866 loprefix,
867 quotedbinary,
868 options,
869 NULL);
870 }
871 else
872 {
873 /* actually start process */
875 "Starting service `%s' using binary `%s' and configuration `%s'\n",
876 sl->name,
877 sl->binary,
878 sl->config);
880 GNUNET_asprintf (&quotedbinary, "\"%s\"", binary);
881
882 if (GNUNET_YES == use_debug)
883 {
884 if (NULL == sl->config)
886 ?
889 :
891 lsocks,
892 loprefix,
893 quotedbinary,
894 "-L",
895 "DEBUG",
896 options,
897 NULL);
898 else
900 ?
903 :
905 lsocks,
906 loprefix,
907 quotedbinary,
908 "-c",
909 sl->config,
910 "-L",
911 "DEBUG",
912 options,
913 NULL);
914 }
915 else
916 {
917 if (NULL == sl->config)
919 ?
922 :
924 lsocks,
925 loprefix,
926 quotedbinary,
927 options,
928 NULL);
929 else
931 ?
934 :
936 lsocks,
937 loprefix,
938 quotedbinary,
939 "-c",
940 sl->config,
941 options,
942 NULL);
943 }
944 }
945 GNUNET_free (binary);
946 GNUNET_free (quotedbinary);
948 if (NULL == sl->proc)
949 {
951 _ ("Failed to start service `%s'\n"),
952 sl->name);
953 if (client)
954 signal_result (client,
955 sl->name,
956 request_id,
958 }
959 else
960 {
962 _ ("Starting service `%s'\n"),
963 sl->name);
965 if (client)
966 signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
967 }
968 /* clean up */
969 GNUNET_free (loprefix);
971 GNUNET_array_grow (lsocks, ls, 0);
972}
973
974
982static struct ServiceList *
983find_service (const char *name)
984{
985 struct ServiceList *sl;
986
987 sl = running_head;
988 while (sl != NULL)
989 {
990 if (0 == strcasecmp (sl->name, name))
991 return sl;
992 sl = sl->next;
993 }
994 return NULL;
995}
996
997
1004static void
1006{
1007 struct ServiceListeningInfo *sli = cls;
1008 struct ServiceList *sl = sli->sl;
1009
1010 sli->accept_task = NULL;
1012 start_process (sl, NULL, 0);
1013}
1014
1015
1024static void
1025create_listen_socket (struct sockaddr *sa,
1026 socklen_t addr_len,
1027 struct ServiceList *sl)
1028{
1029 static int on = 1;
1030 struct GNUNET_NETWORK_Handle *sock;
1031 struct ServiceListeningInfo *sli;
1032
1033 int match_uid;
1034 int match_gid;
1035
1036 switch (sa->sa_family)
1037 {
1038 case AF_INET:
1039 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1040 break;
1041
1042 case AF_INET6:
1043 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1044 break;
1045
1046 case AF_UNIX:
1047 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1048 "@")) /* Do not bind to blank UNIX path! */
1049 return;
1050 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1051 break;
1052
1053 default:
1054 GNUNET_break (0);
1055 sock = NULL;
1056 errno = EAFNOSUPPORT;
1057 break;
1058 }
1059 if (NULL == sock)
1060 {
1062 _ ("Unable to create socket for service `%s': %s\n"),
1063 sl->name,
1064 strerror (errno));
1065 GNUNET_free (sa);
1066 return;
1067 }
1069 SOL_SOCKET,
1070 SO_REUSEADDR,
1071 &on,
1072 sizeof(on)))
1074 "setsockopt");
1075#ifdef IPV6_V6ONLY
1076 if ((sa->sa_family == AF_INET6) &&
1078 IPPROTO_IPV6,
1079 IPV6_V6ONLY,
1080 &on,
1081 sizeof(on))))
1083 "setsockopt");
1084#endif
1085 if (AF_UNIX == sa->sa_family)
1086 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1087 if (GNUNET_OK !=
1088 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1089 {
1090 GNUNET_log (
1092 _ (
1093 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1094 sl->name,
1095 GNUNET_a2s (sa, addr_len),
1096 strerror (errno));
1098 GNUNET_free (sa);
1099 return;
1100 }
1101 if ((AF_UNIX == sa->sa_family)
1102#ifdef __linux__
1103 /* Permission settings are not required when abstract sockets are used */
1104 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1105#endif
1106 )
1107 {
1108 match_uid =
1109 GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "UNIX_MATCH_UID");
1110 match_gid =
1111 GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "UNIX_MATCH_GID");
1112 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1113 match_uid,
1114 match_gid);
1115 }
1116 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1117 {
1120 GNUNET_free (sa);
1121 return;
1122 }
1124 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1125 sl->name,
1126 GNUNET_a2s (sa, addr_len));
1127 sli = GNUNET_new (struct ServiceListeningInfo);
1128 sli->service_addr = sa;
1129 sli->service_addr_len = addr_len;
1130 sli->listen_socket = sock;
1131 sli->sl = sl;
1132 sli->accept_task =
1134 sock,
1136 sli);
1138}
1139
1140
1147static void
1149{
1152 GNUNET_assert (NULL == sl->listen_head);
1155 GNUNET_free (sl->name);
1156 GNUNET_free (sl);
1157}
1158
1159
1168static int
1169check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1170{
1171 (void) cls;
1173 return GNUNET_OK;
1174}
1175
1176
1183static void
1184handle_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1185{
1186 struct GNUNET_SERVICE_Client *client = cls;
1187 const char *servicename;
1188 struct ServiceList *sl;
1189 uint64_t request_id;
1190
1191 request_id = GNUNET_ntohll (amsg->request_id);
1192 servicename = (const char *) &amsg[1];
1194 if (GNUNET_YES == in_shutdown)
1195 {
1196 signal_result (client,
1197 servicename,
1198 request_id,
1200 return;
1201 }
1202 sl = find_service (servicename);
1203 if (NULL == sl)
1204 {
1205 signal_result (client,
1206 servicename,
1207 request_id,
1209 return;
1210 }
1211 sl->force_start = GNUNET_YES;
1212 if (NULL != sl->proc)
1213 {
1214 signal_result (client,
1215 servicename,
1216 request_id,
1218 return;
1219 }
1220 start_process (sl, client, request_id);
1221}
1222
1223
1229static void
1231{
1232 (void) cls;
1233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1235}
1236
1237
1246static int
1247check_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
1248{
1249 (void) cls;
1251 return GNUNET_OK;
1252}
1253
1254
1261static void
1262handle_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
1263{
1264 struct GNUNET_SERVICE_Client *client = cls;
1265 struct ServiceList *sl;
1266 const char *servicename;
1267 uint64_t request_id;
1268
1269 request_id = GNUNET_ntohll (amsg->request_id);
1270 servicename = (const char *) &amsg[1];
1272 _ ("Preparing to stop `%s'\n"),
1273 servicename);
1275 if (0 == strcasecmp (servicename, "arm"))
1276 {
1277 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1278 signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING);
1281 return;
1282 }
1283 sl = find_service (servicename);
1284 if (NULL == sl)
1285 {
1286 signal_result (client,
1287 servicename,
1288 request_id,
1290 return;
1291 }
1292 sl->force_start = GNUNET_NO;
1293 if (GNUNET_YES == in_shutdown)
1294 {
1295 /* shutdown in progress */
1296 signal_result (client,
1297 servicename,
1298 request_id,
1300 return;
1301 }
1302 if (NULL != sl->killing_client)
1303 {
1304 /* killing already in progress */
1305 signal_result (client,
1306 servicename,
1307 request_id,
1309 return;
1310 }
1311 if (NULL == sl->proc)
1312 {
1313 /* process is down */
1314 signal_result (client,
1315 servicename,
1316 request_id,
1318 return;
1319 }
1321 "Sending kill signal to service `%s', waiting for process to die.\n",
1322 servicename);
1323 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1324 /* no signal_start - only when it's STOPPED */
1328 sl->killing_client = client;
1329 sl->killing_client_request_id = request_id;
1330}
1331
1332
1344static int
1345pool_write (char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
1346{
1347 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1348
1349 if (next_pos > pool_size)
1350 return GNUNET_SYSERR;
1351 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1352 *pool_pos = next_pos;
1353 return GNUNET_OK;
1354}
1355
1356
1363static void
1364handle_list (void *cls, const struct GNUNET_ARM_Message *request)
1365{
1366 struct GNUNET_SERVICE_Client *client = cls;
1367 struct GNUNET_MQ_Envelope *env;
1369 size_t extra_size;
1370 struct ServiceList *sl;
1371 uint16_t count;
1372 size_t pool_size;
1373 size_t pool_pos;
1374 char *pool_start;
1376
1377 GNUNET_break_op (0 == ntohl (request->reserved));
1378 count = 0;
1379 pool_size = 0;
1380
1381 /* Do one pass over the list to compute the number of services
1382 * and the string pool size */
1383 for (sl = running_head; NULL != sl; sl = sl->next)
1384 {
1385 pool_size += strlen (sl->name) + 1;
1386 pool_size += strlen (sl->binary) + 1;
1387 count++;
1388 }
1389
1390 extra_size = pool_size + (count * sizeof (struct
1393 extra_size,
1395 msg->arm_msg.request_id = request->request_id;
1396 msg->count = htons (count);
1397
1398 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1399 pool_start = (char *) (ssm + count);
1400 pool_pos = 0;
1401
1402 for (sl = running_head; NULL != sl; sl = sl->next)
1403 {
1404 ssm->name_index = htons ((uint16_t) pool_pos);
1405 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1406 sl->name));
1407 ssm->binary_index = htons ((uint16_t) pool_pos);
1408 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1409 sl->binary));
1410 if (NULL == sl->proc)
1411 {
1412 if (0 == sl->last_started_at.abs_value_us)
1413 {
1414 /* Process never started */
1416 }
1417 else if (0 == sl->last_exit_status)
1418 {
1420 }
1421 else
1422 {
1424 ssm->last_exit_status = htons (sl->last_exit_status);
1425 }
1426 }
1427 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1428 {
1430 }
1431 else
1432 {
1434 }
1437 ssm++;
1438 }
1441}
1442
1443
1450static void
1451handle_test (void *cls, const struct GNUNET_MessageHeader *message)
1452{
1453 struct GNUNET_SERVICE_Client *client = cls;
1454 struct GNUNET_MQ_Envelope *env;
1455 struct GNUNET_MessageHeader *msg;
1456
1457 (void) message;
1461}
1462
1463
1468static void
1470{
1471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1472 if (NULL != notifier)
1473 {
1475 notifier = NULL;
1476 }
1477 if (NULL != service)
1478 {
1480 service = NULL;
1481 }
1482 if (NULL != child_death_task)
1483 {
1485 child_death_task = NULL;
1486 }
1487}
1488
1489
1496static unsigned int
1498{
1499 struct ServiceList *i;
1500 unsigned int res;
1501
1502 for (res = 0, i = running_head; NULL != i; i = i->next, res++)
1504 return res;
1505}
1506
1507
1513static void
1514shutdown_task (void *cls)
1515{
1516 struct ServiceList *pos;
1517 struct ServiceList *nxt;
1518 struct ServiceListeningInfo *sli;
1519
1520 (void) cls;
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1522 if (NULL != child_restart_task)
1523 {
1525 child_restart_task = NULL;
1526 }
1528 /* first, stop listening */
1529 for (pos = running_head; NULL != pos; pos = pos->next)
1530 {
1531 while (NULL != (sli = pos->listen_head))
1532 {
1534 if (NULL != sli->accept_task)
1535 {
1537 sli->accept_task = NULL;
1538 }
1542 GNUNET_free (sli);
1543 }
1544 }
1545 /* then, shutdown all existing service processes */
1546 nxt = running_head;
1547 while (NULL != (pos = nxt))
1548 {
1549 nxt = pos->next;
1550 if (NULL != pos->proc)
1551 {
1552 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name);
1556 }
1557 else
1558 {
1559 free_service (pos);
1560 }
1561 }
1562 /* finally, should all service processes be already gone, terminate for real */
1563 if (NULL == running_head)
1564 do_shutdown ();
1565 else
1567 "Delaying shutdown, have %u children still running\n",
1569}
1570
1571
1577static void
1579
1580{
1581 struct ServiceList *sl;
1582 struct GNUNET_TIME_Relative lowestRestartDelay;
1583 struct ServiceListeningInfo *sli;
1584
1585 (void) cls;
1586 child_restart_task = NULL;
1588 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1589
1590 /* check for services that need to be restarted due to
1591 * configuration changes or because the last restart failed */
1592 for (sl = running_head; NULL != sl; sl = sl->next)
1593 {
1594 if (NULL != sl->proc)
1595 continue;
1596 /* service is currently not running */
1598 {
1599 /* restart is now allowed */
1600 if (sl->force_start)
1601 {
1602 /* process should run by default, start immediately */
1604 _ ("Restarting service `%s'.\n"),
1605 sl->name);
1606 start_process (sl, NULL, 0);
1607 }
1608 else
1609 {
1610 /* process is run on-demand, ensure it is re-started if there is demand */
1611 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1612 if (NULL == sli->accept_task)
1613 {
1614 /* accept was actually paused, so start it again */
1615 sli->accept_task =
1617 sli->listen_socket,
1619 sli);
1620 }
1621 }
1622 }
1623 else
1624 {
1625 /* update calculation for earliest time to reactivate a service */
1626 lowestRestartDelay =
1627 GNUNET_TIME_relative_min (lowestRestartDelay,
1629 sl->restart_at));
1630 }
1631 }
1632 if (lowestRestartDelay.rel_value_us !=
1633 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1634 {
1636 "Will restart process in %s\n",
1637 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1638 GNUNET_YES));
1643 NULL);
1644 }
1645}
1646
1647
1654static void
1656{
1657 struct ServiceList *pos;
1658 struct ServiceList *next;
1659 struct ServiceListeningInfo *sli;
1660 const char *statstr;
1661 int statcode;
1662 int ret;
1663 char c[16];
1664 enum GNUNET_OS_ProcessStatusType statusType;
1665 unsigned long statusCode;
1666 const struct GNUNET_DISK_FileHandle *pr;
1667
1668 (void) cls;
1670 child_death_task = NULL;
1671 /* consume the signal */
1672 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1673
1674 /* check for services that died (WAITPID) */
1675 next = running_head;
1676 while (NULL != (pos = next))
1677 {
1678 next = pos->next;
1679
1680 if (NULL == pos->proc)
1681 {
1682 if (GNUNET_YES == in_shutdown)
1683 free_service (pos);
1684 continue;
1685 }
1686#if HAVE_WAIT4
1687 if (NULL != wait_file)
1688 {
1689 /* need to use 'wait4()' to obtain and log performance data */
1690 struct rusage ru;
1691 int status;
1692 pid_t pid;
1693
1695 ret = wait4 (pid, &status, WNOHANG, &ru);
1696 if (ret <= 0)
1697 continue; /* no process done */
1698 if (WIFEXITED (status))
1699 {
1700 statusType = GNUNET_OS_PROCESS_EXITED;
1701 statusCode = WEXITSTATUS (status);
1702 }
1703 else if (WIFSIGNALED (status))
1704 {
1705 statusType = GNUNET_OS_PROCESS_SIGNALED;
1706 statusCode = WTERMSIG (status);
1707 }
1708 else if (WIFSTOPPED (status))
1709 {
1710 statusType = GNUNET_OS_PROCESS_SIGNALED;
1711 statusCode = WSTOPSIG (status);
1712 }
1713#ifdef WIFCONTINUED
1714 else if (WIFCONTINUED (status))
1715 {
1716 statusType = GNUNET_OS_PROCESS_RUNNING;
1717 statusCode = 0;
1718 }
1719#endif
1720 else
1721 {
1722 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1723 statusCode = 0;
1724 }
1725 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1726 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1727 {
1728 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1729 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1730 fprintf (wait_file,
1731 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1732 pos->binary,
1733 (unsigned int) pid,
1734 utime,
1735 stime,
1736 (unsigned long long) ru.ru_maxrss,
1737 (unsigned long long) ru.ru_inblock,
1738 (unsigned long long) ru.ru_oublock,
1739 (unsigned long long) ru.ru_nvcsw,
1740 (unsigned long long) ru.ru_nivcsw);
1741 }
1742 }
1743 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1744#endif
1746 &statusType,
1747 &statusCode))) ||
1748 (ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1749 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1750 (statusType == GNUNET_OS_PROCESS_RUNNING))
1751 continue;
1752
1753 if (statusType == GNUNET_OS_PROCESS_EXITED)
1754 {
1755 statstr = _ (/* process termination method */ "exit");
1756 statcode = statusCode;
1757 }
1758 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1759 {
1760 statstr = _ (/* process termination method */ "signal");
1761 statcode = statusCode;
1762 }
1763 else
1764 {
1765 statstr = _ (/* process termination method */ "unknown");
1766 statcode = 0;
1767 }
1768 if (0 != pos->killed_at.abs_value_us)
1769 {
1771 _ ("Service `%s' took %s to terminate\n"),
1772 pos->name,
1775 GNUNET_YES));
1776 }
1778 pos->proc = NULL;
1780 if (NULL != pos->killing_client)
1781 {
1783 pos->name,
1786 pos->killing_client = NULL;
1788 }
1789 if (GNUNET_YES != in_shutdown)
1790 {
1791 pos->last_exit_status = statcode;
1792 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1793 {
1794 /* process terminated normally, allow restart at any time */
1795 pos->restart_at.abs_value_us = 0;
1796 GNUNET_log (
1798 _ ("Service `%s' terminated normally, will restart at any time\n"),
1799 pos->name);
1800 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1801 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1802 {
1803 GNUNET_break (NULL == sli->accept_task);
1804 sli->accept_task =
1806 sli->listen_socket,
1808 sli);
1809 }
1810 }
1811 else
1812 {
1813 GNUNET_log (
1815 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1816 pos->name,
1817 statstr,
1818 statcode,
1820 {
1821 /* Reduce backoff based on runtime of the process,
1822 so that there is a cool-down if a process actually
1823 runs for a while. */
1824 struct GNUNET_TIME_Relative runtime;
1825 unsigned int minutes;
1826
1828 minutes =
1829 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1830 if (minutes > 31)
1832 else
1833 pos->backoff.rel_value_us >>= minutes;
1834 }
1835 /* schedule restart */
1838 if (NULL != child_restart_task)
1843 NULL);
1844 }
1845 }
1846 else
1847 {
1848 free_service (pos);
1849 }
1850 }
1853 pr,
1855 NULL);
1856 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1857 do_shutdown ();
1858 else if (GNUNET_YES == in_shutdown)
1860 "Delaying shutdown after child's death, still have %u children\n",
1862}
1863
1864
1869static void
1871{
1872 static char c;
1873 int old_errno = errno; /* back-up errno */
1874
1875 GNUNET_break (
1876 1 ==
1879 &c,
1880 sizeof(c)));
1881 errno = old_errno; /* restore errno */
1882}
1883
1884
1893static void
1894setup_service (void *cls, const char *section)
1895{
1896 struct ServiceList *sl;
1897 char *binary;
1898 char *config;
1899 struct stat sbuf;
1900 struct sockaddr **addrs;
1901 socklen_t *addr_lens;
1902 int ret;
1903
1904 (void) cls;
1905 if (0 == strcasecmp (section, "arm"))
1906 return;
1907 if (GNUNET_OK !=
1908 GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1909 {
1910 /* not a service section */
1911 return;
1912 }
1913 if ((GNUNET_YES ==
1914 GNUNET_CONFIGURATION_have_value (cfg, section, "RUN_PER_USER")) &&
1915 (GNUNET_YES ==
1916 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "RUN_PER_USER")))
1917 {
1918 if (GNUNET_NO == start_user)
1919 {
1920 GNUNET_free (binary);
1921 return; /* user service, and we don't deal with those */
1922 }
1923 }
1924 else
1925 {
1926 if (GNUNET_NO == start_system)
1927 {
1928 GNUNET_free (binary);
1929 return; /* system service, and we don't deal with those */
1930 }
1931 }
1932 sl = find_service (section);
1933 if (NULL != sl)
1934 {
1935 /* got the same section twice!? */
1936 GNUNET_break (0);
1937 GNUNET_free (binary);
1938 return;
1939 }
1940 config = NULL;
1942 section,
1943 "CONFIG",
1944 &config)) &&
1946 "PATHS",
1947 "DEFAULTCONFIG",
1948 &config))) ||
1949 (0 != stat (config, &sbuf)))
1950 {
1951 if (NULL != config)
1952 {
1954 section,
1955 "CONFIG",
1956 strerror (errno));
1958 config = NULL;
1959 }
1960 }
1961 sl = GNUNET_new (struct ServiceList);
1962 sl->name = GNUNET_strdup (section);
1963 sl->binary = binary;
1964 sl->config = config;
1967 if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
1968 sl->pipe_control =
1969 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
1971 if (GNUNET_YES ==
1972 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "IMMEDIATE_START"))
1973 {
1974 sl->force_start = GNUNET_YES;
1975 if (GNUNET_YES ==
1976 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "NOARMBIND"))
1977 return;
1978 }
1979 else
1980 {
1981 if (GNUNET_YES !=
1982 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "START_ON_DEMAND"))
1983 return;
1984 }
1985 if (0 >= (ret = get_server_addresses (section, cfg, &addrs, &addr_lens)))
1986 return;
1987 /* this will free (or capture) addrs[i] */
1988 for (unsigned int i = 0; i < (unsigned int) ret; i++)
1989 create_listen_socket (addrs[i], addr_lens[i], sl);
1990 GNUNET_free (addrs);
1991 GNUNET_free (addr_lens);
1992}
1993
1994
2003static void *
2005 struct GNUNET_SERVICE_Client *client,
2006 struct GNUNET_MQ_Handle *mq)
2007{
2008 /* All clients are considered to be of the "monitor" kind
2009 * (that is, they don't affect ARM shutdown).
2010 */
2011 (void) cls;
2012 (void) mq;
2014 return client;
2015}
2016
2017
2025static void
2027 struct GNUNET_SERVICE_Client *client,
2028 void *app_ctx)
2029{
2030 (void) cls;
2031 GNUNET_assert (client == app_ctx);
2032 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2033 if (sl->killing_client == client)
2034 sl->killing_client = NULL;
2035}
2036
2037
2046static void
2047handle_monitor (void *cls, const struct GNUNET_MessageHeader *message)
2048{
2049 struct GNUNET_SERVICE_Client *client = cls;
2050
2051 (void) message;
2052 /* FIXME: might want to start by letting monitor know about
2053 services that are already running */
2054 /* Removal is handled by the server implementation, internally. */
2059}
2060
2061
2069static void
2070run (void *cls,
2071 const struct GNUNET_CONFIGURATION_Handle *c,
2072 struct GNUNET_SERVICE_Handle *serv)
2073{
2074 struct ServiceList *sl;
2075
2076 (void) cls;
2077 cfg = c;
2078 service = serv;
2084 NULL);
2085#if HAVE_WAIT4
2086 if (GNUNET_OK ==
2088 "ARM",
2089 "RESOURCE_DIAGNOSTICS",
2090 &wait_filename))
2091 {
2092 wait_file = fopen (wait_filename, "w");
2093 if (NULL == wait_file)
2094 {
2096 "fopen",
2097 wait_filename);
2098 }
2099 }
2100#endif
2102 "ARM",
2103 "GLOBAL_PREFIX",
2106 else
2109 "ARM",
2110 "GLOBAL_POSTFIX",
2111 &final_option))
2113 else
2115 start_user =
2116 GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "START_USER_SERVICES");
2117 start_system =
2118 GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "START_SYSTEM_SERVICES");
2119 if ((GNUNET_NO == start_user) && (GNUNET_NO == start_system))
2120 {
2121 GNUNET_log (
2123 "Please configure either START_USER_SERVICES or START_SYSTEM_SERVICES or both.\n");
2125 global_ret = 1;
2126 return;
2127 }
2129
2130 /* start default services... */
2131 for (sl = running_head; NULL != sl; sl = sl->next)
2132 if (GNUNET_YES == sl->force_start)
2133 start_process (sl, NULL, 0);
2135}
2136
2137
2145int
2146main (int argc, char *const *argv)
2147{
2152 struct GNUNET_ARM_Message,
2153 NULL),
2156 struct GNUNET_ARM_Message,
2157 NULL),
2160 struct GNUNET_MessageHeader,
2161 NULL),
2164 struct GNUNET_ARM_Message,
2165 NULL),
2168 struct GNUNET_MessageHeader,
2169 NULL),
2171 };
2172
2174 GNUNET_assert (NULL != sigpipe);
2175 shc_chld =
2178 if (0 != GNUNET_SERVICE_run_ (argc,
2179 argv,
2180 "arm",
2183 &run,
2186 NULL,
2187 handlers))
2188 global_ret = 2;
2189#if HAVE_WAIT4
2190 if (NULL != wait_file)
2191 {
2192 fclose (wait_file);
2193 wait_file = NULL;
2194 }
2195 if (NULL != wait_filename)
2196 {
2197 GNUNET_free (wait_filename);
2198 wait_filename = NULL;
2199 }
2200#endif
2202 shc_chld = NULL;
2204 sigpipe = NULL;
2205 return global_ret;
2206}
2207
2208
2209#if defined(__linux__) && defined(__GLIBC__)
2210#include <malloc.h>
2211
2215void __attribute__ ((constructor))
2216GNUNET_ARM_memory_init ()
2217{
2218 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2219 mallopt (M_TOP_PAD, 1 * 1024);
2220 malloc_trim (0);
2221}
2222
2223
2224#endif
2225
2226
2227/* end of gnunet-service-arm.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
struct GNUNET_MQ_MessageHandlers handlers[]
Definition: 003.c:1
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static struct GNUNET_SIGNAL_Context * shc_chld
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
static int monitor
Monitor ARM activity.
Definition: gnunet-arm.c:64
static int list
Set if we should print a list of currently running services.
Definition: gnunet-arm.c:69
static int ret
Final status code.
Definition: gnunet-arm.c:94
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
const struct GNUNET_CONFIGURATION_Handle * config
static char * name
Name (label) of the records to list.
static char * res
Currently read line or NULL on EOF.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
static int status
The program status; 0 for success.
Definition: gnunet-nse.c:39
static int result
Global testing status.
static struct GNUNET_SCHEDULER_Task * child_restart_task
ID of task called whenever the timeout for restarting a child expires.
static void delayed_restart_task(void *cls)
Task run whenever it is time to restart a child that died.
static struct ServiceList * running_head
List of running services.
static void trigger_shutdown(void *cls)
Start a shutdown sequence.
static void start_process(struct ServiceList *sl, struct GNUNET_SERVICE_Client *client, uint64_t request_id)
Actually start the process for the given service.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *serv)
Process arm requests.
static void broadcast_status(const char *name, enum GNUNET_ARM_ServiceMonitorStatus status, struct GNUNET_SERVICE_Client *unicast)
Tell all clients about status change of a service.
static void free_service(struct ServiceList *sl)
Remove and free an entry in the service list.
#define MAX_NOTIFY_QUEUE
How many messages do we queue up at most for optional notifications to a client? (this can cause noti...
static unsigned int list_count(struct ServiceList *running_head)
Count how many services are still active.
static char * prefix_command
Command to prepend to each actual command.
static void handle_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
Handle STOP-message.
static char * final_option
Option to append to each actual command.
static void add_unixpath(struct sockaddr **saddrs, socklen_t *saddrlens, const char *unixpath, int abstract)
Add the given UNIX domain path as an address to the list (as the first entry).
static int global_ret
Return value from main.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static int start_user
Are we starting user services?
static void maint_child_death(void *cls)
Task triggered whenever we receive a SIGCHLD (child process died).
static struct GNUNET_SCHEDULER_Task * child_death_task
ID of task called whenever we get a SIGCHILD.
static int start_system
Are we starting system services?
static int check_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
Check STOP-message.
static int in_shutdown
Are we in shutdown mode?
static void shutdown_task(void *cls)
Task run for shutdown.
static void handle_test(void *cls, const struct GNUNET_MessageHeader *message)
Handle TEST-message by sending back TEST.
static void setup_service(void *cls, const char *section)
Setup our service record for the given section in the configuration file (assuming the section is for...
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
A client connected, mark as a monitoring client.
static int get_server_addresses(const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t **addr_lens)
Get the list of addresses that a server for the given service should bind to.
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate shutdown via signal.
static void sighandler_child_death()
Signal handler called for SIGCHLD.
static void accept_connection(void *cls)
First connection has come to the listening socket associated with the service, create the service in ...
static void handle_start(void *cls, const struct GNUNET_ARM_Message *amsg)
Handle START-message.
static void do_shutdown()
We are done with everything.
static struct ServiceList * running_tail
List of running services.
static void handle_list(void *cls, const struct GNUNET_ARM_Message *request)
Handle LIST-message.
static void create_listen_socket(struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl)
Creating a listening socket for each of the service's addresses and wait for the first incoming conne...
#define LOG(kind,...)
int main(int argc, char *const *argv)
The main function for the arm service.
static void handle_monitor(void *cls, const struct GNUNET_MessageHeader *message)
Handle MONITOR-message.
static void signal_result(struct GNUNET_SERVICE_Client *client, const char *name, uint64_t request_id, enum GNUNET_ARM_Result result)
Signal our client that we will start or stop the service.
#define LOG_STRERROR(kind, syscall)
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up associated state.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static struct ServiceList * find_service(const char *name)
Find the process with the given service name in the given list and return it.
static int pool_write(char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
Write a string to a string pool.
static struct GNUNET_NotificationContext * notifier
Context for notifications we need to send to our clients.
static int check_start(void *cls, const struct GNUNET_ARM_Message *amsg)
Check START-message.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition: gnunet-vpn.c:50
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition: gnunet-vpn.c:40
struct GNUNET_PQ_ResultSpec __attribute__
Constants for network protocols.
GNUNET_ARM_ServiceMonitorStatus
Statuses of services.
GNUNET_ARM_Result
Replies to ARM requests.
@ GNUNET_ARM_SERVICE_STATUS_FINISHED
The service was started, but then exited normally.
@ GNUNET_ARM_SERVICE_STATUS_FAILED
The service has previously failed, and will be restarted.
@ GNUNET_ARM_SERVICE_STATUS_STOPPED
Service is stopped.
@ GNUNET_ARM_SERVICE_STATUS_STOPPING
The service was started, and we're currently waiting for it to be stopped.
@ GNUNET_ARM_SERVICE_STATUS_STARTED
Service has been started and is currently running.
@ GNUNET_ARM_SERVICE_STOPPING
Service stopping was initiated.
@ GNUNET_ARM_SERVICE_STOPPED
Service was stopped.
@ GNUNET_ARM_SERVICE_STARTING
Service starting was initiated.
@ GNUNET_ARM_SERVICE_MONITORING_STARTED
Dummy message.
@ GNUNET_ARM_RESULT_IS_NOT_KNOWN
Asked to start or stop a service, but it's not known.
@ GNUNET_ARM_RESULT_IS_STOPPED_ALREADY
Asked to stop it, but it's already stopped.
@ GNUNET_ARM_RESULT_STARTING
Service starting was initiated.
@ GNUNET_ARM_RESULT_IS_STARTED_ALREADY
Asked to start it, but it's already started.
@ GNUNET_ARM_RESULT_STOPPING
ARM stopping was initiated (there's no "stopped" for ARM itself).
@ GNUNET_ARM_RESULT_IS_STOPPING_ALREADY
Asked to stop it, but it's already stopping.
@ GNUNET_ARM_RESULT_STOPPED
Service was stopped (never sent for ARM itself).
@ GNUNET_ARM_RESULT_START_FAILED
Tried to start a service, but that failed for some reason.
@ GNUNET_ARM_RESULT_IN_SHUTDOWN
Asked to start something, but ARM is shutting down and can't comply.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
void GNUNET_CONFIGURATION_iterate_sections(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_SectionIterator iter, void *iter_cls)
Iterate over all sections in the configuration.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
char * GNUNET_CONFIGURATION_expand_dollar(const struct GNUNET_CONFIGURATION_Handle *cfg, char *orig)
Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" where either in the "PATHS" section or...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_choice(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *const *choices, const char **value)
Get a configuration value that should be in a set of predefined strings.
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:1617
void GNUNET_DISK_fix_permissions(const char *fn, int require_uid_match, int require_gid_match)
Update POSIX permissions mask of a file on disk.
Definition: disk.c:320
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:686
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1444
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1587
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition: disk.c:582
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:622
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:54
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:37
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_SCHEDULER_PRIORITY_IDLE
Run when otherwise idle.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_BULK
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition: nc.c:138
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:304
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_check_zero_termination(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition: mq.c:285
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
Definition: gnunet_mq_lib.h:63
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition: nc.c:122
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition: nc.c:190
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:78
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition: nc.c:161
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:508
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1000
char * GNUNET_NETWORK_shorten_unixpath(char *unixpath)
Given a unixpath that is too long (larger than UNIX_PATH_MAX), shorten it to an acceptable length whi...
Definition: network.c:143
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:832
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:439
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:651
void GNUNET_NETWORK_unix_precheck(const struct sockaddr_un *un)
If services crash, they can leave a unix domain socket file on the disk.
Definition: network.c:178
int GNUNET_NETWORK_socket_setsockopt(struct GNUNET_NETWORK_Handle *fd, int level, int option_name, const void *option_value, socklen_t option_len)
Set socket option.
Definition: network.c:805
char * GNUNET_OS_get_libexec_binary_path(const char *progname)
Given the name of a gnunet-helper, gnunet-service or gnunet-daemon binary, try to prefix it with the ...
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename,...)
Start a process.
Definition: os_priority.c:665
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:253
GNUNET_OS_ProcessStatusType
Process status types.
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:260
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:210
enum GNUNET_GenericReturnValue GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process.
Definition: os_priority.c:859
@ GNUNET_OS_INHERIT_STD_OUT_AND_ERR
When these flags are set, the child process will inherit stdout and stderr of the parent.
@ GNUNET_OS_USE_PIPE_CONTROL
Should a pipe be used to send signals to the child?
@ GNUNET_OS_PROCESS_SIGNALED
The process was killed by a signal.
@ GNUNET_OS_PROCESS_EXITED
The process exited with a return code.
@ GNUNET_OS_PROCESS_UNKNOWN
The process is not known to the OS (or at least not one of our children).
@ GNUNET_OS_PROCESS_STOPPED
The process is paused (but could be resumed).
@ GNUNET_OS_PROCESS_RUNNING
The process is still running.
#define GNUNET_MESSAGE_TYPE_ARM_STOP
Request to ARM to stop a service.
#define GNUNET_MESSAGE_TYPE_ARM_RESULT
Response from ARM.
#define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT
Response from ARM for listing currently running services.
#define GNUNET_MESSAGE_TYPE_ARM_TEST
Test if ARM service is online.
#define GNUNET_MESSAGE_TYPE_ARM_STATUS
Status update from ARM.
#define GNUNET_MESSAGE_TYPE_ARM_START
Request to ARM to start a service.
#define GNUNET_MESSAGE_TYPE_ARM_LIST
Request to ARM to list all currently running services.
#define GNUNET_MESSAGE_TYPE_ARM_MONITOR
Request to ARM to notify client of service status changes.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1512
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1662
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1340
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1305
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1208
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_with_priority(enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified priority.
Definition: scheduler.c:1232
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition: service.c:2548
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the 'monitor' flag on this client.
Definition: service.c:2572
void GNUNET_SERVICE_client_persist(struct GNUNET_SERVICE_Client *c)
Set the persist option on this client.
Definition: service.c:2589
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition: service.c:2602
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2408
int GNUNET_SERVICE_run_(int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
Creates the "main" function for a GNUnet service.
Definition: service.c:1927
@ GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN
Do not trigger server shutdown on signal at all; instead, allow for the user to terminate the server ...
@ GNUNET_SERVICE_OPTION_CLOSE_LSOCKS
Instead of listening on lsocks passed by the parent, close them after opening our own listen socket(s...
struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install(int signal, GNUNET_SIGNAL_Handler handler)
Install a signal handler that will be run if the given signal is received.
Definition: signal.c:52
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal handler.
Definition: signal.c:78
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Definition: strings.c:138
struct GNUNET_TIME_Relative GNUNET_TIME_relative_min(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the minimum of two relative time values.
Definition: time.c:343
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition: time.c:436
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:405
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:570
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:316
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:638
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
#define GNUNET_SIGCHLD
Definition: platform.h:42
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:234
Reply from ARM to client for the GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count '\0' terminat...
Definition: arm.h:145
uint64_t request_id
ID of a request that is being replied to.
Definition: arm.h:77
Reply from ARM to client.
Definition: arm.h:87
struct GNUNET_TIME_AbsoluteNBO last_started_at
Time when the service was first started, if applicable.
Definition: arm.h:135
uint16_t binary_index
String pool index for the service's binary.
Definition: arm.h:109
struct GNUNET_TIME_AbsoluteNBO restart_at
Time when the service will be restarted, if applicable to the current status.
Definition: arm.h:130
uint32_t status
Status from the 'enum GNUNET_ARM_ServiceStatus'.
Definition: arm.h:124
int16_t last_exit_status
Last process exit status.
Definition: arm.h:114
uint16_t name_index
String pool index for the service's name.
Definition: arm.h:104
Status update from ARM to client.
Definition: arm.h:42
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:68
Handle to a message queue.
Definition: mq.c:87
Message handler for a specific message type.
Header for all communications.
handle to a socket
Definition: network.c:53
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition: nc.c:77
Entry in list of pending tasks.
Definition: scheduler.c:136
Handle to a client that is connected to a service.
Definition: service.c:252
Handle to a service.
Definition: service.c:118
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
uint64_t request_id
non-zero if this request has been sent to the service.
Definition: vpn_api.c:127
List of our services.
struct ServiceListeningInfo * listen_head
Linked list of listen sockets associated with this service.
struct ServiceListeningInfo * listen_tail
Linked list of listen sockets associated with this service.
char * binary
Name of the binary used.
int pipe_control
Should we use pipes to signal this process? (YES for Java binaries and if we are on Windoze).
char * config
Name of the configuration file used.
int last_exit_status
Last exit status of the process.
struct ServiceList * next
This is a doubly-linked list.
struct GNUNET_TIME_Absolute last_started_at
Absolute time at which the process was (re-)started last.
struct GNUNET_OS_Process * proc
Process structure pointer of the child.
struct GNUNET_SERVICE_Client * killing_client
Client to notify upon kill completion (waitpid), NULL if we should simply restart the process.
struct GNUNET_TIME_Relative backoff
Process exponential backoff time.
struct ServiceList * prev
This is a doubly-linked list.
char * name
Name of the service.
int force_start
Is this service to be started by default (or did a client tell us explicitly to start it)?...
struct GNUNET_TIME_Absolute killed_at
Time we asked the service to shut down (used to calculate time it took the service to terminate).
struct GNUNET_TIME_Absolute restart_at
Absolute time at which the process is scheduled to restart in case of death.
uint64_t killing_client_request_id
ID of the request that killed the service (for reporting back).
Record with information about a listen socket we have open.
struct ServiceListeningInfo * prev
This is a linked list.
struct ServiceListeningInfo * next
This is a linked list.
struct sockaddr * service_addr
Address this socket is listening on.
struct ServiceList * sl
Service this listen socket is for.
socklen_t service_addr_len
Number of bytes in service_addr.
struct GNUNET_SCHEDULER_Task * accept_task
Task doing the accepting.
struct GNUNET_NETWORK_Handle * listen_socket
Our listening socket.