aboutsummaryrefslogtreecommitdiff
path: root/src/arm/gnunet-service-arm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm/gnunet-service-arm.c')
-rw-r--r--src/arm/gnunet-service-arm.c2227
1 files changed, 0 insertions, 2227 deletions
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
deleted file mode 100644
index b412094d3..000000000
--- a/src/arm/gnunet-service-arm.c
+++ /dev/null
@@ -1,2227 +0,0 @@
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
21/**
22 * @file arm/gnunet-service-arm.c
23 * @brief the automated restart manager service
24 * @author Christian Grothoff
25 */
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
39/**
40 * Name of the file for writing resource utilization summaries to.
41 */
42static char *wait_filename;
43
44/**
45 * Handle for the file for writing resource summaries.
46 */
47static FILE *wait_file;
48#endif
49
50
51/**
52 * How many messages do we queue up at most for optional
53 * notifications to a client? (this can cause notifications
54 * about outgoing messages to be dropped).
55 */
56#define MAX_NOTIFY_QUEUE 1024
57
58
59/**
60 * List of our services.
61 */
62struct ServiceList;
63
64
65/**
66 * Record with information about a listen socket we have open.
67 */
68struct ServiceListeningInfo
69{
70 /**
71 * This is a linked list.
72 */
73 struct ServiceListeningInfo *next;
74
75 /**
76 * This is a linked list.
77 */
78 struct ServiceListeningInfo *prev;
79
80 /**
81 * Address this socket is listening on.
82 */
83 struct sockaddr *service_addr;
84
85 /**
86 * Service this listen socket is for.
87 */
88 struct ServiceList *sl;
89
90 /**
91 * Number of bytes in @e service_addr
92 */
93 socklen_t service_addr_len;
94
95 /**
96 * Our listening socket.
97 */
98 struct GNUNET_NETWORK_Handle *listen_socket;
99
100 /**
101 * Task doing the accepting.
102 */
103 struct GNUNET_SCHEDULER_Task *accept_task;
104};
105
106
107/**
108 * List of our services.
109 */
110struct ServiceList
111{
112 /**
113 * This is a doubly-linked list.
114 */
115 struct ServiceList *next;
116
117 /**
118 * This is a doubly-linked list.
119 */
120 struct ServiceList *prev;
121
122 /**
123 * Linked list of listen sockets associated with this service.
124 */
125 struct ServiceListeningInfo *listen_head;
126
127 /**
128 * Linked list of listen sockets associated with this service.
129 */
130 struct ServiceListeningInfo *listen_tail;
131
132 /**
133 * Name of the service.
134 */
135 char *name;
136
137 /**
138 * Name of the binary used.
139 */
140 char *binary;
141
142 /**
143 * Name of the configuration file used.
144 */
145 char *config;
146
147 /**
148 * Client to notify upon kill completion (waitpid), NULL
149 * if we should simply restart the process.
150 */
151 struct GNUNET_SERVICE_Client *killing_client;
152
153 /**
154 * ID of the request that killed the service (for reporting back).
155 */
156 uint64_t killing_client_request_id;
157
158 /**
159 * Process structure pointer of the child.
160 */
161 struct GNUNET_OS_Process *proc;
162
163 /**
164 * Process exponential backoff time
165 */
166 struct GNUNET_TIME_Relative backoff;
167
168 /**
169 * Absolute time at which the process was (re-)started last.
170 */
171 struct GNUNET_TIME_Absolute last_started_at;
172
173 /**
174 * Absolute time at which the process is scheduled to restart in case of death
175 */
176 struct GNUNET_TIME_Absolute restart_at;
177
178 /**
179 * Time we asked the service to shut down (used to calculate time it took
180 * the service to terminate).
181 */
182 struct GNUNET_TIME_Absolute killed_at;
183
184 /**
185 * Is this service to be started by default (or did a client tell us explicitly
186 * to start it)? #GNUNET_NO if the service is started only upon 'accept' on a
187 * listen socket or possibly explicitly by a client changing the value.
188 */
189 int force_start;
190
191 /**
192 * Should we use pipes to signal this process? (YES for Java binaries and if we
193 * are on Windoze).
194 */
195 int pipe_control;
196
197 /**
198 * Last exit status of the process.
199 */
200 int last_exit_status;
201};
202
203/**
204 * List of running services.
205 */
206static struct ServiceList *running_head;
207
208/**
209 * List of running services.
210 */
211static struct ServiceList *running_tail;
212
213/**
214 * Our configuration
215 */
216static const struct GNUNET_CONFIGURATION_Handle *cfg;
217
218/**
219 * Command to prepend to each actual command.
220 */
221static char *prefix_command;
222
223/**
224 * Option to append to each actual command.
225 */
226static char *final_option;
227
228/**
229 * ID of task called whenever we get a SIGCHILD.
230 */
231static struct GNUNET_SCHEDULER_Task *child_death_task;
232
233/**
234 * ID of task called whenever the timeout for restarting a child
235 * expires.
236 */
237static struct GNUNET_SCHEDULER_Task *child_restart_task;
238
239/**
240 * Pipe used to communicate shutdown via signal.
241 */
242static struct GNUNET_DISK_PipeHandle *sigpipe;
243
244/**
245 * Are we in shutdown mode?
246 */
247static int in_shutdown;
248
249/**
250 * Return value from main
251 */
252static int global_ret;
253
254/**
255 * Are we starting user services?
256 */
257static int start_user = GNUNET_YES;
258
259/**
260 * Are we starting system services?
261 */
262static int start_system = GNUNET_YES;
263
264/**
265 * Handle to our service instance. Our service is a bit special in that
266 * its service is not immediately stopped once we get a shutdown
267 * request (since we need to continue service until all of our child
268 * processes are dead). This handle is used to shut down the service
269 * (and thus trigger process termination) once all child processes are
270 * also dead. A special option in the ARM configuration modifies the
271 * behaviour of the service implementation to not do the shutdown
272 * immediately.
273 */
274static struct GNUNET_SERVICE_Handle *service;
275
276/**
277 * Context for notifications we need to send to our clients.
278 */
279static struct GNUNET_NotificationContext *notifier;
280
281
282/**
283 * Add the given UNIX domain path as an address to the
284 * list (as the first entry).
285 *
286 * @param saddrs array to update
287 * @param saddrlens where to store the address length
288 * @param unixpath path to add
289 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
290 * parameter is ignore on systems other than LINUX
291 */
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
321/**
322 * Get the list of addresses that a server for the given service
323 * should bind to.
324 *
325 * @param service_name name of the service
326 * @param cfg configuration (which specifies the addresses)
327 * @param addrs set (call by reference) to an array of pointers to the
328 * addresses the server should bind to and listen on; the
329 * array will be NULL-terminated (on success)
330 * @param addr_lens set (call by reference) to an array of the lengths
331 * of the respective `struct sockaddr` struct in the @a addrs
332 * array (on success)
333 * @return number of addresses found on success,
334 * #GNUNET_SYSERR if the configuration
335 * did not specify reasonable finding information or
336 * if it specified a hostname that could not be resolved;
337 * #GNUNET_NO if the number of addresses configured is
338 * zero (in this case, `*addrs` and `*addr_lens` will be
339 * set to NULL).
340 */
341static int
342get_server_addresses (const char *service_name,
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;
366 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
367 {
368 if (GNUNET_SYSERR ==
369 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
370 service_name,
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 {
386 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
387 return GNUNET_SYSERR;
388 }
389 LOG (GNUNET_ERROR_TYPE_INFO,
390 _ (
391 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
392 service_name,
393 strerror (errno));
394 disablev6 = GNUNET_YES;
395 }
396 else
397 {
398 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
399 desc = NULL;
400 }
401 }
402
403 port = 0;
404 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
405 {
406 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
407 service_name,
408 "PORT",
409 &port))
410 {
411 LOG (GNUNET_ERROR_TYPE_ERROR,
412 _ ("Require valid port number for service `%s' in configuration!\n"),
413 service_name);
414 }
415 if (port > 65535)
416 {
417 LOG (GNUNET_ERROR_TYPE_ERROR,
418 _ ("Require valid port number for service `%s' in configuration!\n"),
419 service_name);
420 return GNUNET_SYSERR;
421 }
422 }
423
424 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
425 {
426 GNUNET_break (GNUNET_OK ==
427 GNUNET_CONFIGURATION_get_value_string (cfg,
428 service_name,
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 ==
439 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
440 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
441 service_name,
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 {
451 LOG (GNUNET_ERROR_TYPE_WARNING,
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__
459 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
460 "TESTING",
461 "USE_ABSTRACT_SOCKETS");
462 if (GNUNET_SYSERR == abstract)
463 abstract = GNUNET_NO;
464#endif
465 if ((GNUNET_YES != abstract) &&
466 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
467 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
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 {
477 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
478 GNUNET_free (hostname);
479 GNUNET_free (unixpath);
480 return GNUNET_SYSERR;
481 }
482 LOG (GNUNET_ERROR_TYPE_INFO,
483 _ (
484 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
485 service_name,
486 strerror (errno));
487 GNUNET_free (unixpath);
488 unixpath = NULL;
489 }
490 else
491 {
492 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
493 desc = NULL;
494 }
495 }
496#endif
497
498 if ((0 == port) && (NULL == unixpath))
499 {
500 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
501 service_name,
502 "START_ON_DEMAND"))
503 LOG (GNUNET_ERROR_TYPE_ERROR,
504 _ (
505 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
506 service_name);
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 {
524 LOG (GNUNET_ERROR_TYPE_DEBUG,
525 "Resolving `%s' since that is where `%s' will bind to.\n",
526 hostname,
527 service_name);
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 {
535 LOG (GNUNET_ERROR_TYPE_ERROR,
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 {
554 LOG (GNUNET_ERROR_TYPE_ERROR,
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? */
584 LOG (GNUNET_ERROR_TYPE_DEBUG,
585 "Service `%s' will bind to `%s'\n",
586 service_name,
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
674/**
675 * Signal our client that we will start or stop the
676 * service.
677 *
678 * @param client who is being signalled
679 * @param name name of the service
680 * @param request_id id of the request that is being responded to.
681 * @param result message type to send
682 * @return NULL if it was not found
683 */
684static void
685signal_result (struct GNUNET_SERVICE_Client *client,
686 const char *name,
687 uint64_t request_id,
688 enum GNUNET_ARM_Result result)
689{
690 struct GNUNET_MQ_Envelope *env;
691 struct GNUNET_ARM_ResultMessage *msg;
692
693 (void) name;
694 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_ARM_RESULT);
695 msg->result = htonl (result);
696 msg->arm_msg.request_id = GNUNET_htonll (request_id);
697 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
698}
699
700
701/**
702 * Tell all clients about status change of a service.
703 *
704 * @param name name of the service
705 * @param status message type to send
706 * @param unicast if not NULL, send to this client only.
707 * otherwise, send to all clients in the notifier
708 */
709static void
710broadcast_status (const char *name,
711 enum GNUNET_ARM_ServiceMonitorStatus status,
712 struct GNUNET_SERVICE_Client *unicast)
713{
714 struct GNUNET_MQ_Envelope *env;
715 struct GNUNET_ARM_StatusMessage *msg;
716 size_t namelen;
717
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719 "Sending status %u of service `%s' to client\n",
720 (unsigned int) status,
721 name);
722 namelen = strlen (name) + 1;
723 env = GNUNET_MQ_msg_extra (msg, namelen, GNUNET_MESSAGE_TYPE_ARM_STATUS);
724 msg->status = htonl ((uint32_t) (status));
725 GNUNET_memcpy ((char *) &msg[1], name, namelen);
726 if (NULL == unicast)
727 {
728 if (NULL != notifier)
729 GNUNET_notification_context_broadcast (notifier,
730 &msg->header,
731 GNUNET_YES);
732 GNUNET_MQ_discard (env);
733 }
734 else
735 {
736 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (unicast), env);
737 }
738}
739
740
741/**
742 * Actually start the process for the given service.
743 *
744 * @param sl identifies service to start
745 * @param client that asked to start the service (may be NULL)
746 * @param request_id id of the request in response to which the process is
747 * being started. 0 if starting was not requested.
748 */
749static void
750start_process (struct ServiceList *sl,
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,
771 GNUNET_NETWORK_get_fd (sli->listen_socket));
772 if (NULL != sli->accept_task)
773 {
774 GNUNET_SCHEDULER_cancel (sli->accept_task);
775 sli->accept_task = NULL;
776 }
777 }
778
779 GNUNET_array_append (lsocks, ls, -1);
780
781 /* obtain configuration */
782 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
783 sl->name,
784 "PREFIX",
785 &loprefix))
786 loprefix = GNUNET_strdup (prefix_command);
787 else
788 loprefix = GNUNET_CONFIGURATION_expand_dollar (cfg, loprefix);
789 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
790 sl->name,
791 "OPTIONS",
792 &options))
793 options = NULL;
794 else
795 options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
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 }
829 options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
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;
836 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_choice (cfg,
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);
853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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)
860 options = GNUNET_CONFIGURATION_expand_dollar (cfg, options);
861 sl->proc = GNUNET_OS_start_process_s (sl->pipe_control
862 ? GNUNET_OS_INHERIT_STD_OUT_AND_ERR
863 | GNUNET_OS_USE_PIPE_CONTROL
864 : GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
865 lsocks,
866 loprefix,
867 quotedbinary,
868 options,
869 NULL);
870 }
871 else
872 {
873 /* actually start process */
874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
875 "Starting service `%s' using binary `%s' and configuration `%s'\n",
876 sl->name,
877 sl->binary,
878 sl->config);
879 binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
880 GNUNET_asprintf (&quotedbinary, "\"%s\"", binary);
881
882 if (GNUNET_YES == use_debug)
883 {
884 if (NULL == sl->config)
885 sl->proc = GNUNET_OS_start_process_s (sl->pipe_control
886 ?
887 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
888 | GNUNET_OS_USE_PIPE_CONTROL
889 :
890 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
891 lsocks,
892 loprefix,
893 quotedbinary,
894 "-L",
895 "DEBUG",
896 options,
897 NULL);
898 else
899 sl->proc = GNUNET_OS_start_process_s (sl->pipe_control
900 ?
901 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
902 | GNUNET_OS_USE_PIPE_CONTROL
903 :
904 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
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)
918 sl->proc = GNUNET_OS_start_process_s (sl->pipe_control
919 ?
920 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
921 | GNUNET_OS_USE_PIPE_CONTROL
922 :
923 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
924 lsocks,
925 loprefix,
926 quotedbinary,
927 options,
928 NULL);
929 else
930 sl->proc = GNUNET_OS_start_process_s (sl->pipe_control
931 ?
932 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
933 | GNUNET_OS_USE_PIPE_CONTROL
934 :
935 GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
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);
947 sl->last_started_at = GNUNET_TIME_absolute_get ();
948 if (NULL == sl->proc)
949 {
950 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
951 _ ("Failed to start service `%s'\n"),
952 sl->name);
953 if (client)
954 signal_result (client,
955 sl->name,
956 request_id,
957 GNUNET_ARM_RESULT_START_FAILED);
958 }
959 else
960 {
961 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
962 _ ("Starting service `%s'\n"),
963 sl->name);
964 broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
965 if (client)
966 signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
967 }
968 /* clean up */
969 GNUNET_free (loprefix);
970 GNUNET_free (options);
971 GNUNET_array_grow (lsocks, ls, 0);
972}
973
974
975/**
976 * Find the process with the given service
977 * name in the given list and return it.
978 *
979 * @param name which service entry to look up
980 * @return NULL if it was not found
981 */
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
998/**
999 * First connection has come to the listening socket associated with the service,
1000 * create the service in order to relay the incoming connection to it
1001 *
1002 * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
1003 */
1004static void
1005accept_connection (void *cls)
1006{
1007 struct ServiceListeningInfo *sli = cls;
1008 struct ServiceList *sl = sli->sl;
1009
1010 sli->accept_task = NULL;
1011 GNUNET_assert (GNUNET_NO == in_shutdown);
1012 start_process (sl, NULL, 0);
1013}
1014
1015
1016/**
1017 * Creating a listening socket for each of the service's addresses and
1018 * wait for the first incoming connection to it
1019 *
1020 * @param sa address associated with the service
1021 * @param addr_len length of @a sa
1022 * @param sl service entry for the service in question
1023 */
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 {
1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1062 _ ("Unable to create socket for service `%s': %s\n"),
1063 sl->name,
1064 strerror (errno));
1065 GNUNET_free (sa);
1066 return;
1067 }
1068 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (sock,
1069 SOL_SOCKET,
1070 SO_REUSEADDR,
1071 &on,
1072 sizeof(on)))
1073 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1074 "setsockopt");
1075#ifdef IPV6_V6ONLY
1076 if ((sa->sa_family == AF_INET6) &&
1077 (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (sock,
1078 IPPROTO_IPV6,
1079 IPV6_V6ONLY,
1080 &on,
1081 sizeof(on))))
1082 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
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 (
1091 GNUNET_ERROR_TYPE_WARNING,
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));
1097 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
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 {
1118 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
1119 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1120 GNUNET_free (sa);
1121 return;
1122 }
1123 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
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 =
1133 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1134 sock,
1135 &accept_connection,
1136 sli);
1137 GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli);
1138}
1139
1140
1141/**
1142 * Remove and free an entry in the service list. Listen sockets
1143 * must have already been cleaned up. Only to be called during shutdown.
1144 *
1145 * @param sl entry to free
1146 */
1147static void
1148free_service (struct ServiceList *sl)
1149{
1150 GNUNET_assert (GNUNET_YES == in_shutdown);
1151 GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
1152 GNUNET_assert (NULL == sl->listen_head);
1153 GNUNET_free (sl->config);
1154 GNUNET_free (sl->binary);
1155 GNUNET_free (sl->name);
1156 GNUNET_free (sl);
1157}
1158
1159
1160/**
1161 * Check START-message.
1162 *
1163 * @param cls identification of the client
1164 * @param amsg the actual message
1165 * @return #GNUNET_OK to keep the connection open,
1166 * #GNUNET_SYSERR to close it (signal serious error)
1167 */
1168static int
1169check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
1170{
1171 (void) cls;
1172 GNUNET_MQ_check_zero_termination (amsg);
1173 return GNUNET_OK;
1174}
1175
1176
1177/**
1178 * Handle START-message.
1179 *
1180 * @param cls identification of the client
1181 * @param amsg the actual message
1182 */
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];
1193 GNUNET_SERVICE_client_continue (client);
1194 if (GNUNET_YES == in_shutdown)
1195 {
1196 signal_result (client,
1197 servicename,
1198 request_id,
1199 GNUNET_ARM_RESULT_IN_SHUTDOWN);
1200 return;
1201 }
1202 sl = find_service (servicename);
1203 if (NULL == sl)
1204 {
1205 signal_result (client,
1206 servicename,
1207 request_id,
1208 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
1209 return;
1210 }
1211 sl->force_start = GNUNET_YES;
1212 if (NULL != sl->proc)
1213 {
1214 signal_result (client,
1215 servicename,
1216 request_id,
1217 GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
1218 return;
1219 }
1220 start_process (sl, client, request_id);
1221}
1222
1223
1224/**
1225 * Start a shutdown sequence.
1226 *
1227 * @param cls closure (refers to service)
1228 */
1229static void
1230trigger_shutdown (void *cls)
1231{
1232 (void) cls;
1233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1234 GNUNET_SCHEDULER_shutdown ();
1235}
1236
1237
1238/**
1239 * Check STOP-message.
1240 *
1241 * @param cls identification of the client
1242 * @param amsg the actual message
1243 * @return #GNUNET_OK to keep the connection open,
1244 * #GNUNET_SYSERR to close it (signal serious error)
1245 */
1246static int
1247check_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
1248{
1249 (void) cls;
1250 GNUNET_MQ_check_zero_termination (amsg);
1251 return GNUNET_OK;
1252}
1253
1254
1255/**
1256 * Handle STOP-message.
1257 *
1258 * @param cls identification of the client
1259 * @param amsg the actual message
1260 */
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];
1271 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1272 _ ("Preparing to stop `%s'\n"),
1273 servicename);
1274 GNUNET_SERVICE_client_continue (client);
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);
1279 GNUNET_SERVICE_client_persist (client);
1280 GNUNET_SCHEDULER_add_now (&trigger_shutdown, NULL);
1281 return;
1282 }
1283 sl = find_service (servicename);
1284 if (NULL == sl)
1285 {
1286 signal_result (client,
1287 servicename,
1288 request_id,
1289 GNUNET_ARM_RESULT_IS_NOT_KNOWN);
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,
1299 GNUNET_ARM_RESULT_IN_SHUTDOWN);
1300 return;
1301 }
1302 if (NULL != sl->killing_client)
1303 {
1304 /* killing already in progress */
1305 signal_result (client,
1306 servicename,
1307 request_id,
1308 GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
1309 return;
1310 }
1311 if (NULL == sl->proc)
1312 {
1313 /* process is down */
1314 signal_result (client,
1315 servicename,
1316 request_id,
1317 GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
1318 return;
1319 }
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
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 */
1325 sl->killed_at = GNUNET_TIME_absolute_get ();
1326 if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
1327 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
1328 sl->killing_client = client;
1329 sl->killing_client_request_id = request_id;
1330}
1331
1332
1333/**
1334 * Write a string to a string pool.
1335 *
1336 * @param pool_start pointer to the start of the string pool
1337 * @param pool_size size of the string pool
1338 * @param[in,out] pool_pos current position index in the string pool,
1339 * will be updated
1340 * @param str string to write to the string pool
1341 * @returns GNUNET_OK if the string fits into the pool,
1342 * GNUNET_SYSERR otherwise
1343 */
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
1357/**
1358 * Handle LIST-message.
1359 *
1360 * @param cls identification of the client
1361 * @param message the actual message
1362 */
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;
1368 struct GNUNET_ARM_ListResultMessage *msg;
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;
1375 struct GNUNET_ARM_ServiceInfoMessage *ssm;
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
1391 GNUNET_ARM_ServiceInfoMessage));
1392 env = GNUNET_MQ_msg_extra (msg,
1393 extra_size,
1394 GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT);
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 */
1415 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_STOPPED);
1416 }
1417 else if (0 == sl->last_exit_status)
1418 {
1419 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_FINISHED);
1420 }
1421 else
1422 {
1423 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_FAILED);
1424 ssm->last_exit_status = htons (sl->last_exit_status);
1425 }
1426 }
1427 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1428 {
1429 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_STOPPING);
1430 }
1431 else
1432 {
1433 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_STARTED);
1434 }
1435 ssm->last_started_at = GNUNET_TIME_absolute_hton (sl->last_started_at);
1436 ssm->restart_at = GNUNET_TIME_absolute_hton (sl->restart_at);
1437 ssm++;
1438 }
1439 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1440 GNUNET_SERVICE_client_continue (client);
1441}
1442
1443
1444/**
1445 * Handle TEST-message by sending back TEST.
1446 *
1447 * @param cls identification of the client
1448 * @param message the actual message
1449 */
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;
1458 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_ARM_TEST);
1459 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1460 GNUNET_SERVICE_client_continue (client);
1461}
1462
1463
1464/**
1465 * We are done with everything. Stop remaining
1466 * tasks, signal handler and the server.
1467 */
1468static void
1469do_shutdown ()
1470{
1471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1472 if (NULL != notifier)
1473 {
1474 GNUNET_notification_context_destroy (notifier);
1475 notifier = NULL;
1476 }
1477 if (NULL != service)
1478 {
1479 GNUNET_SERVICE_shutdown (service);
1480 service = NULL;
1481 }
1482 if (NULL != child_death_task)
1483 {
1484 GNUNET_SCHEDULER_cancel (child_death_task);
1485 child_death_task = NULL;
1486 }
1487}
1488
1489
1490/**
1491 * Count how many services are still active.
1492 *
1493 * @param running_head list of services
1494 * @return number of active services found
1495 */
1496static unsigned int
1497list_count (struct ServiceList *running_head)
1498{
1499 struct ServiceList *i;
1500 unsigned int res;
1501
1502 for (res = 0, i = running_head; NULL != i; i = i->next, res++)
1503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", i->name);
1504 return res;
1505}
1506
1507
1508/**
1509 * Task run for shutdown.
1510 *
1511 * @param cls closure, NULL if we need to self-restart
1512 */
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 {
1524 GNUNET_SCHEDULER_cancel (child_restart_task);
1525 child_restart_task = NULL;
1526 }
1527 in_shutdown = GNUNET_YES;
1528 /* first, stop listening */
1529 for (pos = running_head; NULL != pos; pos = pos->next)
1530 {
1531 while (NULL != (sli = pos->listen_head))
1532 {
1533 GNUNET_CONTAINER_DLL_remove (pos->listen_head, pos->listen_tail, sli);
1534 if (NULL != sli->accept_task)
1535 {
1536 GNUNET_SCHEDULER_cancel (sli->accept_task);
1537 sli->accept_task = NULL;
1538 }
1539 GNUNET_break (GNUNET_OK ==
1540 GNUNET_NETWORK_socket_close (sli->listen_socket));
1541 GNUNET_free (sli->service_addr);
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);
1553 pos->killed_at = GNUNET_TIME_absolute_get ();
1554 if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
1555 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
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
1566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1567 "Delaying shutdown, have %u children still running\n",
1568 list_count (running_head));
1569}
1570
1571
1572/**
1573 * Task run whenever it is time to restart a child that died.
1574 *
1575 * @param cls closure, always NULL
1576 */
1577static void
1578delayed_restart_task (void *cls)
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;
1587 GNUNET_assert (GNUNET_NO == in_shutdown);
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 */
1597 if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
1598 {
1599 /* restart is now allowed */
1600 if (sl->force_start)
1601 {
1602 /* process should run by default, start immediately */
1603 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
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 =
1616 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1617 sli->listen_socket,
1618 &accept_connection,
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,
1628 GNUNET_TIME_absolute_get_remaining (
1629 sl->restart_at));
1630 }
1631 }
1632 if (lowestRestartDelay.rel_value_us !=
1633 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1634 {
1635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1636 "Will restart process in %s\n",
1637 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1638 GNUNET_YES));
1639 child_restart_task =
1640 GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
1641 GNUNET_SCHEDULER_PRIORITY_IDLE,
1642 &delayed_restart_task,
1643 NULL);
1644 }
1645}
1646
1647
1648/**
1649 * Task triggered whenever we receive a SIGCHLD (child
1650 * process died).
1651 *
1652 * @param cls closure, NULL
1653 */
1654static void
1655maint_child_death (void *cls)
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;
1669 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
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
1694 pid = GNUNET_OS_process_get_pid (pos->proc);
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
1745 if ((GNUNET_SYSERR == (ret = GNUNET_OS_process_status (pos->proc,
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 {
1770 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1771 _ ("Service `%s' took %s to terminate\n"),
1772 pos->name,
1773 GNUNET_STRINGS_relative_time_to_string (
1774 GNUNET_TIME_absolute_get_duration (pos->killed_at),
1775 GNUNET_YES));
1776 }
1777 GNUNET_OS_process_destroy (pos->proc);
1778 pos->proc = NULL;
1779 broadcast_status (pos->name, GNUNET_ARM_SERVICE_STOPPED, NULL);
1780 if (NULL != pos->killing_client)
1781 {
1782 signal_result (pos->killing_client,
1783 pos->name,
1784 pos->killing_client_request_id,
1785 GNUNET_ARM_RESULT_STOPPED);
1786 pos->killing_client = NULL;
1787 pos->killing_client_request_id = 0;
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 (
1797 GNUNET_ERROR_TYPE_INFO,
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 =
1805 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1806 sli->listen_socket,
1807 &accept_connection,
1808 sli);
1809 }
1810 }
1811 else
1812 {
1813 GNUNET_log (
1814 GNUNET_ERROR_TYPE_WARNING,
1815 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1816 pos->name,
1817 statstr,
1818 statcode,
1819 GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES));
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
1827 runtime = GNUNET_TIME_absolute_get_duration (pos->restart_at);
1828 minutes =
1829 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1830 if (minutes > 31)
1831 pos->backoff = GNUNET_TIME_UNIT_ZERO;
1832 else
1833 pos->backoff.rel_value_us <<= minutes;
1834 }
1835 /* schedule restart */
1836 pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
1837 pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
1838 if (NULL != child_restart_task)
1839 GNUNET_SCHEDULER_cancel (child_restart_task);
1840 child_restart_task =
1841 GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1842 &delayed_restart_task,
1843 NULL);
1844 }
1845 }
1846 else
1847 {
1848 free_service (pos);
1849 }
1850 }
1851 child_death_task =
1852 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1853 pr,
1854 &maint_child_death,
1855 NULL);
1856 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1857 do_shutdown ();
1858 else if (GNUNET_YES == in_shutdown)
1859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860 "Delaying shutdown after child's death, still have %u children\n",
1861 list_count (running_head));
1862}
1863
1864
1865/**
1866 * Signal handler called for SIGCHLD. Triggers the
1867 * respective handler by writing to the trigger pipe.
1868 */
1869static void
1870sighandler_child_death ()
1871{
1872 static char c;
1873 int old_errno = errno; /* back-up errno */
1874
1875 GNUNET_break (
1876 1 ==
1877 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
1878 GNUNET_DISK_PIPE_END_WRITE),
1879 &c,
1880 sizeof(c)));
1881 errno = old_errno; /* restore errno */
1882}
1883
1884
1885/**
1886 * Setup our service record for the given section in the configuration file
1887 * (assuming the section is for a service).
1888 *
1889 * @param cls unused
1890 * @param section a section in the configuration file
1891 * @return #GNUNET_OK (continue)
1892 */
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;
1941 if (((GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
1942 section,
1943 "CONFIG",
1944 &config)) &&
1945 (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
1946 "PATHS",
1947 "DEFAULTCONFIG",
1948 &config))) ||
1949 (0 != stat (config, &sbuf)))
1950 {
1951 if (NULL != config)
1952 {
1953 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1954 section,
1955 "CONFIG",
1956 strerror (errno));
1957 GNUNET_free (config);
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;
1965 sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
1966 sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
1967 if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
1968 sl->pipe_control =
1969 GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
1970 GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
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
1995/**
1996 * A client connected, mark as a monitoring client.
1997 *
1998 * @param cls closure
1999 * @param client identification of the client
2000 * @param mq queue to talk to @a client
2001 * @return @a client
2002 */
2003static void *
2004client_connect_cb (void *cls,
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;
2013 GNUNET_SERVICE_client_mark_monitor (client);
2014 return client;
2015}
2016
2017
2018/**
2019 * A client disconnected, clean up associated state.
2020 *
2021 * @param cls closure
2022 * @param client identification of the client
2023 * @param app_ctx must match @a client
2024 */
2025static void
2026client_disconnect_cb (void *cls,
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
2038/**
2039 * Handle MONITOR-message.
2040 *
2041 * @param cls identification of the client
2042 * @param message the actual message
2043 * @return #GNUNET_OK to keep the connection open,
2044 * #GNUNET_SYSERR to close it (signal serious error)
2045 */
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. */
2055 GNUNET_notification_context_add (notifier,
2056 GNUNET_SERVICE_client_get_mq (client));
2057 broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
2058 GNUNET_SERVICE_client_continue (client);
2059}
2060
2061
2062/**
2063 * Process arm requests.
2064 *
2065 * @param cls closure, NULL
2066 * @param serv the initialized service
2067 * @param c configuration to use
2068 */
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;
2079 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
2080 child_death_task = GNUNET_SCHEDULER_add_read_file (
2081 GNUNET_TIME_UNIT_FOREVER_REL,
2082 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
2083 &maint_child_death,
2084 NULL);
2085#if HAVE_WAIT4
2086 if (GNUNET_OK ==
2087 GNUNET_CONFIGURATION_get_value_filename (cfg,
2088 "ARM",
2089 "RESOURCE_DIAGNOSTICS",
2090 &wait_filename))
2091 {
2092 wait_file = fopen (wait_filename, "w");
2093 if (NULL == wait_file)
2094 {
2095 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
2096 "fopen",
2097 wait_filename);
2098 }
2099 }
2100#endif
2101 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
2102 "ARM",
2103 "GLOBAL_PREFIX",
2104 &prefix_command))
2105 prefix_command = GNUNET_strdup ("");
2106 else
2107 prefix_command = GNUNET_CONFIGURATION_expand_dollar (cfg, prefix_command);
2108 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
2109 "ARM",
2110 "GLOBAL_POSTFIX",
2111 &final_option))
2112 final_option = GNUNET_strdup ("");
2113 else
2114 final_option = GNUNET_CONFIGURATION_expand_dollar (cfg, final_option);
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 (
2122 GNUNET_ERROR_TYPE_ERROR,
2123 "Please configure either START_USER_SERVICES or START_SYSTEM_SERVICES or both.\n");
2124 GNUNET_SCHEDULER_shutdown ();
2125 global_ret = 1;
2126 return;
2127 }
2128 GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
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);
2134 notifier = GNUNET_notification_context_create (MAX_NOTIFY_QUEUE);
2135}
2136
2137
2138/**
2139 * The main function for the arm service.
2140 *
2141 * @param argc number of arguments from the command line
2142 * @param argv command line arguments
2143 * @return 0 ok, 1 on error
2144 */
2145int
2146main (int argc, char *const *argv)
2147{
2148 struct GNUNET_SIGNAL_Context *shc_chld;
2149 struct GNUNET_MQ_MessageHandler handlers[] = {
2150 GNUNET_MQ_hd_var_size (start,
2151 GNUNET_MESSAGE_TYPE_ARM_START,
2152 struct GNUNET_ARM_Message,
2153 NULL),
2154 GNUNET_MQ_hd_var_size (stop,
2155 GNUNET_MESSAGE_TYPE_ARM_STOP,
2156 struct GNUNET_ARM_Message,
2157 NULL),
2158 GNUNET_MQ_hd_fixed_size (monitor,
2159 GNUNET_MESSAGE_TYPE_ARM_MONITOR,
2160 struct GNUNET_MessageHeader,
2161 NULL),
2162 GNUNET_MQ_hd_fixed_size (list,
2163 GNUNET_MESSAGE_TYPE_ARM_LIST,
2164 struct GNUNET_ARM_Message,
2165 NULL),
2166 GNUNET_MQ_hd_fixed_size (test,
2167 GNUNET_MESSAGE_TYPE_ARM_TEST,
2168 struct GNUNET_MessageHeader,
2169 NULL),
2170 GNUNET_MQ_handler_end ()
2171 };
2172
2173 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
2174 GNUNET_assert (NULL != sigpipe);
2175 shc_chld =
2176 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
2177 &sighandler_child_death);
2178 if (0 != GNUNET_SERVICE_run_ (argc,
2179 argv,
2180 "arm",
2181 GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN
2182 | GNUNET_SERVICE_OPTION_CLOSE_LSOCKS,
2183 &run,
2184 &client_connect_cb,
2185 &client_disconnect_cb,
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
2201 GNUNET_SIGNAL_handler_uninstall (shc_chld);
2202 shc_chld = NULL;
2203 GNUNET_DISK_pipe_close (sigpipe);
2204 sigpipe = NULL;
2205 return global_ret;
2206}
2207
2208
2209#if defined(__linux__) && defined(__GLIBC__)
2210#include <malloc.h>
2211
2212/**
2213 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2214 */
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 */