GNUnet 0.22.1
gnunet-service-arm.c File Reference

the automated restart manager service More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_arm_service.h"
#include "gnunet_protocols.h"
#include "arm.h"
Include dependency graph for gnunet-service-arm.c:

Go to the source code of this file.

Data Structures

struct  ServiceListeningInfo
 Record with information about a listen socket we have open. More...
 
struct  ServiceList
 List of our services. More...
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "util", __VA_ARGS__)
 
#define LOG_STRERROR(kind, syscall)    GNUNET_log_from_strerror (kind, "util", syscall)
 
#define MAX_NOTIFY_QUEUE   1024
 How many messages do we queue up at most for optional notifications to a client? (this can cause notifications about outgoing messages to be dropped). More...
 

Functions

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). More...
 
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. More...
 
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. More...
 
static void broadcast_status (const char *name, enum GNUNET_ARM_ServiceMonitorStatus status, struct GNUNET_SERVICE_Client *unicast)
 Tell all clients about status change of a service. More...
 
static void start_process (struct ServiceList *sl, struct GNUNET_SERVICE_Client *client, uint64_t request_id)
 Actually start the process for the given service. More...
 
static struct ServiceListfind_service (const char *name)
 Find the process with the given service name in the given list and return it. More...
 
static void accept_connection (void *cls)
 First connection has come to the listening socket associated with the service, create the service in order to relay the incoming connection to it. More...
 
static void create_listen_socket (struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl)
 Creating a listening socket for each of the service's addresses and wait for the first incoming connection to it. More...
 
static void free_service (struct ServiceList *sl)
 Remove and free an entry in the service list. More...
 
static int check_start (void *cls, const struct GNUNET_ARM_Message *amsg)
 Check START-message. More...
 
static void handle_start (void *cls, const struct GNUNET_ARM_Message *amsg)
 Handle START-message. More...
 
static void trigger_shutdown (void *cls)
 Start a shutdown sequence. More...
 
static int check_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
 Check STOP-message. More...
 
static void handle_stop (void *cls, const struct GNUNET_ARM_Message *amsg)
 Handle STOP-message. More...
 
static int pool_write (char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
 Write a string to a string pool. More...
 
static void handle_list (void *cls, const struct GNUNET_ARM_Message *request)
 Handle LIST-message. More...
 
static void handle_test (void *cls, const struct GNUNET_MessageHeader *message)
 Handle TEST-message by sending back TEST. More...
 
static void do_shutdown ()
 We are done with everything. More...
 
static unsigned int list_count (struct ServiceList *run_head)
 Count how many services are still active. More...
 
static void shutdown_task (void *cls)
 Task run for shutdown. More...
 
static void delayed_restart_task (void *cls)
 Task run whenever it is time to restart a child that died. More...
 
static void maint_child_death (void *cls)
 Task triggered whenever we receive a SIGCHLD (child process died). More...
 
static void sighandler_child_death ()
 Signal handler called for SIGCHLD. More...
 
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 a service). More...
 
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. More...
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
 A client disconnected, clean up associated state. More...
 
static void handle_monitor (void *cls, const struct GNUNET_MessageHeader *message)
 Handle MONITOR-message. More...
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *serv)
 Process arm requests. More...
 
int main (int argc, char *const *argv)
 The main function for the arm service. More...
 

Variables

static struct ServiceListrunning_head
 List of running services. More...
 
static struct ServiceListrunning_tail
 List of running services. More...
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 Our configuration. More...
 
static char * prefix_command
 Command to prepend to each actual command. More...
 
static char * final_option
 Option to append to each actual command. More...
 
static struct GNUNET_SCHEDULER_Taskchild_death_task
 ID of task called whenever we get a SIGCHILD. More...
 
static struct GNUNET_SCHEDULER_Taskchild_restart_task
 ID of task called whenever the timeout for restarting a child expires. More...
 
static struct GNUNET_DISK_PipeHandlesigpipe
 Pipe used to communicate shutdown via signal. More...
 
static int in_shutdown
 Are we in shutdown mode? More...
 
static int global_ret
 Return value from main. More...
 
static int start_user = GNUNET_YES
 Are we starting user services? More...
 
static int start_system = GNUNET_YES
 Are we starting system services? More...
 
static struct GNUNET_SERVICE_Handleservice
 Handle to our service instance. More...
 
static struct GNUNET_NotificationContextnotifier
 Context for notifications we need to send to our clients. More...
 

Detailed Description

the automated restart manager service

Author
Christian Grothoff

Definition in file gnunet-service-arm.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "util", __VA_ARGS__)

Definition at line 32 of file gnunet-service-arm.c.

◆ LOG_STRERROR

#define LOG_STRERROR (   kind,
  syscall 
)     GNUNET_log_from_strerror (kind, "util", syscall)

Definition at line 34 of file gnunet-service-arm.c.

◆ MAX_NOTIFY_QUEUE

#define MAX_NOTIFY_QUEUE   1024

How many messages do we queue up at most for optional notifications to a client? (this can cause notifications about outgoing messages to be dropped).

Definition at line 56 of file gnunet-service-arm.c.

Function Documentation

◆ add_unixpath()

static void add_unixpath ( struct sockaddr **  saddrs,
socklen_t *  saddrlens,
const char *  unixpath,
int  abstract 
)
static

Add the given UNIX domain path as an address to the list (as the first entry).

Parameters
saddrsarray to update
saddrlenswhere to store the address length
unixpathpath to add
abstractGNUNET_YES to add an abstract UNIX domain socket. This parameter is ignore on systems other than LINUX

Definition at line 293 of file gnunet-service-arm.c.

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}
@ GNUNET_YES
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Definition: strings.c:137

References GNUNET_assert, GNUNET_new, GNUNET_strlcpy(), and GNUNET_YES.

Referenced by get_server_addresses().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_server_addresses()

static int get_server_addresses ( const char *  service_name,
const struct GNUNET_CONFIGURATION_Handle cfg_,
struct sockaddr ***  addrs,
socklen_t **  addr_lens 
)
static

Get the list of addresses that a server for the given service should bind to.

Parameters
service_namename of the service
cfgconfiguration (which specifies the addresses)
addrsset (call by reference) to an array of pointers to the addresses the server should bind to and listen on; the array will be NULL-terminated (on success)
addr_lensset (call by reference) to an array of the lengths of the respective struct sockaddr struct in the addrs array (on success)
Returns
number of addresses found on success, GNUNET_SYSERR if the configuration did not specify reasonable finding information or if it specified a hostname that could not be resolved; GNUNET_NO if the number of addresses configured is zero (in this case, *addrs and *addr_lens will be set to NULL).

Definition at line 342 of file gnunet-service-arm.c.

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 disablev6 = GNUNET_NO;
367 if (GNUNET_SYSERR ==
368 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg_,
370 "DISABLEV6")))
371 return GNUNET_SYSERR;
372 if (! disablev6)
373 {
374 /* probe IPv6 support */
375 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
376 if (NULL == desc)
377 {
378 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
379 (EACCES == errno))
380 {
382 return GNUNET_SYSERR;
383 }
385 _ (
386 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
388 strerror (errno));
389 disablev6 = GNUNET_YES;
390 }
391 else
392 {
394 }
395 }
396
397 port = 0;
399 {
400 if (GNUNET_OK !=
403 "PORT",
404 &port))
405 {
407 _ ("Require valid port number for service `%s' in configuration!\n"),
409 }
410 if (port > 65535)
411 {
413 _ ("Require valid port number for service `%s' in configuration!\n"),
415 return GNUNET_SYSERR;
416 }
417 }
418
419 hostname = NULL;
423 "BINDTO",
424 &hostname));
425 unixpath = NULL;
426 abstract = GNUNET_NO;
427#ifdef AF_UNIX
428 if ( (GNUNET_OK ==
431 "UNIXPATH",
432 &unixpath)) &&
433 (0 < strlen (unixpath)) )
434 {
435 /* probe UNIX support */
436 struct sockaddr_un s_un;
437
438 if (strlen (unixpath) >= sizeof(s_un.sun_path))
439 {
441 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
442 unixpath,
443 (unsigned long long) sizeof(s_un.sun_path));
444 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
445 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
446 }
447#ifdef __linux__
449 "TESTING",
450 "USE_ABSTRACT_SOCKETS");
451 if (GNUNET_SYSERR == abstract)
452 abstract = GNUNET_NO;
453#endif
454 if ((GNUNET_YES != abstract) &&
457 }
458 if (NULL != unixpath)
459 {
460 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
461 if (NULL == desc)
462 {
463 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
464 (EACCES == errno))
465 {
467 GNUNET_free (hostname);
468 GNUNET_free (unixpath);
469 return GNUNET_SYSERR;
470 }
472 _ (
473 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
475 strerror (errno));
476 GNUNET_free (unixpath);
477 unixpath = NULL;
478 }
479 else
480 {
482 desc = NULL;
483 }
484 }
485#endif
486
487 if ((0 == port) && (NULL == unixpath))
488 {
489 if (GNUNET_YES ==
492 "START_ON_DEMAND"))
494 _ (
495 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
497 GNUNET_free (hostname);
498 return GNUNET_SYSERR;
499 }
500 if (0 == port)
501 {
502 saddrs = GNUNET_new_array (2, struct sockaddr *);
503 saddrlens = GNUNET_new_array (2, socklen_t);
504 add_unixpath (saddrs, saddrlens, unixpath, abstract);
505 GNUNET_free (unixpath);
506 GNUNET_free (hostname);
507 *addrs = saddrs;
508 *addr_lens = saddrlens;
509 return 1;
510 }
511
512 if (NULL != hostname)
513 {
515 "Resolving `%s' since that is where `%s' will bind to.\n",
516 hostname,
518 memset (&hints, 0, sizeof(struct addrinfo));
519 if (disablev6)
520 hints.ai_family = AF_INET;
521 hints.ai_protocol = IPPROTO_TCP;
522 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
523 (NULL == res))
524 {
526 _ ("Failed to resolve `%s': %s\n"),
527 hostname,
528 gai_strerror (ret));
529 GNUNET_free (hostname);
530 GNUNET_free (unixpath);
531 return GNUNET_SYSERR;
532 }
533 next = res;
534 i = 0;
535 while (NULL != (pos = next))
536 {
537 next = pos->ai_next;
538 if ((disablev6) && (pos->ai_family == AF_INET6))
539 continue;
540 i++;
541 }
542 if (0 == i)
543 {
545 _ ("Failed to find %saddress for `%s'.\n"),
546 disablev6 ? "IPv4 " : "",
547 hostname);
548 freeaddrinfo (res);
549 GNUNET_free (hostname);
550 GNUNET_free (unixpath);
551 return GNUNET_SYSERR;
552 }
553 resi = i;
554 if (NULL != unixpath)
555 resi++;
556 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
557 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
558 i = 0;
559 if (NULL != unixpath)
560 {
561 add_unixpath (saddrs, saddrlens, unixpath, abstract);
562 i++;
563 }
564 next = res;
565 while (NULL != (pos = next))
566 {
567 next = pos->ai_next;
568 if ((disablev6) && (AF_INET6 == pos->ai_family))
569 continue;
570 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
571 continue; /* not TCP */
572 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
573 continue; /* huh? */
575 "Service `%s' will bind to `%s'\n",
577 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
578 if (AF_INET == pos->ai_family)
579 {
580 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
581 saddrlens[i] = pos->ai_addrlen;
582 saddrs[i] = GNUNET_malloc (saddrlens[i]);
583 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
584 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
585 }
586 else
587 {
588 GNUNET_assert (AF_INET6 == pos->ai_family);
589 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
590 saddrlens[i] = pos->ai_addrlen;
591 saddrs[i] = GNUNET_malloc (saddrlens[i]);
592 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
593 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
594 }
595 i++;
596 }
597 GNUNET_free (hostname);
598 freeaddrinfo (res);
599 resi = i;
600 }
601 else
602 {
603 /* will bind against everything, just set port */
604 if (disablev6)
605 {
606 /* V4-only */
607 resi = 1;
608 if (NULL != unixpath)
609 resi++;
610 i = 0;
611 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
612 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
613 if (NULL != unixpath)
614 {
615 add_unixpath (saddrs, saddrlens, unixpath, abstract);
616 i++;
617 }
618 saddrlens[i] = sizeof(struct sockaddr_in);
619 saddrs[i] = GNUNET_malloc (saddrlens[i]);
620#if HAVE_SOCKADDR_IN_SIN_LEN
621 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
622#endif
623 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
624 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
625 }
626 else
627 {
628 /* dual stack */
629 resi = 2;
630 if (NULL != unixpath)
631 resi++;
632 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
633 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
634 i = 0;
635 if (NULL != unixpath)
636 {
637 add_unixpath (saddrs, saddrlens, unixpath, abstract);
638 i++;
639 }
640 saddrlens[i] = sizeof(struct sockaddr_in6);
641 saddrs[i] = GNUNET_malloc (saddrlens[i]);
642#if HAVE_SOCKADDR_IN_SIN_LEN
643 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
644#endif
645 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
646 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
647 i++;
648 saddrlens[i] = sizeof(struct sockaddr_in);
649 saddrs[i] = GNUNET_malloc (saddrlens[i]);
650#if HAVE_SOCKADDR_IN_SIN_LEN
651 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
652#endif
653 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
654 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
655 }
656 }
657 GNUNET_free (unixpath);
658 *addrs = saddrs;
659 *addr_lens = saddrlens;
660 return resi;
661}
static int ret
Final status code.
Definition: gnunet-arm.c:93
static uint16_t port
Port number.
Definition: gnunet-bcd.c:146
static char * res
Currently read line or NULL on EOF.
static void add_unixpath(struct sockaddr **saddrs, socklen_t *saddrlens, const char *unixpath, int abstract)
Add the given UNIX domain path as an address to the list (as the first entry).
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
#define LOG(kind,...)
#define LOG_STRERROR(kind, syscall)
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition: gnunet-vpn.c:50
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition: disk.c:583
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:508
char * GNUNET_NETWORK_shorten_unixpath(char *unixpath)
Given a unixpath that is too long (larger than UNIX_PATH_MAX), shorten it to an acceptable length whi...
Definition: network.c:143
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:833
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
handle to a socket
Definition: network.c:53

References _, add_unixpath(), cfg, GNUNET_a2s(), GNUNET_assert, GNUNET_break, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_number(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONFIGURATION_have_value(), GNUNET_DISK_directory_create_for_file(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log_strerror_file, GNUNET_malloc, GNUNET_memcpy, GNUNET_NETWORK_shorten_unixpath(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_new_array, GNUNET_NO, GNUNET_OK, GNUNET_SYSERR, GNUNET_YES, LOG, LOG_STRERROR, port, res, ret, and service_name.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ signal_result()

static void signal_result ( struct GNUNET_SERVICE_Client client,
const char *  name,
uint64_t  request_id,
enum GNUNET_ARM_Result  result 
)
static

Signal our client that we will start or stop the service.

Parameters
clientwho is being signalled
namename of the service
request_idid of the request that is being responded to.
resultmessage type to send
Returns
NULL if it was not found

Definition at line 675 of file gnunet-service-arm.c.

679{
680 struct GNUNET_MQ_Envelope *env;
682
683 (void) name;
685 msg->result = htonl (result);
686 msg->arm_msg.request_id = GNUNET_htonll (request_id);
688}
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static char * name
Name (label) of the records to list.
static int result
Global testing status.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:37
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:305
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:78
#define GNUNET_MESSAGE_TYPE_ARM_RESULT
Response from ARM.
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition: service.c:2459
Reply from ARM to client.
Definition: arm.h:87

References env, GNUNET_htonll(), GNUNET_MESSAGE_TYPE_ARM_RESULT, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_SERVICE_client_get_mq(), msg, name, and result.

Referenced by handle_start(), handle_stop(), maint_child_death(), and start_process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ broadcast_status()

static void broadcast_status ( const char *  name,
enum GNUNET_ARM_ServiceMonitorStatus  status,
struct GNUNET_SERVICE_Client unicast 
)
static

Tell all clients about status change of a service.

Parameters
namename of the service
statusmessage type to send
unicastif not NULL, send to this client only. otherwise, send to all clients in the notifier

Definition at line 700 of file gnunet-service-arm.c.

703{
704 struct GNUNET_MQ_Envelope *env;
706 size_t namelen;
707
709 "Sending status %u of service `%s' to client\n",
710 (unsigned int) status,
711 name);
712 namelen = strlen (name) + 1;
714 namelen,
716 msg->status = htonl ((uint32_t) (status));
717 GNUNET_memcpy ((char *) &msg[1],
718 name,
719 namelen);
720 if (NULL == unicast)
721 {
722 if (NULL != notifier)
724 &msg->header,
725 GNUNET_YES);
727 }
728 else
729 {
731 env);
732 }
733}
static int status
The program status; 0 for success.
Definition: gnunet-nse.c:39
static struct GNUNET_NotificationContext * notifier
Context for notifications we need to send to our clients.
#define GNUNET_log(kind,...)
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition: mq.c:285
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
Definition: gnunet_mq_lib.h:63
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition: nc.c:190
#define GNUNET_MESSAGE_TYPE_ARM_STATUS
Status update from ARM.
Status update from ARM to client.
Definition: arm.h:42

References env, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_ARM_STATUS, GNUNET_MQ_discard(), GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_notification_context_broadcast(), GNUNET_SERVICE_client_get_mq(), GNUNET_YES, msg, name, notifier, and status.

Referenced by handle_monitor(), handle_stop(), maint_child_death(), and start_process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_process()

static void start_process ( struct ServiceList sl,
struct GNUNET_SERVICE_Client client,
uint64_t  request_id 
)
static

Actually start the process for the given service.

Parameters
slidentifies service to start
clientthat asked to start the service (may be NULL)
request_idid of the request in response to which the process is being started. 0 if starting was not requested.

Definition at line 745 of file gnunet-service-arm.c.

748{
749 char *loprefix;
750 char *options;
751 enum GNUNET_GenericReturnValue use_debug;
752 bool is_simple_service;
753 int *lsocks;
754 unsigned int ls;
755 char *binary;
756 char *quotedbinary;
757
758 /* calculate listen socket list */
759 lsocks = NULL;
760 ls = 0;
761 for (struct ServiceListeningInfo *sli = sl->listen_head;
762 NULL != sli;
763 sli = sli->next)
764 {
765 GNUNET_array_append (lsocks,
766 ls,
767 GNUNET_NETWORK_get_fd (sli->listen_socket));
768 if (NULL != sli->accept_task)
769 {
770 GNUNET_SCHEDULER_cancel (sli->accept_task);
771 sli->accept_task = NULL;
772 }
773 }
774
775 GNUNET_array_append (lsocks,
776 ls,
777 -1);
778
779 /* obtain configuration */
780 if (GNUNET_OK !=
782 sl->name,
783 "PREFIX",
784 &loprefix))
785 loprefix = GNUNET_strdup (prefix_command);
786 else
788 loprefix);
789 if (GNUNET_OK !=
791 sl->name,
792 "OPTIONS",
793 &options))
794 options = NULL;
795 else
797 {
798 char *new_options;
799 char *optpos;
800 char *fin_options;
801
802 fin_options = GNUNET_strdup (final_option);
803 /* replace '{}' with service name */
804 while (NULL != (optpos = strstr (fin_options, "{}")))
805 {
806 /* terminate string at opening parenthesis */
807 *optpos = 0;
808 GNUNET_asprintf (&new_options,
809 "%s%s%s",
810 fin_options,
811 sl->name,
812 optpos + 2);
813 GNUNET_free (fin_options);
814 fin_options = new_options;
815 }
816 if (NULL != options)
817 {
818 /* combine "fin_options" with "options" */
819 optpos = options;
820 GNUNET_asprintf (&options, "%s %s", fin_options, optpos);
821 GNUNET_free (fin_options);
822 GNUNET_free (optpos);
823 }
824 else
825 {
826 /* only have "fin_options", use that */
827 options = fin_options;
828 }
829 }
831 options);
833 sl->name,
834 "DEBUG");
835 {
836 const char *service_type = NULL;
837 const char *choices[] = {
838 "GNUNET",
839 "SIMPLE",
840 NULL
841 };
842
843 is_simple_service = false;
844 if ( (GNUNET_OK ==
846 sl->name,
847 "TYPE",
848 choices,
849 &service_type)) &&
850 (0 == strcasecmp (service_type,
851 "SIMPLE")))
852 is_simple_service = true;
853 }
854
855 GNUNET_assert (NULL == sl->proc);
856 if (is_simple_service)
857 {
858 /* A simple service will receive no GNUnet specific
859 command line options. */
860 binary = GNUNET_strdup (sl->binary);
862 binary);
863 GNUNET_asprintf (&quotedbinary,
864 "\"%s\"",
865 sl->binary);
867 "Starting simple service `%s' using binary `%s'\n",
868 sl->name,
869 sl->binary);
870 /* FIXME: dollar expansion should only be done outside
871 * of ''-quoted strings, escaping should be considered. */
872 if (NULL != options)
874 options);
879 lsocks,
880 loprefix,
881 quotedbinary,
882 options,
883 NULL);
884 }
885 else
886 {
887 /* actually start process */
889 "Starting service `%s' using binary `%s' and configuration `%s'\n",
890 sl->name,
891 sl->binary,
892 sl->config);
894 GNUNET_asprintf (&quotedbinary,
895 "\"%s\"",
896 binary);
897
898 if (GNUNET_YES == use_debug)
899 {
900 if (NULL == sl->config)
902 sl->pipe_control
906 lsocks,
907 loprefix,
908 quotedbinary,
909 "-L",
910 "DEBUG",
911 options,
912 NULL);
913 else
915 sl->pipe_control
919 lsocks,
920 loprefix,
921 quotedbinary,
922 "-c",
923 sl->config,
924 "-L",
925 "DEBUG",
926 options,
927 NULL);
928 }
929 else
930 {
931 if (NULL == sl->config)
933 sl->pipe_control
937 lsocks,
938 loprefix,
939 quotedbinary,
940 options,
941 NULL);
942 else
944 sl->pipe_control
948 lsocks,
949 loprefix,
950 quotedbinary,
951 "-c",
952 sl->config,
953 options,
954 NULL);
955 }
956 }
957 GNUNET_free (binary);
958 GNUNET_free (quotedbinary);
960 if (NULL == sl->proc)
961 {
963 "Failed to start service `%s'\n",
964 sl->name);
965 if (client)
966 signal_result (client,
967 sl->name,
968 request_id,
970 }
971 else
972 {
974 "Starting service `%s'\n",
975 sl->name);
978 NULL);
979 if (client)
980 signal_result (client,
981 sl->name,
982 request_id,
984 }
985 /* clean up */
986 GNUNET_free (loprefix);
988 GNUNET_array_grow (lsocks,
989 ls,
990 0);
991}
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
static void broadcast_status(const char *name, enum GNUNET_ARM_ServiceMonitorStatus status, struct GNUNET_SERVICE_Client *unicast)
Tell all clients about status change of a service.
static char * prefix_command
Command to prepend to each actual command.
static char * final_option
Option to append to each actual command.
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.
@ GNUNET_ARM_SERVICE_STARTING
Service starting was initiated.
@ GNUNET_ARM_RESULT_STARTING
Service starting was initiated.
@ GNUNET_ARM_RESULT_START_FAILED
Tried to start a service, but that failed for some reason.
char * GNUNET_CONFIGURATION_expand_dollar(const struct GNUNET_CONFIGURATION_Handle *cfg, char *orig)
Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" where either in the "PATHS" section or...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_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.
GNUNET_GenericReturnValue
Named constants for return values.
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1001
char * GNUNET_OS_get_libexec_binary_path(const char *progname)
Given the name of a gnunet-helper, gnunet-service or gnunet-daemon binary, try to prefix it with the ...
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename,...)
Start a process.
Definition: os_priority.c:666
@ GNUNET_OS_INHERIT_STD_OUT_AND_ERR
When these flags are set, the child process will inherit stdout and stderr of the parent.
@ GNUNET_OS_USE_PIPE_CONTROL
Should a pipe be used to send signals to the child?
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:979
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
struct ServiceListeningInfo * listen_head
Linked list of listen sockets associated with this service.
char * binary
Name of the binary used.
int pipe_control
Should we use pipes to signal this process? (YES for Java binaries and if we are on Windoze).
char * config
Name of the configuration file used.
struct GNUNET_TIME_Absolute last_started_at
Absolute time at which the process was (re-)started last.
struct GNUNET_OS_Process * proc
Process structure pointer of the child.
char * name
Name of the service.
Record with information about a listen socket we have open.
struct ServiceListeningInfo * next
This is a linked list.

References ServiceList::binary, broadcast_status(), cfg, warningfilter::choices, ServiceList::config, final_option, GNUNET_ARM_RESULT_START_FAILED, GNUNET_ARM_RESULT_STARTING, GNUNET_ARM_SERVICE_STARTING, GNUNET_array_append, GNUNET_array_grow, GNUNET_asprintf(), GNUNET_assert, GNUNET_CONFIGURATION_expand_dollar(), GNUNET_CONFIGURATION_get_value_choice(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_log, GNUNET_NETWORK_get_fd(), GNUNET_OK, GNUNET_OS_get_libexec_binary_path(), GNUNET_OS_INHERIT_STD_OUT_AND_ERR, GNUNET_OS_start_process_s(), GNUNET_OS_USE_PIPE_CONTROL, GNUNET_SCHEDULER_cancel(), GNUNET_strdup, GNUNET_TIME_absolute_get(), GNUNET_YES, ServiceList::last_started_at, ServiceList::listen_head, ls, ServiceList::name, ServiceListeningInfo::next, options, ServiceList::pipe_control, prefix_command, ServiceList::proc, and signal_result().

Referenced by accept_connection(), delayed_restart_task(), handle_start(), and run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_service()

static struct ServiceList * find_service ( const char *  name)
static

Find the process with the given service name in the given list and return it.

Parameters
namewhich service entry to look up
Returns
NULL if it was not found

Definition at line 1002 of file gnunet-service-arm.c.

1003{
1004 struct ServiceList *sl;
1005
1006 sl = running_head;
1007 while (sl != NULL)
1008 {
1009 if (0 == strcasecmp (sl->name, name))
1010 return sl;
1011 sl = sl->next;
1012 }
1013 return NULL;
1014}
static struct ServiceList * running_head
List of running services.
List of our services.
struct ServiceList * next
This is a doubly-linked list.

References name, ServiceList::name, ServiceList::next, and running_head.

Referenced by handle_start(), handle_stop(), and setup_service().

Here is the caller graph for this function:

◆ accept_connection()

static void accept_connection ( void *  cls)
static

First connection has come to the listening socket associated with the service, create the service in order to relay the incoming connection to it.

Parameters
clscallback data, struct ServiceListeningInfo describing a listen socket

Definition at line 1024 of file gnunet-service-arm.c.

1025{
1026 struct ServiceListeningInfo *sli = cls;
1027 struct ServiceList *sl = sli->sl;
1028
1029 sli->accept_task = NULL;
1031 start_process (sl, NULL, 0);
1032}
static void start_process(struct ServiceList *sl, struct GNUNET_SERVICE_Client *client, uint64_t request_id)
Actually start the process for the given service.
static int in_shutdown
Are we in shutdown mode?
struct ServiceList * sl
Service this listen socket is for.
struct GNUNET_SCHEDULER_Task * accept_task
Task doing the accepting.

References ServiceListeningInfo::accept_task, GNUNET_assert, GNUNET_NO, in_shutdown, ServiceListeningInfo::sl, and start_process().

Referenced by create_listen_socket(), delayed_restart_task(), and maint_child_death().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_listen_socket()

static void create_listen_socket ( struct sockaddr *  sa,
socklen_t  addr_len,
struct ServiceList sl 
)
static

Creating a listening socket for each of the service's addresses and wait for the first incoming connection to it.

Parameters
saaddress associated with the service
addr_lenlength of sa
slservice entry for the service in question

Definition at line 1044 of file gnunet-service-arm.c.

1047{
1048 static int on = 1;
1049 struct GNUNET_NETWORK_Handle *sock;
1050 struct ServiceListeningInfo *sli;
1051
1052 int match_uid;
1053 int match_gid;
1054
1055 switch (sa->sa_family)
1056 {
1057 case AF_INET:
1058 sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
1059 break;
1060
1061 case AF_INET6:
1062 sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1063 break;
1064
1065 case AF_UNIX:
1066 if (0 == strcmp (GNUNET_a2s (sa, addr_len),
1067 "@")) /* Do not bind to blank UNIX path! */
1068 return;
1069 sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
1070 break;
1071
1072 default:
1073 GNUNET_break (0);
1074 sock = NULL;
1075 errno = EAFNOSUPPORT;
1076 break;
1077 }
1078 if (NULL == sock)
1079 {
1081 _ ("Unable to create socket for service `%s': %s\n"),
1082 sl->name,
1083 strerror (errno));
1084 GNUNET_free (sa);
1085 return;
1086 }
1088 SOL_SOCKET,
1089 SO_REUSEADDR,
1090 &on,
1091 sizeof(on)))
1093 "setsockopt");
1094#ifdef IPV6_V6ONLY
1095 if ((sa->sa_family == AF_INET6) &&
1097 IPPROTO_IPV6,
1098 IPV6_V6ONLY,
1099 &on,
1100 sizeof(on))))
1102 "setsockopt");
1103#endif
1104 if (AF_UNIX == sa->sa_family)
1105 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
1106 if (GNUNET_OK !=
1107 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
1108 {
1109 GNUNET_log (
1111 _ (
1112 "Unable to bind listening socket for service `%s' to address `%s': %s\n"),
1113 sl->name,
1114 GNUNET_a2s (sa, addr_len),
1115 strerror (errno));
1117 GNUNET_free (sa);
1118 return;
1119 }
1120 if ((AF_UNIX == sa->sa_family)
1121#ifdef __linux__
1122 /* Permission settings are not required when abstract sockets are used */
1123 && ('\0' != ((const struct sockaddr_un *) sa)->sun_path[0])
1124#endif
1125 )
1126 {
1127 match_uid =
1128 (GNUNET_YES ==
1130 sl->name,
1131 "UNIX_MATCH_UID"));
1132 match_gid =
1133 (GNUNET_YES ==
1135 sl->name,
1136 "UNIX_MATCH_GID"));
1137 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *) sa)->sun_path,
1138 match_uid,
1139 match_gid);
1140 }
1141 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1142 {
1145 GNUNET_free (sa);
1146 return;
1147 }
1149 _ ("ARM now monitors connections to service `%s' at `%s'\n"),
1150 sl->name,
1151 GNUNET_a2s (sa, addr_len));
1152 sli = GNUNET_new (struct ServiceListeningInfo);
1153 sli->service_addr = sa;
1154 sli->service_addr_len = addr_len;
1155 sli->listen_socket = sock;
1156 sli->sl = sl;
1157 sli->accept_task =
1159 sock,
1161 sli);
1163}
static void accept_connection(void *cls)
First connection has come to the listening socket associated with the service, create the service in ...
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:321
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_BULK
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:439
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:652
void GNUNET_NETWORK_unix_precheck(const struct sockaddr_un *un)
If services crash, they can leave a unix domain socket file on the disk.
Definition: network.c:178
int GNUNET_NETWORK_socket_setsockopt(struct GNUNET_NETWORK_Handle *fd, int level, int option_name, const void *option_value, socklen_t option_len)
Set socket option.
Definition: network.c:806
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:1510
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct ServiceListeningInfo * listen_tail
Linked list of listen sockets associated with this service.
struct sockaddr * service_addr
Address this socket is listening on.
socklen_t service_addr_len
Number of bytes in service_addr.
struct GNUNET_NETWORK_Handle * listen_socket
Our listening socket.

References _, accept_connection(), ServiceListeningInfo::accept_task, cfg, GNUNET_a2s(), GNUNET_break, GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONTAINER_DLL_insert, GNUNET_DISK_fix_permissions(), GNUNET_ERROR_TYPE_BULK, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_log_strerror, GNUNET_NETWORK_socket_bind(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_NETWORK_socket_listen(), GNUNET_NETWORK_socket_setsockopt(), GNUNET_NETWORK_unix_precheck(), GNUNET_new, GNUNET_OK, GNUNET_SCHEDULER_add_read_net(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, ServiceList::listen_head, ServiceListeningInfo::listen_socket, ServiceList::listen_tail, ServiceList::name, ServiceListeningInfo::service_addr, ServiceListeningInfo::service_addr_len, and ServiceListeningInfo::sl.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_service()

static void free_service ( struct ServiceList sl)
static

Remove and free an entry in the service list.

Listen sockets must have already been cleaned up. Only to be called during shutdown.

Parameters
slentry to free

Definition at line 1173 of file gnunet-service-arm.c.

1174{
1177 GNUNET_assert (NULL == sl->listen_head);
1178 GNUNET_free (sl->config);
1179 GNUNET_free (sl->binary);
1180 GNUNET_free (sl->name);
1181 GNUNET_free (sl);
1182}
static struct ServiceList * running_tail
List of running services.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.

References ServiceList::binary, ServiceList::config, GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_YES, in_shutdown, ServiceList::listen_head, ServiceList::name, running_head, running_tail, and ServiceListeningInfo::sl.

Referenced by maint_child_death(), and shutdown_task().

Here is the caller graph for this function:

◆ check_start()

static int check_start ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Check START-message.

Parameters
clsidentification of the client
amsgthe actual message
Returns
GNUNET_OK to keep the connection open, GNUNET_SYSERR to close it (signal serious error)

Definition at line 1194 of file gnunet-service-arm.c.

1195{
1196 (void) cls;
1198 return GNUNET_OK;
1199}
#define GNUNET_MQ_check_zero_termination(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...

References GNUNET_MQ_check_zero_termination, and GNUNET_OK.

◆ handle_start()

static void handle_start ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Handle START-message.

Parameters
clsidentification of the client
amsgthe actual message

Definition at line 1209 of file gnunet-service-arm.c.

1210{
1211 struct GNUNET_SERVICE_Client *client = cls;
1212 const char *servicename;
1213 struct ServiceList *sl;
1214 uint64_t request_id;
1215
1216 request_id = GNUNET_ntohll (amsg->request_id);
1217 servicename = (const char *) &amsg[1];
1219 if (GNUNET_YES == in_shutdown)
1220 {
1221 signal_result (client,
1222 servicename,
1223 request_id,
1225 return;
1226 }
1227 sl = find_service (servicename);
1228 if (NULL == sl)
1229 {
1230 signal_result (client,
1231 servicename,
1232 request_id,
1234 return;
1235 }
1236 sl->force_start = GNUNET_YES;
1237 if (NULL != sl->proc)
1238 {
1239 signal_result (client,
1240 servicename,
1241 request_id,
1243 return;
1244 }
1245 start_process (sl, client, request_id);
1246}
static struct ServiceList * find_service(const char *name)
Find the process with the given service name in the given list and return it.
@ GNUNET_ARM_RESULT_IS_NOT_KNOWN
Asked to start or stop a service, but it's not known.
@ GNUNET_ARM_RESULT_IS_STARTED_ALREADY
Asked to start it, but it's already started.
@ GNUNET_ARM_RESULT_IN_SHUTDOWN
Asked to start something, but ARM is shutting down and can't comply.
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:54
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2348
uint64_t request_id
ID of a request that is being replied to.
Definition: arm.h:77
Handle to a client that is connected to a service.
Definition: service.c:245
int force_start
Is this service to be started by default (or did a client tell us explicitly to start it)?...

References find_service(), ServiceList::force_start, GNUNET_ARM_RESULT_IN_SHUTDOWN, GNUNET_ARM_RESULT_IS_NOT_KNOWN, GNUNET_ARM_RESULT_IS_STARTED_ALREADY, GNUNET_ntohll(), GNUNET_SERVICE_client_continue(), GNUNET_YES, in_shutdown, ServiceList::proc, GNUNET_ARM_Message::request_id, signal_result(), and start_process().

Here is the call graph for this function:

◆ trigger_shutdown()

static void trigger_shutdown ( void *  cls)
static

Start a shutdown sequence.

Parameters
clsclosure (refers to service)

Definition at line 1255 of file gnunet-service-arm.c.

1256{
1257 (void) cls;
1258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
1260}
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:566

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, and GNUNET_SCHEDULER_shutdown().

Referenced by handle_stop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_stop()

static int check_stop ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Check STOP-message.

Parameters
clsidentification of the client
amsgthe actual message
Returns
GNUNET_OK to keep the connection open, GNUNET_SYSERR to close it (signal serious error)

Definition at line 1272 of file gnunet-service-arm.c.

1273{
1274 (void) cls;
1276 return GNUNET_OK;
1277}

References GNUNET_MQ_check_zero_termination, and GNUNET_OK.

◆ handle_stop()

static void handle_stop ( void *  cls,
const struct GNUNET_ARM_Message amsg 
)
static

Handle STOP-message.

Parameters
clsidentification of the client
amsgthe actual message

Definition at line 1287 of file gnunet-service-arm.c.

1288{
1289 struct GNUNET_SERVICE_Client *client = cls;
1290 struct ServiceList *sl;
1291 const char *servicename;
1292 uint64_t request_id;
1293
1294 request_id = GNUNET_ntohll (amsg->request_id);
1295 servicename = (const char *) &amsg[1];
1297 _ ("Preparing to stop `%s'\n"),
1298 servicename);
1300 if (0 == strcasecmp (servicename, "arm"))
1301 {
1302 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1303 signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING);
1306 return;
1307 }
1308 sl = find_service (servicename);
1309 if (NULL == sl)
1310 {
1311 signal_result (client,
1312 servicename,
1313 request_id,
1315 return;
1316 }
1317 sl->force_start = GNUNET_NO;
1318 if (GNUNET_YES == in_shutdown)
1319 {
1320 /* shutdown in progress */
1321 signal_result (client,
1322 servicename,
1323 request_id,
1325 return;
1326 }
1327 if (NULL != sl->killing_client)
1328 {
1329 /* killing already in progress */
1330 signal_result (client,
1331 servicename,
1332 request_id,
1334 return;
1335 }
1336 if (NULL == sl->proc)
1337 {
1338 /* process is down */
1339 signal_result (client,
1340 servicename,
1341 request_id,
1343 return;
1344 }
1346 "Sending kill signal to service `%s', waiting for process to die.\n",
1347 servicename);
1348 broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
1349 /* no signal_start - only when it's STOPPED */
1353 sl->killing_client = client;
1354 sl->killing_client_request_id = request_id;
1355}
static void trigger_shutdown(void *cls)
Start a shutdown sequence.
@ GNUNET_ARM_SERVICE_STOPPING
Service stopping was initiated.
@ GNUNET_ARM_RESULT_IS_STOPPED_ALREADY
Asked to stop it, but it's already stopped.
@ GNUNET_ARM_RESULT_STOPPING
ARM stopping was initiated (there's no "stopped" for ARM itself).
@ GNUNET_ARM_RESULT_IS_STOPPING_ALREADY
Asked to stop it, but it's already stopping.
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:210
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:1303
void GNUNET_SERVICE_client_persist(struct GNUNET_SERVICE_Client *c)
Set the persist option on this client.
Definition: service.c:2452
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:234
struct GNUNET_SERVICE_Client * killing_client
Client to notify upon kill completion (waitpid), NULL if we should simply restart the process.
struct GNUNET_TIME_Absolute killed_at
Time we asked the service to shut down (used to calculate time it took the service to terminate).
uint64_t killing_client_request_id
ID of the request that killed the service (for reporting back).

References _, broadcast_status(), find_service(), ServiceList::force_start, GNUNET_ARM_RESULT_IN_SHUTDOWN, GNUNET_ARM_RESULT_IS_NOT_KNOWN, GNUNET_ARM_RESULT_IS_STOPPED_ALREADY, GNUNET_ARM_RESULT_IS_STOPPING_ALREADY, GNUNET_ARM_RESULT_STOPPING, GNUNET_ARM_SERVICE_STOPPING, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_log_strerror, GNUNET_NO, GNUNET_ntohll(), GNUNET_OS_process_kill(), GNUNET_SCHEDULER_add_now(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_persist(), GNUNET_TERM_SIG, GNUNET_TIME_absolute_get(), GNUNET_YES, in_shutdown, ServiceList::killed_at, ServiceList::killing_client, ServiceList::killing_client_request_id, ServiceList::proc, GNUNET_ARM_Message::request_id, signal_result(), and trigger_shutdown().

Here is the call graph for this function:

◆ pool_write()

static int pool_write ( char *  pool_start,
size_t  pool_size,
size_t *  pool_pos,
char *  str 
)
static

Write a string to a string pool.

Parameters
pool_startpointer to the start of the string pool
pool_sizesize of the string pool
[in,out]pool_poscurrent position index in the string pool, will be updated
strstring to write to the string pool
Returns
GNUNET_OK if the string fits into the pool, GNUNET_SYSERR otherwise

Definition at line 1370 of file gnunet-service-arm.c.

1371{
1372 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1373
1374 if (next_pos > pool_size)
1375 return GNUNET_SYSERR;
1376 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1377 *pool_pos = next_pos;
1378 return GNUNET_OK;
1379}

References GNUNET_OK, and GNUNET_SYSERR.

Referenced by handle_list().

Here is the caller graph for this function:

◆ handle_list()

static void handle_list ( void *  cls,
const struct GNUNET_ARM_Message request 
)
static

Handle LIST-message.

Parameters
clsidentification of the client
requestthe actual message

Definition at line 1389 of file gnunet-service-arm.c.

1390{
1391 struct GNUNET_SERVICE_Client *client = cls;
1392 struct GNUNET_MQ_Envelope *env;
1394 size_t extra_size;
1395 struct ServiceList *sl;
1396 uint16_t count;
1397 size_t pool_size;
1398 size_t pool_pos;
1399 char *pool_start;
1401
1402 GNUNET_break_op (0 == ntohl (request->reserved));
1403 count = 0;
1404 pool_size = 0;
1405
1406 /* Do one pass over the list to compute the number of services
1407 * and the string pool size */
1408 for (sl = running_head; NULL != sl; sl = sl->next)
1409 {
1410 pool_size += strlen (sl->name) + 1;
1411 pool_size += strlen (sl->binary) + 1;
1412 count++;
1413 }
1414
1415 extra_size = pool_size + (count * sizeof (struct
1418 extra_size,
1420 msg->arm_msg.request_id = request->request_id;
1421 msg->count = htons (count);
1422
1423 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1424 pool_start = (char *) (ssm + count);
1425 pool_pos = 0;
1426
1427 for (sl = running_head; NULL != sl; sl = sl->next)
1428 {
1429 ssm->name_index = htons ((uint16_t) pool_pos);
1430 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1431 sl->name));
1432 ssm->binary_index = htons ((uint16_t) pool_pos);
1433 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos,
1434 sl->binary));
1435 if (NULL == sl->proc)
1436 {
1437 if (0 == sl->last_started_at.abs_value_us)
1438 {
1439 /* Process never started */
1441 }
1442 else if (0 == sl->last_exit_status)
1443 {
1445 }
1446 else
1447 {
1449 ssm->last_exit_status = htons (sl->last_exit_status);
1450 }
1451 }
1452 else if ((NULL != sl->killing_client) || (GNUNET_YES == in_shutdown))
1453 {
1455 }
1456 else
1457 {
1459 }
1462 ssm++;
1463 }
1466}
static int pool_write(char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
Write a string to a string pool.
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition: gnunet-vpn.c:40
@ GNUNET_ARM_SERVICE_STATUS_FINISHED
The service was started, but then exited normally.
@ GNUNET_ARM_SERVICE_STATUS_FAILED
The service has previously failed, and will be restarted.
@ GNUNET_ARM_SERVICE_STATUS_STOPPED
Service is stopped.
@ GNUNET_ARM_SERVICE_STATUS_STOPPING
The service was started, and we're currently waiting for it to be stopped.
@ GNUNET_ARM_SERVICE_STATUS_STARTED
Service has been started and is currently running.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT
Response from ARM for listing currently running services.
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:640
Reply from ARM to client for the GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count '\0' terminat...
Definition: arm.h:145
struct GNUNET_TIME_AbsoluteNBO last_started_at
Time when the service was first started, if applicable.
Definition: arm.h:135
uint16_t binary_index
String pool index for the service's binary.
Definition: arm.h:109
struct GNUNET_TIME_AbsoluteNBO restart_at
Time when the service will be restarted, if applicable to the current status.
Definition: arm.h:130
uint32_t status
Status from the 'enum GNUNET_ARM_ServiceStatus'.
Definition: arm.h:124
int16_t last_exit_status
Last process exit status.
Definition: arm.h:114
uint16_t name_index
String pool index for the service's name.
Definition: arm.h:104
uint64_t abs_value_us
The actual value.
uint64_t request_id
non-zero if this request has been sent to the service.
Definition: vpn_api.c:127
int last_exit_status
Last exit status of the process.
struct GNUNET_TIME_Absolute restart_at
Absolute time at which the process is scheduled to restart in case of death.

References GNUNET_TIME_Absolute::abs_value_us, ServiceList::binary, GNUNET_ARM_ServiceInfoMessage::binary_index, env, GNUNET_ARM_SERVICE_STATUS_FAILED, GNUNET_ARM_SERVICE_STATUS_FINISHED, GNUNET_ARM_SERVICE_STATUS_STARTED, GNUNET_ARM_SERVICE_STATUS_STOPPED, GNUNET_ARM_SERVICE_STATUS_STOPPING, GNUNET_assert, GNUNET_break_op, GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_OK, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), GNUNET_TIME_absolute_hton(), GNUNET_YES, in_shutdown, ServiceList::killing_client, GNUNET_ARM_ServiceInfoMessage::last_exit_status, ServiceList::last_exit_status, GNUNET_ARM_ServiceInfoMessage::last_started_at, ServiceList::last_started_at, msg, ServiceList::name, GNUNET_ARM_ServiceInfoMessage::name_index, ServiceList::next, pool_write(), ServiceList::proc, request, GNUNET_VPN_RedirectionRequest::request_id, GNUNET_ARM_ServiceInfoMessage::restart_at, ServiceList::restart_at, running_head, and GNUNET_ARM_ServiceInfoMessage::status.

Here is the call graph for this function:

◆ handle_test()

static void handle_test ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Handle TEST-message by sending back TEST.

Parameters
clsidentification of the client
messagethe actual message

Definition at line 1476 of file gnunet-service-arm.c.

1477{
1478 struct GNUNET_SERVICE_Client *client = cls;
1479 struct GNUNET_MQ_Envelope *env;
1480 struct GNUNET_MessageHeader *msg;
1481
1482 (void) message;
1486}
#define GNUNET_MESSAGE_TYPE_ARM_TEST
Test if ARM service is online.
Header for all communications.

References env, GNUNET_MESSAGE_TYPE_ARM_TEST, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), and msg.

Here is the call graph for this function:

◆ do_shutdown()

static void do_shutdown ( )
static

We are done with everything.

Stop remaining tasks, signal handler and the server.

Definition at line 1494 of file gnunet-service-arm.c.

1495{
1496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
1497 if (NULL != notifier)
1498 {
1500 notifier = NULL;
1501 }
1502 if (NULL != service)
1503 {
1505 service = NULL;
1506 }
1507 if (NULL != child_death_task)
1508 {
1510 child_death_task = NULL;
1511 }
1512}
static struct GNUNET_SCHEDULER_Task * child_death_task
ID of task called whenever we get a SIGCHILD.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition: nc.c:138
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition: service.c:2426

References child_death_task, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_notification_context_destroy(), GNUNET_SCHEDULER_cancel(), GNUNET_SERVICE_shutdown(), notifier, and service.

Referenced by maint_child_death(), and shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ list_count()

static unsigned int list_count ( struct ServiceList run_head)
static

Count how many services are still active.

Parameters
running_headlist of services
Returns
number of active services found

Definition at line 1522 of file gnunet-service-arm.c.

1523{
1524 struct ServiceList *i;
1525 unsigned int res;
1526
1527 for (res = 0, i = run_head; NULL != i; i = i->next, res++)
1529 return res;
1530}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, ServiceList::name, ServiceList::next, and res.

Referenced by maint_child_death(), and shutdown_task().

Here is the caller graph for this function:

◆ shutdown_task()

static void shutdown_task ( void *  cls)
static

Task run for shutdown.

Parameters
clsclosure, NULL if we need to self-restart

Definition at line 1539 of file gnunet-service-arm.c.

1540{
1541 struct ServiceList *pos;
1542 struct ServiceList *nxt;
1543 struct ServiceListeningInfo *sli;
1544
1545 (void) cls;
1546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
1547 if (NULL != child_restart_task)
1548 {
1550 child_restart_task = NULL;
1551 }
1553 /* first, stop listening */
1554 for (pos = running_head; NULL != pos; pos = pos->next)
1555 {
1556 while (NULL != (sli = pos->listen_head))
1557 {
1559 if (NULL != sli->accept_task)
1560 {
1562 sli->accept_task = NULL;
1563 }
1567 GNUNET_free (sli);
1568 }
1569 }
1570 /* then, shutdown all existing service processes */
1571 nxt = running_head;
1572 while (NULL != (pos = nxt))
1573 {
1574 nxt = pos->next;
1575 if (NULL != pos->proc)
1576 {
1577 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name);
1581 }
1582 else
1583 {
1584 free_service (pos);
1585 }
1586 }
1587 /* finally, should all service processes be already gone, terminate for real */
1588 if (NULL == running_head)
1589 do_shutdown ();
1590 else
1592 "Delaying shutdown, have %u children still running\n",
1594}
static struct GNUNET_SCHEDULER_Task * child_restart_task
ID of task called whenever the timeout for restarting a child expires.
static void free_service(struct ServiceList *sl)
Remove and free an entry in the service list.
static unsigned int list_count(struct ServiceList *run_head)
Count how many services are still active.
static void do_shutdown()
We are done with everything.

References ServiceListeningInfo::accept_task, child_restart_task, do_shutdown(), free_service(), GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_log_strerror, GNUNET_NETWORK_socket_close(), GNUNET_OK, GNUNET_OS_process_kill(), GNUNET_SCHEDULER_cancel(), GNUNET_TERM_SIG, GNUNET_TIME_absolute_get(), GNUNET_YES, in_shutdown, ServiceList::killed_at, list_count(), ServiceList::listen_head, ServiceListeningInfo::listen_socket, ServiceList::listen_tail, ServiceList::name, ServiceList::next, ServiceList::proc, running_head, and ServiceListeningInfo::service_addr.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ delayed_restart_task()

static void delayed_restart_task ( void *  cls)
static

Task run whenever it is time to restart a child that died.

Parameters
clsclosure, always NULL

Definition at line 1603 of file gnunet-service-arm.c.

1605{
1606 struct ServiceList *sl;
1607 struct GNUNET_TIME_Relative lowestRestartDelay;
1608 struct ServiceListeningInfo *sli;
1609
1610 (void) cls;
1611 child_restart_task = NULL;
1613 lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
1614
1615 /* check for services that need to be restarted due to
1616 * configuration changes or because the last restart failed */
1617 for (sl = running_head; NULL != sl; sl = sl->next)
1618 {
1619 if (NULL != sl->proc)
1620 continue;
1621 /* service is currently not running */
1623 {
1624 /* restart is now allowed */
1625 if (sl->force_start)
1626 {
1627 /* process should run by default, start immediately */
1629 _ ("Restarting service `%s'.\n"),
1630 sl->name);
1631 start_process (sl, NULL, 0);
1632 }
1633 else
1634 {
1635 /* process is run on-demand, ensure it is re-started if there is demand */
1636 for (sli = sl->listen_head; NULL != sli; sli = sli->next)
1637 if (NULL == sli->accept_task)
1638 {
1639 /* accept was actually paused, so start it again */
1640 sli->accept_task =
1642 sli->listen_socket,
1644 sli);
1645 }
1646 }
1647 }
1648 else
1649 {
1650 /* update calculation for earliest time to reactivate a service */
1651 lowestRestartDelay =
1652 GNUNET_TIME_relative_min (lowestRestartDelay,
1654 sl->restart_at));
1655 }
1656 }
1657 if (lowestRestartDelay.rel_value_us !=
1658 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1659 {
1661 "Will restart process in %s\n",
1662 GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay,
1663 GNUNET_YES));
1668 NULL);
1669 }
1670}
static void delayed_restart_task(void *cls)
Task run whenever it is time to restart a child that died.
@ GNUNET_SCHEDULER_PRIORITY_IDLE
Run when otherwise idle.
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:1206
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:344
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:406
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:579
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.

References _, accept_connection(), ServiceListeningInfo::accept_task, child_restart_task, delayed_restart_task(), ServiceList::force_start, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_add_delayed_with_priority(), GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_PRIORITY_IDLE, GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_relative_min(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, in_shutdown, ServiceList::listen_head, ServiceListeningInfo::listen_socket, ServiceList::name, ServiceListeningInfo::next, ServiceList::next, ServiceList::proc, GNUNET_TIME_Relative::rel_value_us, ServiceList::restart_at, running_head, ServiceListeningInfo::sl, and start_process().

Referenced by delayed_restart_task(), and maint_child_death().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ maint_child_death()

static void maint_child_death ( void *  cls)
static

Task triggered whenever we receive a SIGCHLD (child process died).

Parameters
clsclosure, NULL

Definition at line 1680 of file gnunet-service-arm.c.

1681{
1682 struct ServiceList *pos;
1683 struct ServiceList *next;
1684 struct ServiceListeningInfo *sli;
1685 const char *statstr;
1686 int statcode;
1687 int ret;
1688 char c[16];
1689 enum GNUNET_OS_ProcessStatusType statusType;
1690 unsigned long statusCode;
1691 const struct GNUNET_DISK_FileHandle *pr;
1692
1693 (void) cls;
1695 child_death_task = NULL;
1696 /* consume the signal */
1697 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
1698
1699 /* check for services that died (WAITPID) */
1700 next = running_head;
1701 while (NULL != (pos = next))
1702 {
1703 next = pos->next;
1704
1705 if (NULL == pos->proc)
1706 {
1707 if (GNUNET_YES == in_shutdown)
1708 free_service (pos);
1709 continue;
1710 }
1711#if HAVE_WAIT4
1712 if (NULL != wait_file)
1713 {
1714 /* need to use 'wait4()' to obtain and log performance data */
1715 struct rusage ru;
1716 int status;
1717 pid_t pid;
1718
1720 ret = wait4 (pid, &status, WNOHANG, &ru);
1721 if (ret <= 0)
1722 continue; /* no process done */
1723 if (WIFEXITED (status))
1724 {
1725 statusType = GNUNET_OS_PROCESS_EXITED;
1726 statusCode = WEXITSTATUS (status);
1727 }
1728 else if (WIFSIGNALED (status))
1729 {
1730 statusType = GNUNET_OS_PROCESS_SIGNALED;
1731 statusCode = WTERMSIG (status);
1732 }
1733 else if (WIFSTOPPED (status))
1734 {
1735 statusType = GNUNET_OS_PROCESS_SIGNALED;
1736 statusCode = WSTOPSIG (status);
1737 }
1738#ifdef WIFCONTINUED
1739 else if (WIFCONTINUED (status))
1740 {
1741 statusType = GNUNET_OS_PROCESS_RUNNING;
1742 statusCode = 0;
1743 }
1744#endif
1745 else
1746 {
1747 statusType = GNUNET_OS_PROCESS_UNKNOWN;
1748 statusCode = 0;
1749 }
1750 if ((GNUNET_OS_PROCESS_EXITED == statusType) ||
1751 (GNUNET_OS_PROCESS_SIGNALED == statusType))
1752 {
1753 double utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 10e6);
1754 double stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 10e6);
1755 fprintf (wait_file,
1756 "%s(%u) %.3f %.3f %llu %llu %llu %llu %llu\n",
1757 pos->binary,
1758 (unsigned int) pid,
1759 utime,
1760 stime,
1761 (unsigned long long) ru.ru_maxrss,
1762 (unsigned long long) ru.ru_inblock,
1763 (unsigned long long) ru.ru_oublock,
1764 (unsigned long long) ru.ru_nvcsw,
1765 (unsigned long long) ru.ru_nivcsw);
1766 }
1767 }
1768 else /* continue with JUST this "if" as "else" (intentionally no brackets!) */
1769#endif
1771 &statusType,
1772 &statusCode))) ||
1773 (ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) ||
1774 (statusType == GNUNET_OS_PROCESS_UNKNOWN) ||
1775 (statusType == GNUNET_OS_PROCESS_RUNNING))
1776 continue;
1777
1778 if (statusType == GNUNET_OS_PROCESS_EXITED)
1779 {
1780 statstr = _ (/* process termination method */ "exit");
1781 statcode = statusCode;
1782 }
1783 else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
1784 {
1785 statstr = _ (/* process termination method */ "signal");
1786 statcode = statusCode;
1787 }
1788 else
1789 {
1790 statstr = _ (/* process termination method */ "unknown");
1791 statcode = 0;
1792 }
1793 if (0 != pos->killed_at.abs_value_us)
1794 {
1796 _ ("Service `%s' took %s to terminate\n"),
1797 pos->name,
1800 GNUNET_YES));
1801 }
1803 pos->proc = NULL;
1805 if (NULL != pos->killing_client)
1806 {
1808 pos->name,
1811 pos->killing_client = NULL;
1813 }
1814 if (GNUNET_YES != in_shutdown)
1815 {
1816 pos->last_exit_status = statcode;
1817 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1818 {
1819 /* process terminated normally, allow restart at any time */
1820 pos->restart_at.abs_value_us = 0;
1821 GNUNET_log (
1823 _ ("Service `%s' terminated normally, will restart at any time\n"),
1824 pos->name);
1825 /* process can still be re-started on-demand, ensure it is re-started if there is demand */
1826 for (sli = pos->listen_head; NULL != sli; sli = sli->next)
1827 {
1828 GNUNET_break (NULL == sli->accept_task);
1829 sli->accept_task =
1831 sli->listen_socket,
1833 sli);
1834 }
1835 }
1836 else
1837 {
1838 GNUNET_log (
1840 _ ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1841 pos->name,
1842 statstr,
1843 statcode,
1845 {
1846 /* Reduce backoff based on runtime of the process,
1847 so that there is a cool-down if a process actually
1848 runs for a while. */
1849 struct GNUNET_TIME_Relative runtime;
1850 unsigned int minutes;
1851
1853 minutes =
1854 runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
1855 if (minutes > 31)
1857 else
1858 pos->backoff.rel_value_us >>= minutes;
1859 }
1860 /* schedule restart */
1863 if (NULL != child_restart_task)
1868 NULL);
1869 }
1870 }
1871 else
1872 {
1873 free_service (pos);
1874 }
1875 }
1878 pr,
1880 NULL);
1881 if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
1882 do_shutdown ();
1883 else if (GNUNET_YES == in_shutdown)
1885 "Delaying shutdown after child's death, still have %u children\n",
1887}
static void maint_child_death(void *cls)
Task triggered whenever we receive a SIGCHLD (child process died).
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate shutdown via signal.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
@ GNUNET_ARM_SERVICE_STOPPED
Service was stopped.
@ GNUNET_ARM_RESULT_STOPPED
Service was stopped (never sent for ARM itself).
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:1618
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:623
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:253
GNUNET_OS_ProcessStatusType
Process status types.
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:260
enum GNUNET_GenericReturnValue GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process.
Definition: os_priority.c:860
@ GNUNET_OS_PROCESS_SIGNALED
The process was killed by a signal.
@ GNUNET_OS_PROCESS_EXITED
The process exited with a return code.
@ GNUNET_OS_PROCESS_UNKNOWN
The process is not known to the OS (or at least not one of our children).
@ GNUNET_OS_PROCESS_STOPPED
The process is paused (but could be resumed).
@ GNUNET_OS_PROCESS_RUNNING
The process is still running.
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:1660
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:1230
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:438
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:316
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
Handle used to access files (and pipes).
struct GNUNET_TIME_Relative backoff
Process exponential backoff time.

References _, GNUNET_TIME_Absolute::abs_value_us, accept_connection(), ServiceListeningInfo::accept_task, ServiceList::backoff, ServiceList::binary, broadcast_status(), child_death_task, child_restart_task, delayed_restart_task(), do_shutdown(), free_service(), GNUNET_ARM_RESULT_STOPPED, GNUNET_ARM_SERVICE_STOPPED, GNUNET_break, GNUNET_DISK_file_read(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_pipe_handle(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NO, GNUNET_OS_process_destroy(), GNUNET_OS_PROCESS_EXITED, GNUNET_OS_process_get_pid(), GNUNET_OS_PROCESS_RUNNING, GNUNET_OS_PROCESS_SIGNALED, GNUNET_OS_process_status(), GNUNET_OS_PROCESS_STOPPED, GNUNET_OS_PROCESS_UNKNOWN, GNUNET_SCHEDULER_add_read_file(), GNUNET_SCHEDULER_add_read_net(), GNUNET_SCHEDULER_add_with_priority(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_PRIORITY_IDLE, GNUNET_STRINGS_relative_time_to_string(), GNUNET_SYSERR, GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_STD_BACKOFF, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_MINUTES, GNUNET_TIME_UNIT_ZERO, GNUNET_YES, in_shutdown, ServiceList::killed_at, ServiceList::killing_client, ServiceList::killing_client_request_id, ServiceList::last_exit_status, list_count(), ServiceList::listen_head, ServiceListeningInfo::listen_socket, maint_child_death(), ServiceList::name, ServiceListeningInfo::next, ServiceList::next, pid, ServiceList::proc, GNUNET_TIME_Relative::rel_value_us, ServiceList::restart_at, ret, running_head, signal_result(), sigpipe, and status.

Referenced by maint_child_death(), and run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sighandler_child_death()

static void sighandler_child_death ( void  )
static

Signal handler called for SIGCHLD.

Triggers the respective handler by writing to the trigger pipe.

Definition at line 1895 of file gnunet-service-arm.c.

1896{
1897 static char c;
1898 int old_errno = errno; /* back-up errno */
1899
1900 GNUNET_break (
1901 1 ==
1904 ,
1905 &c,
1906 sizeof(c)));
1907 errno = old_errno; /* restore errno */
1908}
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:687
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.

References GNUNET_break, GNUNET_DISK_file_write(), GNUNET_DISK_PIPE_END_WRITE, GNUNET_DISK_pipe_handle(), and sigpipe.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_service()

static void setup_service ( void *  cls,
const char *  section 
)
static

Setup our service record for the given section in the configuration file (assuming the section is for a service).

Parameters
clsunused
sectiona section in the configuration file
Returns
GNUNET_OK (continue)

Definition at line 1920 of file gnunet-service-arm.c.

1921{
1922 struct ServiceList *sl;
1923 char *binary;
1924 char *config;
1925 struct stat sbuf;
1926 struct sockaddr **addrs;
1927 socklen_t *addr_lens;
1928 int ret;
1929
1930 (void) cls;
1931 if (0 == strcasecmp (section, "arm"))
1932 return;
1933 if (GNUNET_OK !=
1934 GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
1935 {
1936 /* not a service section */
1937 return;
1938 }
1939 if (GNUNET_YES ==
1941 section,
1942 "RUN_PER_USER"))
1943 {
1944 if (GNUNET_NO == start_user)
1945 {
1946 GNUNET_free (binary);
1947 return; /* user service, and we don't deal with those */
1948 }
1949 }
1950 else
1951 {
1952 if (GNUNET_NO == start_system)
1953 {
1954 GNUNET_free (binary);
1955 return; /* system service, and we don't deal with those */
1956 }
1957 }
1958 sl = find_service (section);
1959 if (NULL != sl)
1960 {
1961 /* got the same section twice!? */
1962 GNUNET_break (0);
1963 GNUNET_free (binary);
1964 return;
1965 }
1966 config = NULL;
1967 if (((GNUNET_OK !=
1969 section,
1970 "CONFIG",
1971 &config)) &&
1972 (GNUNET_OK !=
1974 "PATHS",
1975 "DEFAULTCONFIG",
1976 &config))) ||
1977 (0 != stat (config,
1978 &sbuf)))
1979 {
1980 if (NULL != config)
1981 {
1983 section,
1984 "CONFIG",
1985 strerror (errno));
1987 config = NULL;
1988 }
1989 }
1990 sl = GNUNET_new (struct ServiceList);
1991 sl->name = GNUNET_strdup (section);
1992 sl->binary = binary;
1993 sl->config = config;
1996 sl->pipe_control =
1997 (GNUNET_YES ==
1999 section,
2000 "PIPECONTROL"));
2003 sl);
2004 if (GNUNET_YES ==
2006 section,
2007 "IMMEDIATE_START"))
2008 {
2009 sl->force_start = GNUNET_YES;
2010 if (GNUNET_YES ==
2012 section,
2013 "NOARMBIND"))
2014 return;
2015 }
2016 else
2017 {
2018 if (GNUNET_YES !=
2020 section,
2021 "START_ON_DEMAND"))
2022 return;
2023 }
2024 if (0 >= (ret = get_server_addresses (section,
2025 cfg,
2026 &addrs,
2027 &addr_lens)))
2028 return;
2029 /* this will free (or capture) addrs[i] */
2030 for (unsigned int i = 0; i < (unsigned int) ret; i++)
2031 create_listen_socket (addrs[i], addr_lens[i], sl);
2032 GNUNET_free (addrs);
2033 GNUNET_free (addr_lens);
2034}
const struct GNUNET_CONFIGURATION_Handle * config
static int start_user
Are we starting user services?
static int start_system
Are we starting system services?
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 create_listen_socket(struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl)
Creating a listening socket for each of the service's addresses and wait for the first incoming conne...
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".

References ServiceList::backoff, ServiceList::binary, cfg, config, ServiceList::config, create_listen_socket(), find_service(), ServiceList::force_start, get_server_addresses(), GNUNET_break, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log_config_invalid(), GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_strdup, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_YES, consensus-simulation::int, ServiceList::name, ServiceList::pipe_control, ServiceList::restart_at, ret, running_head, running_tail, start_system, and start_user.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_connect_cb()

static void * client_connect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
struct GNUNET_MQ_Handle mq 
)
static

A client connected, mark as a monitoring client.

Parameters
clsclosure
clientidentification of the client
mqqueue to talk to client
Returns
client

Definition at line 2046 of file gnunet-service-arm.c.

2049{
2050 /* All clients are considered to be of the "monitor" kind
2051 * (that is, they don't affect ARM shutdown).
2052 */
2053 (void) cls;
2054 (void) mq;
2056 return client;
2057}
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the 'monitor' flag on this client.
Definition: service.c:2442

References GNUNET_SERVICE_client_mark_monitor(), and mq.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_disconnect_cb()

static void client_disconnect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
void *  app_ctx 
)
static

A client disconnected, clean up associated state.

Parameters
clsclosure
clientidentification of the client
app_ctxmust match client

Definition at line 2068 of file gnunet-service-arm.c.

2071{
2072 (void) cls;
2073 GNUNET_assert (client == app_ctx);
2074 for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
2075 if (sl->killing_client == client)
2076 sl->killing_client = NULL;
2077}

References GNUNET_assert, ServiceList::next, and running_head.

Referenced by main().

Here is the caller graph for this function:

◆ handle_monitor()

static void handle_monitor ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Handle MONITOR-message.

Parameters
clsidentification of the client
messagethe actual message
Returns
GNUNET_OK to keep the connection open, GNUNET_SYSERR to close it (signal serious error)

Definition at line 2089 of file gnunet-service-arm.c.

2090{
2091 struct GNUNET_SERVICE_Client *client = cls;
2092
2093 (void) message;
2094 /* FIXME: might want to start by letting monitor know about
2095 services that are already running */
2096 /* Removal is handled by the server implementation, internally. */
2101}
@ GNUNET_ARM_SERVICE_MONITORING_STARTED
Dummy message.
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition: nc.c:161

References broadcast_status(), GNUNET_ARM_SERVICE_MONITORING_STARTED, GNUNET_notification_context_add(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), and notifier.

Here is the call graph for this function:

◆ run()

static void run ( void *  cls,
const struct GNUNET_CONFIGURATION_Handle c,
struct GNUNET_SERVICE_Handle serv 
)
static

Process arm requests.

Parameters
clsclosure, NULL
servthe initialized service
cconfiguration to use

Definition at line 2112 of file gnunet-service-arm.c.

2115{
2116 struct ServiceList *sl;
2117 enum GNUNET_GenericReturnValue ret1;
2118 enum GNUNET_GenericReturnValue ret2;
2119
2120 (void) cls;
2121 cfg = c;
2122 service = serv;
2129 NULL);
2130#if HAVE_WAIT4
2131 if (GNUNET_OK ==
2133 "ARM",
2134 "RESOURCE_DIAGNOSTICS",
2135 &wait_filename))
2136 {
2137 wait_file = fopen (wait_filename, "w");
2138 if (NULL == wait_file)
2139 {
2141 "fopen",
2142 wait_filename);
2143 }
2144 }
2145#endif
2146 if (GNUNET_OK !=
2148 "ARM",
2149 "GLOBAL_PREFIX",
2152 else
2154 if (GNUNET_OK !=
2156 "ARM",
2157 "GLOBAL_POSTFIX",
2158 &final_option))
2160 else
2163 "ARM",
2164 "START_SYSTEM_SERVICES");
2166 "ARM",
2167 "START_USER_SERVICES");
2168 if ( (GNUNET_SYSERR == ret1) ||
2169 (GNUNET_SYSERR == ret2) )
2170 {
2171 /* invalid option */
2172 GNUNET_break (0);
2174 global_ret = 1;
2175 return;
2176 }
2178 "ARM",
2179 "START_SYSTEM_SERVICES"))
2180 ret1 = GNUNET_SYSERR;
2182 "ARM",
2183 "START_USER_SERVICES"))
2184 ret2 = GNUNET_SYSERR;
2185 start_system = (GNUNET_YES == ret1) ||
2186 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2187 start_user = (GNUNET_YES == ret2) ||
2188 ( (GNUNET_SYSERR == ret1) && (GNUNET_SYSERR == ret2) );
2189 if ( (GNUNET_NO == start_user) &&
2190 (GNUNET_NO == start_system) )
2191 {
2192 GNUNET_log (
2194 "Please enable either START_USER_SERVICES or START_SYSTEM_SERVICES\n");
2196 global_ret = 1;
2197 return;
2198 }
2201 NULL);
2202
2203 /* start default services... */
2204 for (sl = running_head; NULL != sl; sl = sl->next)
2205 if (GNUNET_YES == sl->force_start)
2206 start_process (sl, NULL, 0);
2208}
#define MAX_NOTIFY_QUEUE
How many messages do we queue up at most for optional notifications to a client? (this can cause noti...
static int global_ret
Return value from main.
static void shutdown_task(void *cls)
Task run for shutdown.
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...
void GNUNET_CONFIGURATION_iterate_sections(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_SectionIterator iter, void *iter_cls)
Iterate over all sections in the configuration.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition: nc.c:122
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1338

References cfg, child_death_task, final_option, ServiceList::force_start, global_ret, GNUNET_break, GNUNET_CONFIGURATION_expand_dollar(), GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONFIGURATION_have_value(), GNUNET_CONFIGURATION_iterate_sections(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_pipe_handle(), GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_log_strerror_file, GNUNET_NO, GNUNET_notification_context_create(), GNUNET_OK, GNUNET_SCHEDULER_add_read_file(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_SCHEDULER_shutdown(), GNUNET_strdup, GNUNET_SYSERR, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, maint_child_death(), MAX_NOTIFY_QUEUE, ServiceList::next, notifier, prefix_command, running_head, service, setup_service(), shutdown_task(), sigpipe, start_process(), start_system, and start_user.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *const *  argv 
)

The main function for the arm service.

Parameters
argcnumber of arguments from the command line
argvcommand line arguments
Returns
0 ok, 1 on error

Definition at line 2219 of file gnunet-service-arm.c.

2220{
2225 struct GNUNET_ARM_Message,
2226 NULL),
2229 struct GNUNET_ARM_Message,
2230 NULL),
2233 struct GNUNET_MessageHeader,
2234 NULL),
2237 struct GNUNET_ARM_Message,
2238 NULL),
2241 struct GNUNET_MessageHeader,
2242 NULL),
2244 };
2245
2247 GNUNET_assert (NULL != sigpipe);
2248 shc_chld =
2251 if (0 != GNUNET_SERVICE_run_ (argc,
2252 argv,
2253 "arm",
2256 &run,
2259 NULL,
2260 handlers))
2261 global_ret = 2;
2262#if HAVE_WAIT4
2263 if (NULL != wait_file)
2264 {
2265 fclose (wait_file);
2266 wait_file = NULL;
2267 }
2268 if (NULL != wait_filename)
2269 {
2270 GNUNET_free (wait_filename);
2271 wait_filename = NULL;
2272 }
2273#endif
2275 shc_chld = NULL;
2277 sigpipe = NULL;
2278 return global_ret;
2279}
struct GNUNET_MQ_MessageHandlers handlers[]
Definition: 003.c:1
static struct GNUNET_SIGNAL_Context * shc_chld
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:38
static int monitor
Monitor ARM activity.
Definition: gnunet-arm.c:63
static int list
Set if we should print a list of currently running services.
Definition: gnunet-arm.c:68
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *serv)
Process arm requests.
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 void sighandler_child_death()
Signal handler called for SIGCHLD.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up associated state.
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1445
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1588
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
#define GNUNET_MESSAGE_TYPE_ARM_STOP
Request to ARM to stop a service.
#define GNUNET_MESSAGE_TYPE_ARM_START
Request to ARM to start a service.
#define GNUNET_MESSAGE_TYPE_ARM_LIST
Request to ARM to list all currently running services.
#define GNUNET_MESSAGE_TYPE_ARM_MONITOR
Request to ARM to notify client of service status changes.
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:1965
@ GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN
Do not trigger server shutdown on signal at all; instead, allow for the user to terminate the server ...
@ GNUNET_SERVICE_OPTION_CLOSE_LSOCKS
Instead of listening on lsocks passed by the parent, close them after opening our own listen socket(s...
struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install(int signal, GNUNET_SIGNAL_Handler handler)
Install a signal handler that will be run if the given signal is received.
Definition: signal.c:52
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal handler.
Definition: signal.c:78
#define GNUNET_SIGCHLD
Definition: platform.h:42
Message handler for a specific message type.

References client_connect_cb(), client_disconnect_cb(), global_ret, GNUNET_assert, GNUNET_DISK_PF_NONE, GNUNET_DISK_pipe(), GNUNET_DISK_pipe_close(), GNUNET_free, GNUNET_MESSAGE_TYPE_ARM_LIST, GNUNET_MESSAGE_TYPE_ARM_MONITOR, GNUNET_MESSAGE_TYPE_ARM_START, GNUNET_MESSAGE_TYPE_ARM_STOP, GNUNET_MESSAGE_TYPE_ARM_TEST, GNUNET_MQ_handler_end, GNUNET_MQ_hd_fixed_size, GNUNET_MQ_hd_var_size, GNUNET_SERVICE_OPTION_CLOSE_LSOCKS, GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, GNUNET_SERVICE_run_(), GNUNET_SIGCHLD, GNUNET_SIGNAL_handler_install(), GNUNET_SIGNAL_handler_uninstall(), handlers, list, monitor, run(), shc_chld, sighandler_child_death(), sigpipe, and start.

Here is the call graph for this function:

Variable Documentation

◆ running_head

struct ServiceList* running_head
static

◆ running_tail

struct ServiceList* running_tail
static

List of running services.

Definition at line 211 of file gnunet-service-arm.c.

Referenced by free_service(), and setup_service().

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Our configuration.

Definition at line 216 of file gnunet-service-arm.c.

Referenced by create_listen_socket(), get_server_addresses(), run(), setup_service(), and start_process().

◆ prefix_command

char* prefix_command
static

Command to prepend to each actual command.

Definition at line 221 of file gnunet-service-arm.c.

Referenced by run(), and start_process().

◆ final_option

char* final_option
static

Option to append to each actual command.

Definition at line 226 of file gnunet-service-arm.c.

Referenced by run(), and start_process().

◆ child_death_task

struct GNUNET_SCHEDULER_Task* child_death_task
static

ID of task called whenever we get a SIGCHILD.

Definition at line 231 of file gnunet-service-arm.c.

Referenced by do_shutdown(), maint_child_death(), and run().

◆ child_restart_task

struct GNUNET_SCHEDULER_Task* child_restart_task
static

ID of task called whenever the timeout for restarting a child expires.

Definition at line 237 of file gnunet-service-arm.c.

Referenced by delayed_restart_task(), maint_child_death(), and shutdown_task().

◆ sigpipe

struct GNUNET_DISK_PipeHandle* sigpipe
static

Pipe used to communicate shutdown via signal.

Definition at line 242 of file gnunet-service-arm.c.

Referenced by main(), maint_child_death(), run(), and sighandler_child_death().

◆ in_shutdown

int in_shutdown
static

◆ global_ret

int global_ret
static

Return value from main.

Definition at line 252 of file gnunet-service-arm.c.

Referenced by main(), and run().

◆ start_user

int start_user = GNUNET_YES
static

Are we starting user services?

Definition at line 257 of file gnunet-service-arm.c.

Referenced by run(), and setup_service().

◆ start_system

int start_system = GNUNET_YES
static

Are we starting system services?

Definition at line 262 of file gnunet-service-arm.c.

Referenced by run(), and setup_service().

◆ service

struct GNUNET_SERVICE_Handle* service
static

Handle to our service instance.

Our service is a bit special in that its service is not immediately stopped once we get a shutdown request (since we need to continue service until all of our child processes are dead). This handle is used to shut down the service (and thus trigger process termination) once all child processes are also dead. A special option in the ARM configuration modifies the behaviour of the service implementation to not do the shutdown immediately.

Definition at line 274 of file gnunet-service-arm.c.

Referenced by add_service_handle(), callback_shutdown_service(), check_get(), check_set(), check_statistics_value(), check_watch(), close_service_room(), create_message_info(), create_message_peer(), create_service(), create_srv_handle(), destroy_service(), do_shutdown(), entry_service_room(), find_subsystem_entry(), free_service_record(), get_service_contact_store(), get_service_peer_identity(), get_service_room(), gns_string_to_value(), handle_get(), handle_service_message(), handle_set(), handle_statistics_value(), handle_watch(), init_peer_store(), open_service_room(), recv_message_miss(), remove_service_handle(), resolver_lookup_get_next_label(), run(), srv_status(), and store_service().

◆ notifier

struct GNUNET_NotificationContext* notifier
static

Context for notifications we need to send to our clients.

Definition at line 279 of file gnunet-service-arm.c.

Referenced by broadcast_status(), do_shutdown(), handle_monitor(), and run().