GNUnet  0.10.x
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) GNUNET_log_from_strerror (kind, "util", syscall)
35 
36 
37 #if HAVE_WAIT4
38 
41 static char *wait_filename;
42 
46 static FILE *wait_file;
47 #endif
48 
49 
55 #define MAX_NOTIFY_QUEUE 1024
56 
57 
61 struct ServiceList;
62 
63 
68 {
73 
78 
82  struct sockaddr *service_addr;
83 
87  struct ServiceList *sl;
88 
92  socklen_t service_addr_len;
93 
98 
103 
104 };
105 
106 
111 {
115  struct ServiceList *next;
116 
120  struct ServiceList *prev;
121 
126 
131 
135  char *name;
136 
140  char *binary;
141 
145  char *config;
146 
152 
157 
162 
167 
171  struct GNUNET_TIME_Absolute restart_at;
172 
177  struct GNUNET_TIME_Absolute killed_at;
178 
185 
191 };
192 
196 static struct ServiceList *running_head;
197 
201 static struct ServiceList *running_tail;
202 
206 static const struct GNUNET_CONFIGURATION_Handle *cfg;
207 
211 static char *prefix_command;
212 
216 static char *final_option;
217 
222 
228 
233 
237 static int in_shutdown;
238 
242 static int global_ret;
243 
247 static int start_user = GNUNET_YES;
248 
253 
265 
270 
271 
282 static void
283 add_unixpath (struct sockaddr **saddrs,
284  socklen_t *saddrlens,
285  const char *unixpath,
286  int abstract)
287 {
288 #ifdef AF_UNIX
289  struct sockaddr_un *un;
290 
291  un = GNUNET_new (struct sockaddr_un);
292  un->sun_family = AF_UNIX;
293  GNUNET_strlcpy (un->sun_path, unixpath, sizeof (un->sun_path));
294 #ifdef LINUX
295  if (GNUNET_YES == abstract)
296  un->sun_path[0] = '\0';
297 #endif
298 #if HAVE_SOCKADDR_UN_SUN_LEN
299  un->sun_len = (u_char) sizeof (struct sockaddr_un);
300 #endif
301  *saddrs = (struct sockaddr *) un;
302  *saddrlens = sizeof (struct sockaddr_un);
303 #else
304  /* this function should never be called
305  * unless AF_UNIX is defined! */
306  GNUNET_assert (0);
307 #endif
308 }
309 
310 
331 static int
333  const struct GNUNET_CONFIGURATION_Handle *cfg,
334  struct sockaddr ***addrs,
335  socklen_t ** addr_lens)
336 {
337  int disablev6;
338  struct GNUNET_NETWORK_Handle *desc;
339  unsigned long long port;
340  char *unixpath;
341  struct addrinfo hints;
342  struct addrinfo *res;
343  struct addrinfo *pos;
344  struct addrinfo *next;
345  unsigned int i;
346  int resi;
347  int ret;
348  int abstract;
349  struct sockaddr **saddrs;
350  socklen_t *saddrlens;
351  char *hostname;
352 
353  *addrs = NULL;
354  *addr_lens = NULL;
355  desc = NULL;
357  service_name,
358  "DISABLEV6"))
359  {
360  if (GNUNET_SYSERR ==
361  (disablev6 =
363  service_name,
364  "DISABLEV6")))
365  return GNUNET_SYSERR;
366  }
367  else
368  disablev6 = GNUNET_NO;
369 
370  if (! disablev6)
371  {
372  /* probe IPv6 support */
373  desc = GNUNET_NETWORK_socket_create (PF_INET6,
374  SOCK_STREAM,
375  0);
376  if (NULL == desc)
377  {
378  if ( (ENOBUFS == errno) ||
379  (ENOMEM == errno) ||
380  (ENFILE == errno) ||
381  (EACCES == errno) )
382  {
384  "socket");
385  return GNUNET_SYSERR;
386  }
388  _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
389  service_name,
390  STRERROR (errno));
391  disablev6 = GNUNET_YES;
392  }
393  else
394  {
396  desc = NULL;
397  }
398  }
399 
400  port = 0;
402  service_name,
403  "PORT"))
404  {
405  if (GNUNET_OK !=
407  service_name,
408  "PORT",
409  &port))
410  {
412  _("Require valid port number for service `%s' in configuration!\n"),
413  service_name);
414  }
415  if (port > 65535)
416  {
418  _("Require valid port number for service `%s' in configuration!\n"),
419  service_name);
420  return GNUNET_SYSERR;
421  }
422  }
423 
425  service_name,
426  "BINDTO"))
427  {
430  service_name,
431  "BINDTO",
432  &hostname));
433  }
434  else
435  hostname = NULL;
436 
437  unixpath = NULL;
438  abstract = GNUNET_NO;
439 #ifdef AF_UNIX
440  if ((GNUNET_YES ==
442  service_name,
443  "UNIXPATH")) &&
444  (GNUNET_OK ==
446  service_name,
447  "UNIXPATH",
448  &unixpath)) &&
449  (0 < strlen (unixpath)))
450  {
451  /* probe UNIX support */
452  struct sockaddr_un s_un;
453 
454  if (strlen (unixpath) >= sizeof (s_un.sun_path))
455  {
457  _("UNIXPATH `%s' too long, maximum length is %llu\n"),
458  unixpath,
459  (unsigned long long) sizeof (s_un.sun_path));
460  unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
462  _("Using `%s' instead\n"),
463  unixpath);
464  }
465 #ifdef LINUX
466  abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
467  "TESTING",
468  "USE_ABSTRACT_SOCKETS");
469  if (GNUNET_SYSERR == abstract)
470  abstract = GNUNET_NO;
471 #endif
472  if ( (GNUNET_YES != abstract) &&
473  (GNUNET_OK !=
476  "mkdir",
477  unixpath);
478  }
479  if (NULL != unixpath)
480  {
481  desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
482  if (NULL == desc)
483  {
484  if ( (ENOBUFS == errno) ||
485  (ENOMEM == errno) ||
486  (ENFILE == errno) ||
487  (EACCES == errno) )
488  {
490  GNUNET_free_non_null (hostname);
491  GNUNET_free (unixpath);
492  return GNUNET_SYSERR;
493  }
495  _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
496  service_name,
497  STRERROR (errno));
498  GNUNET_free (unixpath);
499  unixpath = NULL;
500  }
501  else
502  {
504  desc = NULL;
505  }
506  }
507 #endif
508 
509  if ( (0 == port) &&
510  (NULL == unixpath) )
511  {
512  if (GNUNET_YES ==
514  service_name,
515  "START_ON_DEMAND"))
517  _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
518  service_name);
519  GNUNET_free_non_null (hostname);
520  return GNUNET_SYSERR;
521  }
522  if (0 == port)
523  {
524  saddrs = GNUNET_new_array (2,
525  struct sockaddr *);
526  saddrlens = GNUNET_new_array (2,
527  socklen_t);
528  add_unixpath (saddrs,
529  saddrlens,
530  unixpath,
531  abstract);
532  GNUNET_free_non_null (unixpath);
533  GNUNET_free_non_null (hostname);
534  *addrs = saddrs;
535  *addr_lens = saddrlens;
536  return 1;
537  }
538 
539  if (NULL != hostname)
540  {
542  "Resolving `%s' since that is where `%s' will bind to.\n",
543  hostname,
544  service_name);
545  memset (&hints, 0, sizeof (struct addrinfo));
546  if (disablev6)
547  hints.ai_family = AF_INET;
548  hints.ai_protocol = IPPROTO_TCP;
549  if ((0 != (ret = getaddrinfo (hostname,
550  NULL,
551  &hints,
552  &res))) ||
553  (NULL == res))
554  {
556  _("Failed to resolve `%s': %s\n"),
557  hostname,
558  gai_strerror (ret));
559  GNUNET_free (hostname);
560  GNUNET_free_non_null (unixpath);
561  return GNUNET_SYSERR;
562  }
563  next = res;
564  i = 0;
565  while (NULL != (pos = next))
566  {
567  next = pos->ai_next;
568  if ((disablev6) && (pos->ai_family == AF_INET6))
569  continue;
570  i++;
571  }
572  if (0 == i)
573  {
575  _("Failed to find %saddress for `%s'.\n"),
576  disablev6 ? "IPv4 " : "",
577  hostname);
578  freeaddrinfo (res);
579  GNUNET_free (hostname);
580  GNUNET_free_non_null (unixpath);
581  return GNUNET_SYSERR;
582  }
583  resi = i;
584  if (NULL != unixpath)
585  resi++;
586  saddrs = GNUNET_new_array (resi + 1,
587  struct sockaddr *);
588  saddrlens = GNUNET_new_array (resi + 1,
589  socklen_t);
590  i = 0;
591  if (NULL != unixpath)
592  {
593  add_unixpath (saddrs, saddrlens, unixpath, abstract);
594  i++;
595  }
596  next = res;
597  while (NULL != (pos = next))
598  {
599  next = pos->ai_next;
600  if ((disablev6) && (AF_INET6 == pos->ai_family))
601  continue;
602  if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
603  continue; /* not TCP */
604  if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
605  continue; /* huh? */
606  LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
607  service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
608  if (AF_INET == pos->ai_family)
609  {
610  GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
611  saddrlens[i] = pos->ai_addrlen;
612  saddrs[i] = GNUNET_malloc (saddrlens[i]);
613  GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
614  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
615  }
616  else
617  {
618  GNUNET_assert (AF_INET6 == pos->ai_family);
619  GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
620  saddrlens[i] = pos->ai_addrlen;
621  saddrs[i] = GNUNET_malloc (saddrlens[i]);
622  GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
623  ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
624  }
625  i++;
626  }
627  GNUNET_free (hostname);
628  freeaddrinfo (res);
629  resi = i;
630  }
631  else
632  {
633  /* will bind against everything, just set port */
634  if (disablev6)
635  {
636  /* V4-only */
637  resi = 1;
638  if (NULL != unixpath)
639  resi++;
640  i = 0;
641  saddrs = GNUNET_new_array (resi + 1,
642  struct sockaddr *);
643  saddrlens = GNUNET_new_array (resi + 1,
644  socklen_t);
645  if (NULL != unixpath)
646  {
647  add_unixpath (saddrs, saddrlens, unixpath, abstract);
648  i++;
649  }
650  saddrlens[i] = sizeof (struct sockaddr_in);
651  saddrs[i] = GNUNET_malloc (saddrlens[i]);
652 #if HAVE_SOCKADDR_IN_SIN_LEN
653  ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
654 #endif
655  ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
656  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
657  }
658  else
659  {
660  /* dual stack */
661  resi = 2;
662  if (NULL != unixpath)
663  resi++;
664  saddrs = GNUNET_new_array (resi + 1,
665  struct sockaddr *);
666  saddrlens = GNUNET_new_array (resi + 1,
667  socklen_t);
668  i = 0;
669  if (NULL != unixpath)
670  {
671  add_unixpath (saddrs,
672  saddrlens,
673  unixpath,
674  abstract);
675  i++;
676  }
677  saddrlens[i] = sizeof (struct sockaddr_in6);
678  saddrs[i] = GNUNET_malloc (saddrlens[i]);
679 #if HAVE_SOCKADDR_IN_SIN_LEN
680  ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
681 #endif
682  ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
683  ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
684  i++;
685  saddrlens[i] = sizeof (struct sockaddr_in);
686  saddrs[i] = GNUNET_malloc (saddrlens[i]);
687 #if HAVE_SOCKADDR_IN_SIN_LEN
688  ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
689 #endif
690  ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
691  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
692  }
693  }
694  GNUNET_free_non_null (unixpath);
695  *addrs = saddrs;
696  *addr_lens = saddrlens;
697  return resi;
698 }
699 
700 
711 static void
713  const char *name,
714  uint64_t request_id,
716 {
717  struct GNUNET_MQ_Envelope *env;
719 
720  (void) name;
721  env = GNUNET_MQ_msg (msg,
723  msg->result = htonl (result);
724  msg->arm_msg.request_id = GNUNET_htonll (request_id);
726  env);
727 }
728 
729 
738 static void
739 broadcast_status (const char *name,
742 {
743  struct GNUNET_MQ_Envelope *env;
745  size_t namelen;
746 
748  "Sending status %u of service `%s' to client\n",
749  (unsigned int) status,
750  name);
751  namelen = strlen (name) + 1;
752  env = GNUNET_MQ_msg_extra (msg,
753  namelen,
755  msg->status = htonl ((uint32_t) (status));
756  GNUNET_memcpy ((char *) &msg[1],
757  name,
758  namelen);
759  if (NULL == unicast)
760  {
761  if (NULL != notifier)
763  &msg->header,
764  GNUNET_YES);
765  GNUNET_MQ_discard (env);
766  }
767  else
768  {
770  env);
771  }
772 }
773 
774 
783 static void
785  struct GNUNET_SERVICE_Client *client,
786  uint64_t request_id)
787 {
788  char *loprefix;
789  char *options;
790  int use_debug;
791  int is_simple_service;
792  struct ServiceListeningInfo *sli;
793  SOCKTYPE *lsocks;
794  unsigned int ls;
795  char *binary;
796  char *quotedbinary;
797 
798  /* calculate listen socket list */
799  lsocks = NULL;
800  ls = 0;
801  for (sli = sl->listen_head; NULL != sli; sli = sli->next)
802  {
803  GNUNET_array_append (lsocks, ls,
805  if (NULL != sli->accept_task)
806  {
808  sli->accept_task = NULL;
809  }
810  }
811 #if WINDOWS
812  GNUNET_array_append (lsocks,
813  ls,
815 #else
816  GNUNET_array_append (lsocks,
817  ls,
818  -1);
819 #endif
820 
821  /* obtain configuration */
822  if (GNUNET_OK !=
824  sl->name,
825  "PREFIX",
826  &loprefix))
827  loprefix = GNUNET_strdup (prefix_command);
828  else
829  loprefix = GNUNET_CONFIGURATION_expand_dollar (cfg,
830  loprefix);
831  if (GNUNET_OK !=
833  sl->name,
834  "OPTIONS",
835  &options))
836  options = NULL;
837  else
838  options = GNUNET_CONFIGURATION_expand_dollar (cfg,
839  options);
840  {
841  char *new_options;
842  char *optpos;
843  char *fin_options;
844 
845  fin_options = GNUNET_strdup (final_option);
846  /* replace '{}' with service name */
847  while (NULL != (optpos = strstr (fin_options,
848  "{}")))
849  {
850  /* terminate string at opening parenthesis */
851  *optpos = 0;
852  GNUNET_asprintf (&new_options,
853  "%s%s%s",
854  fin_options,
855  sl->name,
856  optpos + 2);
857  GNUNET_free (fin_options);
858  fin_options = new_options;
859  }
860  if (NULL != options)
861  {
862  /* combine "fin_options" with "options" */
863  optpos = options;
864  GNUNET_asprintf (&options,
865  "%s %s",
866  fin_options,
867  optpos);
868  GNUNET_free (fin_options);
869  GNUNET_free (optpos);
870  }
871  else
872  {
873  /* only have "fin_options", use that */
874  options = fin_options;
875  }
876  }
877  options = GNUNET_CONFIGURATION_expand_dollar (cfg,
878  options);
879  use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg,
880  sl->name,
881  "DEBUG");
882  {
883  const char *service_type = NULL;
884  const char *choices[] = { "GNUNET", "SIMPLE", NULL };
885 
886  is_simple_service = GNUNET_NO;
887  if ( (GNUNET_OK ==
889  sl->name,
890  "TYPE",
891  choices,
892  &service_type)) &&
893  (0 == strcasecmp (service_type, "SIMPLE")) )
894  is_simple_service = GNUNET_YES;
895  }
896 
897  GNUNET_assert (NULL == sl->proc);
898  if (GNUNET_YES == is_simple_service)
899  {
900  /* A simple service will receive no GNUnet specific
901  command line options. */
902  binary = GNUNET_strdup (sl->binary);
903  binary = GNUNET_CONFIGURATION_expand_dollar (cfg, binary);
904  GNUNET_asprintf (&quotedbinary,
905  "\"%s\"",
906  sl->binary);
908  "Starting simple service `%s' using binary `%s'\n",
909  sl->name, sl->binary);
910  /* FIXME: dollar expansion should only be done outside
911  * of ''-quoted strings, escaping should be considered. */
912  if (NULL != options)
913  options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
914  sl->proc =
917  lsocks,
918  loprefix,
919  quotedbinary,
920  options,
921  NULL);
922  }
923  else
924  {
925  /* actually start process */
927  "Starting service `%s' using binary `%s' and configuration `%s'\n",
928  sl->name, sl->binary, sl->config);
930  GNUNET_asprintf (&quotedbinary,
931  "\"%s\"",
932  binary);
933 
934  if (GNUNET_YES == use_debug)
935  {
936  if (NULL == sl->config)
937  sl->proc =
940  lsocks,
941  loprefix,
942  quotedbinary,
943  "-L", "DEBUG",
944  options,
945  NULL);
946  else
947  sl->proc =
950  lsocks,
951  loprefix,
952  quotedbinary,
953  "-c", sl->config,
954  "-L", "DEBUG",
955  options,
956  NULL);
957  }
958  else
959  {
960  if (NULL == sl->config)
961  sl->proc =
964  lsocks,
965  loprefix,
966  quotedbinary,
967  options,
968  NULL);
969  else
970  sl->proc =
973  lsocks,
974  loprefix,
975  quotedbinary,
976  "-c", sl->config,
977  options,
978  NULL);
979  }
980  }
981  GNUNET_free (binary);
982  GNUNET_free (quotedbinary);
983  if (NULL == sl->proc)
984  {
986  _("Failed to start service `%s'\n"),
987  sl->name);
988  if (client)
989  signal_result (client,
990  sl->name,
991  request_id,
993  }
994  else
995  {
997  _("Starting service `%s'\n"),
998  sl->name);
999  broadcast_status (sl->name,
1001  NULL);
1002  if (client)
1003  signal_result (client,
1004  sl->name,
1005  request_id,
1007  }
1008  /* clean up */
1009  GNUNET_free (loprefix);
1010  GNUNET_free (options);
1011  GNUNET_array_grow (lsocks,
1012  ls,
1013  0);
1014 }
1015 
1016 
1024 static struct ServiceList *
1025 find_service (const char *name)
1026 {
1027  struct ServiceList *sl;
1028 
1029  sl = running_head;
1030  while (sl != NULL)
1031  {
1032  if (0 == strcasecmp (sl->name, name))
1033  return sl;
1034  sl = sl->next;
1035  }
1036  return NULL;
1037 }
1038 
1039 
1046 static void
1048 {
1049  struct ServiceListeningInfo *sli = cls;
1050  struct ServiceList *sl = sli->sl;
1051 
1052  sli->accept_task = NULL;
1054  start_process (sl, NULL, 0);
1055 }
1056 
1057 
1066 static void
1067 create_listen_socket (struct sockaddr *sa,
1068  socklen_t addr_len,
1069  struct ServiceList *sl)
1070 {
1071  static int on = 1;
1072  struct GNUNET_NETWORK_Handle *sock;
1073  struct ServiceListeningInfo *sli;
1074 #ifndef WINDOWS
1075  int match_uid;
1076  int match_gid;
1077 #endif
1078 
1079  switch (sa->sa_family)
1080  {
1081  case AF_INET:
1082  sock = GNUNET_NETWORK_socket_create (PF_INET,
1083  SOCK_STREAM,
1084  0);
1085  break;
1086  case AF_INET6:
1087  sock = GNUNET_NETWORK_socket_create (PF_INET6,
1088  SOCK_STREAM,
1089  0);
1090  break;
1091  case AF_UNIX:
1092  if (0 == strcmp (GNUNET_a2s (sa,
1093  addr_len),
1094  "@")) /* Do not bind to blank UNIX path! */
1095  return;
1096  sock = GNUNET_NETWORK_socket_create (PF_UNIX,
1097  SOCK_STREAM,
1098  0);
1099  break;
1100  default:
1101  GNUNET_break (0);
1102  sock = NULL;
1103  errno = EAFNOSUPPORT;
1104  break;
1105  }
1106  if (NULL == sock)
1107  {
1109  _("Unable to create socket for service `%s': %s\n"),
1110  sl->name,
1111  STRERROR (errno));
1112  GNUNET_free (sa);
1113  return;
1114  }
1115  if (GNUNET_OK !=
1117  SOL_SOCKET,
1118  SO_REUSEADDR,
1119  &on,
1120  sizeof (on)))
1122  "setsockopt");
1123 #ifdef IPV6_V6ONLY
1124  if ( (sa->sa_family == AF_INET6) &&
1125  (GNUNET_OK !=
1127  IPPROTO_IPV6,
1128  IPV6_V6ONLY,
1129  &on,
1130  sizeof (on))) )
1132  "setsockopt");
1133 #endif
1134 #ifndef WINDOWS
1135  if (AF_UNIX == sa->sa_family)
1136  GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1137 #endif
1138  if (GNUNET_OK !=
1140  (const struct sockaddr *) sa,
1141  addr_len))
1142  {
1144  _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1145  sl->name,
1146  GNUNET_a2s (sa,
1147  addr_len),
1148  STRERROR (errno));
1151  GNUNET_free (sa);
1152  return;
1153  }
1154 #ifndef WINDOWS
1155  if ((AF_UNIX == sa->sa_family)
1156 #ifdef LINUX
1157  /* Permission settings are not required when abstract sockets are used */
1158  && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
1159 #endif
1160  )
1161  {
1162  match_uid =
1164  sl->name,
1165  "UNIX_MATCH_UID");
1166  match_gid =
1168  sl->name,
1169  "UNIX_MATCH_GID");
1170  GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
1171  match_uid,
1172  match_gid);
1173 
1174  }
1175 #endif
1176  if (GNUNET_OK !=
1177  GNUNET_NETWORK_socket_listen (sock, 5))
1178  {
1180  "listen");
1183  GNUNET_free (sa);
1184  return;
1185  }
1187  _("ARM now monitors connections to service `%s' at `%s'\n"),
1188  sl->name,
1189  GNUNET_a2s (sa,
1190  addr_len));
1191  sli = GNUNET_new (struct ServiceListeningInfo);
1192  sli->service_addr = sa;
1193  sli->service_addr_len = addr_len;
1194  sli->listen_socket = sock;
1195  sli->sl = sl;
1196  sli->accept_task
1198  sock,
1199  &accept_connection, sli);
1201  sl->listen_tail,
1202  sli);
1203 }
1204 
1205 
1212 static void
1214 {
1216  GNUNET_CONTAINER_DLL_remove (running_head,
1217  running_tail,
1218  sl);
1219  GNUNET_assert (NULL == sl->listen_head);
1222  GNUNET_free (sl->name);
1223  GNUNET_free (sl);
1224 }
1225 
1226 
1235 static int
1236 check_start (void *cls,
1237  const struct GNUNET_ARM_Message *amsg)
1238 {
1239  (void) cls;
1241  return GNUNET_OK;
1242 }
1243 
1244 
1251 static void
1252 handle_start (void *cls,
1253  const struct GNUNET_ARM_Message *amsg)
1254 {
1255  struct GNUNET_SERVICE_Client *client = cls;
1256  const char *servicename;
1257  struct ServiceList *sl;
1258  uint64_t request_id;
1259 
1260  request_id = GNUNET_ntohll (amsg->request_id);
1261  servicename = (const char *) &amsg[1];
1263  if (GNUNET_YES == in_shutdown)
1264  {
1265  signal_result (client,
1266  servicename,
1267  request_id,
1269  return;
1270  }
1271  sl = find_service (servicename);
1272  if (NULL == sl)
1273  {
1274  signal_result (client,
1275  servicename,
1276  request_id,
1278  return;
1279  }
1280  sl->force_start = GNUNET_YES;
1281  if (NULL != sl->proc)
1282  {
1283  signal_result (client,
1284  servicename,
1285  request_id,
1287  return;
1288  }
1289  start_process (sl,
1290  client,
1291  request_id);
1292 }
1293 
1294 
1300 static void
1301 trigger_shutdown (void *cls)
1302 {
1303  (void) cls;
1305  "Triggering shutdown\n");
1307 }
1308 
1309 
1318 static int
1319 check_stop (void *cls,
1320  const struct GNUNET_ARM_Message *amsg)
1321 {
1322  (void) cls;
1324  return GNUNET_OK;
1325 }
1326 
1327 
1334 static void
1335 handle_stop (void *cls,
1336  const struct GNUNET_ARM_Message *amsg)
1337 {
1338  struct GNUNET_SERVICE_Client *client = cls;
1339  struct ServiceList *sl;
1340  const char *servicename;
1341  uint64_t request_id;
1342 
1343  request_id = GNUNET_ntohll (amsg->request_id);
1344  servicename = (const char *) &amsg[1];
1346  _("Preparing to stop `%s'\n"),
1347  servicename);
1349  if (0 == strcasecmp (servicename,
1350  "arm"))
1351  {
1352  broadcast_status (servicename,
1354  NULL);
1355  signal_result (client,
1356  servicename,
1357  request_id,
1361  NULL);
1362  return;
1363  }
1364  sl = find_service (servicename);
1365  if (NULL == sl)
1366  {
1367  signal_result (client,
1368  servicename,
1369  request_id,
1371  return;
1372  }
1373  sl->force_start = GNUNET_NO;
1374  if (GNUNET_YES == in_shutdown)
1375  {
1376  /* shutdown in progress */
1377  signal_result (client,
1378  servicename,
1379  request_id,
1381  return;
1382  }
1383  if (NULL != sl->killing_client)
1384  {
1385  /* killing already in progress */
1386  signal_result (client,
1387  servicename,
1388  request_id,
1390  return;
1391  }
1392  if (NULL == sl->proc)
1393  {
1394  /* process is down */
1395  signal_result (client,
1396  servicename,
1397  request_id,
1399  return;
1400  }
1402  "Sending kill signal to service `%s', waiting for process to die.\n",
1403  servicename);
1404  broadcast_status (servicename,
1406  NULL);
1407  /* no signal_start - only when it's STOPPED */
1409  if (0 != GNUNET_OS_process_kill (sl->proc,
1410  GNUNET_TERM_SIG))
1412  "kill");
1413  sl->killing_client = client;
1414  sl->killing_client_request_id = request_id;
1415 }
1416 
1417 
1424 static void
1425 handle_list (void *cls,
1426  const struct GNUNET_ARM_Message *request)
1427 {
1428  struct GNUNET_SERVICE_Client *client = cls;
1429  struct GNUNET_MQ_Envelope *env;
1431  size_t string_list_size;
1432  struct ServiceList *sl;
1433  uint16_t count;
1434  char *pos;
1435 
1436  GNUNET_break (0 == ntohl (request->reserved));
1437  count = 0;
1438  string_list_size = 0;
1439 
1440  /* first count the running processes get their name's size */
1441  for (sl = running_head; NULL != sl; sl = sl->next)
1442  {
1443  if (NULL != sl->proc)
1444  {
1445  string_list_size += strlen (sl->name);
1446  string_list_size += strlen (sl->binary);
1447  string_list_size += 4;
1448  count++;
1449  }
1450  }
1451 
1452  env = GNUNET_MQ_msg_extra (msg,
1453  string_list_size,
1455  msg->arm_msg.request_id = request->request_id;
1456  msg->count = htons (count);
1457 
1458  pos = (char *) &msg[1];
1459  for (sl = running_head; NULL != sl; sl = sl->next)
1460  {
1461  if (NULL != sl->proc)
1462  {
1463  size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
1464  GNUNET_snprintf (pos,
1465  s,
1466  "%s (%s)",
1467  sl->name,
1468  sl->binary);
1469  pos += s;
1470  }
1471  }
1473  env);
1475 }
1476 
1477 
1484 static void
1485 handle_test (void *cls,
1486  const struct GNUNET_MessageHeader *message)
1487 {
1488  struct GNUNET_SERVICE_Client *client = cls;
1489  struct GNUNET_MQ_Envelope *env;
1490  struct GNUNET_MessageHeader *msg;
1491 
1492  (void) message;
1493  env = GNUNET_MQ_msg (msg,
1496  env);
1498 }
1499 
1500 
1505 static void
1507 {
1509  "Last shutdown phase\n");
1510  if (NULL != notifier)
1511  {
1513  notifier = NULL;
1514  }
1515  if (NULL != service)
1516  {
1517  GNUNET_SERVICE_shutdown (service);
1518  service = NULL;
1519  }
1520  if (NULL != child_death_task)
1521  {
1522  GNUNET_SCHEDULER_cancel (child_death_task);
1523  child_death_task = NULL;
1524  }
1525 }
1526 
1527 
1534 static unsigned int
1535 list_count (struct ServiceList *running_head)
1536 {
1537  struct ServiceList *i;
1538  unsigned int res;
1539 
1540  for (res = 0, i = running_head; NULL != i; i = i->next, res++)
1542  "%s\n",
1543  i->name);
1544  return res;
1545 }
1546 
1547 
1553 static void
1554 shutdown_task (void *cls)
1555 {
1556  struct ServiceList *pos;
1557  struct ServiceList *nxt;
1558  struct ServiceListeningInfo *sli;
1559 
1560  (void) cls;
1562  "First shutdown phase\n");
1563  if (NULL != child_restart_task)
1564  {
1565  GNUNET_SCHEDULER_cancel (child_restart_task);
1566  child_restart_task = NULL;
1567  }
1569  /* first, stop listening */
1570  for (pos = running_head; NULL != pos; pos = pos->next)
1571  {
1572  while (NULL != (sli = pos->listen_head))
1573  {
1575  pos->listen_tail,
1576  sli);
1577  if (NULL != sli->accept_task)
1578  {
1580  sli->accept_task = NULL;
1581  }
1584  GNUNET_free (sli->service_addr);
1585  GNUNET_free (sli);
1586  }
1587  }
1588  /* then, shutdown all existing service processes */
1589  nxt = running_head;
1590  while (NULL != (pos = nxt))
1591  {
1592  nxt = pos->next;
1593  if (NULL != pos->proc)
1594  {
1596  "Stopping service `%s'\n",
1597  pos->name);
1599  if (0 != GNUNET_OS_process_kill (pos->proc,
1600  GNUNET_TERM_SIG))
1602  "kill");
1603  }
1604  else
1605  {
1606  free_service (pos);
1607  }
1608  }
1609  /* finally, should all service processes be already gone, terminate for real */
1610  if (NULL == running_head)
1611  do_shutdown ();
1612  else
1614  "Delaying shutdown, have %u childs still running\n",
1615  list_count (running_head));
1616 }
1617 
1618 
1624 static void
1626 
1627 {
1628  struct ServiceList *sl;
1629  struct GNUNET_TIME_Relative lowestRestartDelay;
1630  struct ServiceListeningInfo *sli;
1631 
1632  (void) cls;
1633  child_restart_task = NULL;
1635  lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1636 
1637  /* check for services that need to be restarted due to
1638  * configuration changes or because the last restart failed */
1639  for (sl = running_head; NULL != sl; sl = sl->next)
1640  {
1641  if (NULL != sl->proc)
1642  continue;
1643  /* service is currently not running */
1645  {
1646  /* restart is now allowed */
1647  if (sl->force_start)
1648  {
1649  /* process should run by default, start immediately */
1651  _("Restarting service `%s'.\n"),
1652  sl->name);
1653  start_process (sl,
1654  NULL,
1655  0);
1656  }
1657  else
1658  {
1659  /* process is run on-demand, ensure it is re-started if there is demand */
1660  for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1661  if (NULL == sli->accept_task)
1662  {
1663  /* accept was actually paused, so start it again */
1664  sli->accept_task
1666  sli->listen_socket,
1668  sli);
1669  }
1670  }
1671  }
1672  else
1673  {
1674  /* update calculation for earliest time to reactivate a service */
1675  lowestRestartDelay =
1676  GNUNET_TIME_relative_min (lowestRestartDelay,
1678  (sl->restart_at));
1679  }
1680  }
1681  if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1682  {
1684  "Will restart process in %s\n",
1685  GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1686  GNUNET_YES));
1687  child_restart_task =
1688  GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1691  NULL);
1692  }
1693 }
1694 
1695 
1702 static void
1704 {
1705  struct ServiceList *pos;
1706  struct ServiceList *next;
1707  struct ServiceListeningInfo *sli;
1708  const char *statstr;
1709  int statcode;
1710  int ret;
1711  char c[16];
1712  enum GNUNET_OS_ProcessStatusType statusType;
1713  unsigned long statusCode;
1714  const struct GNUNET_DISK_FileHandle *pr;
1715 
1716  (void) cls;
1717  pr = GNUNET_DISK_pipe_handle (sigpipe,
1719  child_death_task = NULL;
1720  /* consume the signal */
1722  &c,
1723  sizeof (c)));
1724 
1725  /* check for services that died (WAITPID) */
1726  next = running_head;
1727  while (NULL != (pos = next))
1728  {
1729  next = pos->next;
1730 
1731  if (NULL == pos->proc)
1732  {
1733  if (GNUNET_YES == in_shutdown)
1734  free_service (pos);
1735  continue;
1736  }
1737 #if HAVE_WAIT4
1738  if (NULL != wait_file)
1739  {
1740  /* need to use 'wait4()' to obtain and log performance data */
1741  struct rusage ru;
1742  int status;
1743  pid_t pid;
1744 
1745  pid = GNUNET_OS_process_get_pid (pos->proc);
1746  ret = wait4 (pid,
1747  &status,
1748  WNOHANG,
1749  &ru);
1750  if (ret <= 0)
1751  continue; /* no process done */
1752  if (WIFEXITED (status))
1753  {
1754  statusType = GNUNET_OS_PROCESS_EXITED;
1755  statusCode = WEXITSTATUS (status);
1756  }
1757  else if (WIFSIGNALED (status))
1758  {
1759  statusType = GNUNET_OS_PROCESS_SIGNALED;
1760  statusCode = WTERMSIG (status);
1761  }
1762  else if (WIFSTOPPED (status))
1763  {
1764  statusType = GNUNET_OS_PROCESS_SIGNALED;
1765  statusCode = WSTOPSIG (status);
1766  }
1767 #ifdef WIFCONTINUED
1768  else if (WIFCONTINUED (status))
1769  {
1770  statusType = GNUNET_OS_PROCESS_RUNNING;
1771  statusCode = 0;
1772  }
1773 #endif
1774  else
1775  {
1776  statusType = GNUNET_OS_PROCESS_UNKNOWN;
1777  statusCode = 0;
1778  }
1779  if ( (GNUNET_OS_PROCESS_EXITED == statusType) ||
1780  (GNUNET_OS_PROCESS_SIGNALED == statusType) )
1781  {
1782  double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1783  double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1784  fprintf (wait_file,
1785  "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1786  pos->binary,
1787  (unsigned int) pid,
1788  utime,
1789  stime,
1790  (unsigned long long) ru.ru_maxrss,
1791  (unsigned long long) ru.ru_inblock,
1792  (unsigned long long) ru.ru_oublock,
1793  (unsigned long long) ru.ru_nvcsw,
1794  (unsigned long long) ru.ru_nivcsw);
1795  }
1796  }
1797  else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1798 #endif
1799  if ( (GNUNET_SYSERR ==
1800  (ret =
1802  &statusType,
1803  &statusCode))) ||
1804  (ret == GNUNET_NO) ||
1805  (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1806  (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1807  (statusType == GNUNET_OS_PROCESS_RUNNING) )
1808  continue;
1809 
1810  if (statusType == GNUNET_OS_PROCESS_EXITED)
1811  {
1812  statstr = _( /* process termination method */ "exit");
1813  statcode = statusCode;
1814  }
1815  else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1816  {
1817  statstr = _( /* process termination method */ "signal");
1818  statcode = statusCode;
1819  }
1820  else
1821  {
1822  statstr = _( /* process termination method */ "unknown");
1823  statcode = 0;
1824  }
1825  if (0 != pos->killed_at.abs_value_us)
1826  {
1828  _("Service `%s' took %s to terminate\n"),
1829  pos->name,
1831  GNUNET_YES));
1832  }
1834  pos->proc = NULL;
1835  broadcast_status (pos->name,
1837  NULL);
1838  if (NULL != pos->killing_client)
1839  {
1840  signal_result (pos->killing_client, pos->name,
1843  pos->killing_client = NULL;
1844  pos->killing_client_request_id = 0;
1845  }
1846  if (GNUNET_YES != in_shutdown)
1847  {
1848  if ( (statusType == GNUNET_OS_PROCESS_EXITED) &&
1849  (statcode == 0) )
1850  {
1851  /* process terminated normally, allow restart at any time */
1852  pos->restart_at.abs_value_us = 0;
1854  _("Service `%s' terminated normally, will restart at any time\n"),
1855  pos->name);
1856  /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1857  for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1858  {
1859  GNUNET_break (NULL == sli->accept_task);
1860  sli->accept_task =
1862  sli->listen_socket,
1864  sli);
1865  }
1866  }
1867  else
1868  {
1870  _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1871  pos->name,
1872  statstr,
1873  statcode,
1875  GNUNET_YES));
1876  {
1877  /* Reduce backoff based on runtime of the process,
1878  so that there is a cool-down if a process actually
1879  runs for a while. */
1880  struct GNUNET_TIME_Relative runtime;
1881  unsigned int minutes;
1882 
1884  minutes = runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1885  if (minutes > 31)
1887  else
1888  pos->backoff.rel_value_us <<= minutes;
1889  }
1890  /* schedule restart */
1892  pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1893  if (NULL != child_restart_task)
1894  GNUNET_SCHEDULER_cancel (child_restart_task);
1895  child_restart_task
1898  NULL);
1899  }
1900  }
1901  else
1902  {
1903  free_service (pos);
1904  }
1905  }
1906  child_death_task = GNUNET_SCHEDULER_add_read_file (
1908  pr,
1909  &maint_child_death, NULL);
1910  if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1911  do_shutdown ();
1912  else if (GNUNET_YES == in_shutdown)
1914  "Delaying shutdown after child's death, still have %u children\n",
1915  list_count (running_head));
1916 
1917 }
1918 
1919 
1924 static void
1926 {
1927  static char c;
1928  int old_errno = errno; /* back-up errno */
1929 
1930  GNUNET_break (1 ==
1933  &c,
1934  sizeof (c)));
1935  errno = old_errno; /* restore errno */
1936 }
1937 
1938 
1947 static void
1948 setup_service (void *cls,
1949  const char *section)
1950 {
1951  struct ServiceList *sl;
1952  char *binary;
1953  char *config;
1954  struct stat sbuf;
1955  struct sockaddr **addrs;
1956  socklen_t *addr_lens;
1957  int ret;
1958 
1959  (void) cls;
1960  if (0 == strcasecmp (section,
1961  "arm"))
1962  return;
1963  if (GNUNET_OK !=
1965  section,
1966  "BINARY",
1967  &binary))
1968  {
1969  /* not a service section */
1970  return;
1971  }
1972  if ((GNUNET_YES ==
1974  section,
1975  "RUN_PER_USER")) &&
1976  (GNUNET_YES ==
1978  section,
1979  "RUN_PER_USER")))
1980  {
1981  if (GNUNET_NO == start_user)
1982  {
1983  GNUNET_free (binary);
1984  return; /* user service, and we don't deal with those */
1985  }
1986  }
1987  else
1988  {
1989  if (GNUNET_NO == start_system)
1990  {
1991  GNUNET_free (binary);
1992  return; /* system service, and we don't deal with those */
1993  }
1994  }
1995  sl = find_service (section);
1996  if (NULL != sl)
1997  {
1998  /* got the same section twice!? */
1999  GNUNET_break (0);
2000  GNUNET_free (binary);
2001  return;
2002  }
2003  config = NULL;
2004  if (( (GNUNET_OK !=
2006  section,
2007  "CONFIG",
2008  &config)) &&
2009  (GNUNET_OK !=
2011  "PATHS",
2012  "DEFAULTCONFIG",
2013  &config)) ) ||
2014  (0 != STAT (config, &sbuf)))
2015  {
2016  if (NULL != config)
2017  {
2019  section, "CONFIG",
2020  STRERROR (errno));
2021  GNUNET_free (config);
2022  config = NULL;
2023  }
2024  }
2025  sl = GNUNET_new (struct ServiceList);
2026  sl->name = GNUNET_strdup (section);
2027  sl->binary = binary;
2028  sl->config = config;
2031 #if WINDOWS
2032  sl->pipe_control = GNUNET_YES;
2033 #else
2035  section,
2036  "PIPECONTROL"))
2038  section,
2039  "PIPECONTROL");
2040 #endif
2041  GNUNET_CONTAINER_DLL_insert (running_head,
2042  running_tail,
2043  sl);
2044  if (GNUNET_YES ==
2046  section,
2047  "IMMEDIATE_START"))
2048  {
2049  sl->force_start = GNUNET_YES;
2050  if (GNUNET_YES ==
2052  section,
2053  "NOARMBIND"))
2054  return;
2055  }
2056  else
2057  {
2058  if (GNUNET_YES !=
2060  section,
2061  "START_ON_DEMAND"))
2062  return;
2063  }
2064  if (0 >= (ret = get_server_addresses (section,
2065  cfg,
2066  &addrs,
2067  &addr_lens)))
2068  return;
2069  /* this will free (or capture) addrs[i] */
2070  for (unsigned int i = 0; i < (unsigned int) ret; i++)
2071  create_listen_socket (addrs[i],
2072  addr_lens[i],
2073  sl);
2074  GNUNET_free (addrs);
2075  GNUNET_free (addr_lens);
2076 }
2077 
2078 
2087 static void *
2089  struct GNUNET_SERVICE_Client *client,
2090  struct GNUNET_MQ_Handle *mq)
2091 {
2092  /* All clients are considered to be of the "monitor" kind
2093  * (that is, they don't affect ARM shutdown).
2094  */
2095  (void) cls;
2096  (void) mq;
2098  return client;
2099 }
2100 
2101 
2109 static void
2111  struct GNUNET_SERVICE_Client *client,
2112  void *app_ctx)
2113 {
2114  (void) cls;
2115  GNUNET_assert (client == app_ctx);
2116  for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2117  if (sl->killing_client == client)
2118  sl->killing_client = NULL;
2119 }
2120 
2121 
2130 static void
2131 handle_monitor (void *cls,
2132  const struct GNUNET_MessageHeader *message)
2133 {
2134  struct GNUNET_SERVICE_Client *client = cls;
2135 
2136  (void) message;
2137  /* FIXME: might want to start by letting monitor know about
2138  services that are already running */
2139  /* Removal is handled by the server implementation, internally. */
2141  GNUNET_SERVICE_client_get_mq (client));
2142  broadcast_status ("arm",
2144  client);
2146 }
2147 
2148 
2156 static void
2157 run (void *cls,
2158  const struct GNUNET_CONFIGURATION_Handle *c,
2159  struct GNUNET_SERVICE_Handle *serv)
2160 {
2161  struct ServiceList *sl;
2162 
2163  (void) cls;
2164  cfg = c;
2165  service = serv;
2167  NULL);
2168  child_death_task =
2170  GNUNET_DISK_pipe_handle (sigpipe,
2173  NULL);
2174 #if HAVE_WAIT4
2175  if (GNUNET_OK ==
2177  "ARM",
2178  "RESOURCE_DIAGNOSTICS",
2179  &wait_filename))
2180  {
2181  wait_file = fopen (wait_filename,
2182  "w");
2183  if (NULL == wait_file)
2184  {
2186  "fopen",
2187  wait_filename);
2188  }
2189  }
2190 #endif
2191  if (GNUNET_OK !=
2193  "ARM",
2194  "GLOBAL_PREFIX",
2195  &prefix_command))
2197  else
2199  prefix_command);
2200  if (GNUNET_OK !=
2202  "ARM",
2203  "GLOBAL_POSTFIX",
2204  &final_option))
2205  final_option = GNUNET_strdup ("");
2206  else
2208  final_option);
2210  "ARM",
2211  "START_USER_SERVICES");
2213  "ARM",
2214  "START_SYSTEM_SERVICES");
2215  if ( (GNUNET_NO == start_user) &&
2216  (GNUNET_NO == start_system) )
2217  {
2219  "Please configure either START_USER_SERVICES or START_SYSTEM_SERVICES or both.\n");
2221  global_ret = 1;
2222  return;
2223  }
2225  &setup_service,
2226  NULL);
2227 
2228  /* start default services... */
2229  for (sl = running_head; NULL != sl; sl = sl->next)
2230  if (GNUNET_YES == sl->force_start)
2231  start_process (sl,
2232  NULL,
2233  0);
2235 }
2236 
2237 
2245 int
2246 main (int argc,
2247  char *const *argv)
2248 {
2249  struct GNUNET_SIGNAL_Context *shc_chld;
2250  struct GNUNET_MQ_MessageHandler handlers[] = {
2253  struct GNUNET_ARM_Message,
2254  NULL),
2255  GNUNET_MQ_hd_var_size (stop,
2257  struct GNUNET_ARM_Message,
2258  NULL),
2261  struct GNUNET_MessageHeader,
2262  NULL),
2265  struct GNUNET_ARM_Message,
2266  NULL),
2269  struct GNUNET_MessageHeader,
2270  NULL),
2272  };
2273 
2274  sigpipe = GNUNET_DISK_pipe (GNUNET_NO,
2275  GNUNET_NO,
2276  GNUNET_NO,
2277  GNUNET_NO);
2278  GNUNET_assert (NULL != sigpipe);
2279  shc_chld =
2282  if ( GNUNET_OK != GNUNET_SERVICE_run_ (argc,
2283  argv,
2284  "arm",
2286  &run,
2289  NULL,
2290  handlers))
2291  global_ret = 2;
2292 #if HAVE_WAIT4
2293  if (NULL != wait_file)
2294  {
2295  fclose (wait_file);
2296  wait_file = NULL;
2297  }
2298  if (NULL != wait_filename)
2299  {
2300  GNUNET_free (wait_filename);
2301  wait_filename = NULL;
2302  }
2303 #endif
2305  shc_chld = NULL;
2306  GNUNET_DISK_pipe_close (sigpipe);
2307  sigpipe = NULL;
2308  return global_ret;
2309 }
2310 
2311 
2312 #if defined(LINUX) && defined(__GLIBC__)
2313 #include <malloc.h>
2314 
2318 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
2319 {
2320  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2321  mallopt (M_TOP_PAD, 1 * 1024);
2322  malloc_trim (0);
2323 }
2324 #endif
2325 
2326 
2327 /* end of gnunet-service-arm.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
int GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:796
static void handle_start(void *cls, const struct GNUNET_ARM_Message *amsg)
Handle START-message.
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:1005
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1268
static struct ServiceList * running_head
List of running services.
ARM stopping was initiated (there&#39;s no "stopped" for ARM itself).
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:351
char * config
Name of the configuration file used.
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition: nc.c:77
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
static char * prefix_command
Command to prepend to each actual command.
#define GNUNET_MESSAGE_TYPE_ARM_STATUS
Status update from ARM.
#define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT
Response from ARM for listing currently running services.
int 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.
uint64_t rel_value_us
The actual value.
static struct GNUNET_SCHEDULER_Task * child_death_task
ID of task called whenever we get a SIGCHILD.
struct ServiceList * prev
This is a doubly-linked list.
Asked to stop it, but it&#39;s already stopping.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
uint64_t request_id
ID of a request that is being replied to.
Definition: arm.h:78
static struct GNUNET_TIME_Relative backoff
How long should we wait to reconnect?
Definition: resolver_api.c:81
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#define SOCKTYPE
Definition: platform.h:276
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:364
Handle to a service.
Definition: service.c:116
Status update from ARM to client.
Definition: arm.h:41
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
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:1178
#define GNUNET_SIGCHLD
Definition: platform.h:46
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition: service.c:2734
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:881
int GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process, waiting on it if dead.
Definition: os_priority.c:1719
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1293
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct ServiceListeningInfo * prev
This is a linked list.
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
Do not trigger server shutdown on signal at all; instead, allow for the user to terminate the server ...
#define GNUNET_MESSAGE_TYPE_ARM_RESULT
Response from ARM.
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:245
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...
struct GNUNET_TIME_Relative backoff
Process exponential backoff time.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up associated state.
#define STRERROR(i)
Definition: plibc.h:676
struct ServiceListeningInfo * listen_head
Linked list of listen sockets associated with this service.
#define GNUNET_MESSAGE_TYPE_ARM_START
Request to ARM to start a service.
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(int pipe_control, unsigned int std_inheritance, const SOCKTYPE *lsocks, const char *filename,...)
Start a process.
Definition: os_priority.c:1474
#define GNUNET_MESSAGE_TYPE_ARM_STOP
Request to ARM to stop a service.
struct GNUNET_ARM_Message arm_msg
Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT, with an ID.
Definition: arm.h:113
int 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:522
int main(int argc, char *const *argv)
The main function for the arm service.
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
static void handle_test(void *cls, const struct GNUNET_MessageHeader *message)
Handle TEST-message by sending back TEST.
static unsigned int list_count(struct ServiceList *running_head)
Count how many services are still active.
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:67
int GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition: disk.c:833
static void maint_child_death(void *cls)
Task triggered whenever we receive a SIGCHLD (child process died).
#define GNUNET_NO
Definition: gnunet_common.h:81
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:1643
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal hander.
Definition: signal.c:99
struct GNUNET_TIME_Absolute restart_at
Absolute time at which the process is scheduled to restart in case of death.
socklen_t service_addr_len
Number of bytes in service_addr.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
GNUNET_ARM_Result
Replies to ARM requests.
Service starting was initiated.
int pipe_control
Should we use pipes to signal this process? (YES for Java binaries and if we are on Windoze)...
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 STAT(p, b)
Definition: plibc.h:663
#define LOG(kind,...)
Asked to start it, but it&#39;s already started.
static void create_listen_socket(struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl)
Creating a listening socket for each of the service&#39;s addresses and wait for the first incoming conne...
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:524
static int ret
Final status code.
Definition: gnunet-arm.c:89
uint32_t reserved
For alignment.
Definition: arm.h:71
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition: nc.c:164
uint64_t abs_value_us
The actual value.
uint16_t count
Number of &#39;\0&#39; terminated strings that follow this message.
Definition: arm.h:119
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
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:2641
struct ServiceList * sl
Service this listen socket is for.
static int start_user
Are we starting user services?
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
struct GNUNET_SCHEDULER_Task * accept_task
Task doing the accepting.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static char * section
Name of the section.
Definition: gnunet-config.c:33
struct ServiceList * next
This is a doubly-linked list.
Handle to a client that is connected to a service.
Definition: service.c:249
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.
static struct ServiceList * find_service(const char *name)
Find the process with the given service name in the given list and return it.
uint64_t killing_client_request_id
ID of the request that killed the service (for reporting back).
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *serv)
Process arm requests.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
List of our services.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
#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:52
static void sighandler_child_death()
Signal handler called for SIGCHLD.
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:1200
#define GNUNET_MQ_check_zero_termination(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
static void handle_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
Handle STOP-message.
struct GNUNET_ARM_Message arm_msg
Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT, with an ID.
Definition: arm.h:93
Tried to start a service, but that failed for some reason.
#define GNUNET_memcpy(dst, src, n)
Service starting was initiated.
#define INVALID_SOCKET
Definition: network.c:39
uint32_t result
Result from the enum GNUNET_ARM_Result
Definition: arm.h:98
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
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:1049
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:1273
GNUNET_OS_ProcessStatusType
Process status types.
int 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.
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:727
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition: gnunet-vpn.c:51
uint16_t status
See PRISM_STATUS_*-constants.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define MAX_NOTIFY_QUEUE
How many messages do we queue up at most for optional notifications to a client? (this can cause noti...
static const struct GNUNET_CONFIGURATION_Handle * config
static int result
Global testing status.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
The writing-end of a pipe.
Service was stopped.
Record with information about a listen socket we have open.
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)...
The reading-end of a pipe.
static struct ServiceList * running_tail
List of running services.
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the &#39;monitor&#39; flag on this client.
Definition: service.c:2704
The process exited with a return code.
static void delayed_restart_task(void *cls)
Task run whenever it is time to restart a child that died.
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
static void trigger_shutdown(void *cls)
Start a shutdown sequence.
Message handler for a specific message type.
static int res
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
When these flags are set, the child process will inherit stdout and stderr of the parent...
Definition: gnunet_os_lib.h:98
Asked to start something, but ARM is shutting down and can&#39;t comply.
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(int blocking_read, int blocking_write, int inherit_read, int inherit_write)
Creates an interprocess channel.
Definition: disk.c:2289
Run when otherwise idle.
int 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.
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate shutdown via signal.
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition: mq.c:321
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 void shutdown_task(void *cls)
Task run for shutdown.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:35
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:59
int force_start
Is this service to be started by default (or did a client tell us explicitly to start it)...
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:271
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static void handle_list(void *cls, const struct GNUNET_ARM_Message *request)
Handle LIST-message.
static void broadcast_status(const char *name, enum GNUNET_ARM_ServiceStatus status, struct GNUNET_SERVICE_Client *unicast)
Tell all clients about status change of a service.
#define GNUNET_MESSAGE_TYPE_ARM_LIST
Request to ARM to list all currently running services.
const char * name
static int check_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
Check STOP-message.
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
Reply from ARM to client for the GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count &#39;\0&#39; terminat...
Definition: arm.h:107
static void unicast(struct TransportClient *tc, const struct GNUNET_MessageHeader *msg, int may_drop)
Queue the given message for transmission to the given client.
static void handle_monitor(void *cls, const struct GNUNET_MessageHeader *message)
Handle MONITOR-message.
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static void start_process(struct ServiceList *sl, struct GNUNET_SERVICE_Client *client, uint64_t request_id)
Actually start the process for the given service.
The process was killed by a signal.
static void free_service(struct ServiceList *sl)
Remove and free an entry in the service list.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
static char * final_option
Option to append to each actual command.
Asked to stop it, but it&#39;s already stopped.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition: nc.c:125
Handle to a message queue.
Definition: mq.c:85
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:2603
uint32_t status
Status from the &#39;enum GNUNET_ARM_ServiceStatus&#39;.
Definition: arm.h:52
GNUNET_ARM_ServiceStatus
Statuses of services.
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
struct GNUNET_OS_Process * proc
Process structure pointer of the child.
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:192
enum RadiotapType __attribute__
#define GNUNET_MESSAGE_TYPE_ARM_TEST
Test if ARM service is online.
Reply from ARM to client.
Definition: arm.h:87
#define GNUNET_MESSAGE_TYPE_ARM_MONITOR
Request to ARM to notify client of service status changes.
static char * hostname
Our hostname; we give this to all the peers we start.
static int monitor
Monitor ARM activity.
Definition: gnunet-arm.c:59
char * binary
Name of the binary used.
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:2248
static uint16_t port
Port number.
Definition: gnunet-bcd.c:79
configuration data
Definition: configuration.c:85
Service stopping was initiated.
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:373
struct GNUNET_NETWORK_Handle * listen_socket
Our listening socket.
#define LOG_STRERROR(kind, syscall)
void GNUNET_CONFIGURATION_iterate_sections(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Section_Iterator iter, void *iter_cls)
Iterate over all sections in the configuration.
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
The process is still running.
Asked to start or stop a service, but it&#39;s not known.
int 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.
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 ...
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:498
static int in_shutdown
Are we in shutdown mode?
handle to a socket
Definition: network.c:46
The process is not known to the OS (or at least not one of our children).
static struct GNUNET_SCHEDULER_Task * child_restart_task
ID of task called whenever the timeout for restarting a child expires.
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:331
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:157
static struct GNUNET_NotificationContext * notifier
Context for notifications we need to send to our clients.
Header for all communications.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:80
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:1478
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition: nc.c:141
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:353
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:201
char * name
Name of the service.
struct ServiceListeningInfo * next
This is a linked list.
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 check_start(void *cls, const struct GNUNET_ARM_Message *amsg)
Check START-message.
struct GNUNET_TIME_Absolute killed_at
Time we asked the service to shut down (used to calculate time it took the service to terminate)...
int 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.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:282
struct ServiceListeningInfo * listen_tail
Linked list of listen sockets associated with this service.
int 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".
Service was stopped (never sent for ARM itself).
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).
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:66
struct GNUNET_SERVICE_Client * killing_client
Client to notify upon kill completion (waitpid), NULL if we should simply restart the process...
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2533
static int global_ret
Return value from main.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:604
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
static int list
Set if we should print a list of currently running services.
Definition: gnunet-arm.c:64
#define GNUNET_malloc(size)
Wrapper around malloc.
The process is paused (but could be resumed).
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:48
static void do_shutdown()
We are done with everything.
void GNUNET_SERVICE_client_persist(struct GNUNET_SERVICE_Client *c)
Set the persist option on this client.
Definition: service.c:2721
#define GNUNET_free(ptr)
Wrapper around free.
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...
Time for relative time used by GNUnet, in microseconds.
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition: service.c:2679
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:1037
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:251
struct sockaddr * service_addr
Address this socket is listening on.
static int start_system
Are we starting system services?
static void accept_connection(void *cls)
First connection has come to the listening socket associated with the service, create the service in ...
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965