1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
- */
- /**
- * @file arm/gnunet-service-arm.c
- * @brief the automated restart manager service
- * @author Christian Grothoff
- */
- #include "platform.h"
- #include "gnunet_util_lib.h"
- #include "gnunet_arm_service.h"
- #include "gnunet_protocols.h"
- #include "arm.h"
- /**
- * 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).
- */
- #define MAX_NOTIFY_QUEUE 1024
- /**
- * List of our services.
- */
- struct ServiceList;
- /**
- * Record with information about a listen socket we have open.
- */
- struct ServiceListeningInfo
- {
- /**
- * This is a linked list.
- */
- struct ServiceListeningInfo *next;
- /**
- * This is a linked list.
- */
- struct ServiceListeningInfo *prev;
- /**
- * Address this socket is listening on.
- */
- struct sockaddr *service_addr;
- /**
- * Service this listen socket is for.
- */
- struct ServiceList *sl;
- /**
- * Number of bytes in 'service_addr'
- */
- socklen_t service_addr_len;
- /**
- * Our listening socket.
- */
- struct GNUNET_NETWORK_Handle *listen_socket;
- /**
- * Task doing the accepting.
- */
- struct GNUNET_SCHEDULER_Task * accept_task;
- };
- /**
- * List of our services.
- */
- struct ServiceList
- {
- /**
- * This is a doubly-linked list.
- */
- struct ServiceList *next;
- /**
- * This is a doubly-linked list.
- */
- struct ServiceList *prev;
- /**
- * Linked list of listen sockets associated with this service.
- */
- struct ServiceListeningInfo *listen_head;
- /**
- * Linked list of listen sockets associated with this service.
- */
- struct ServiceListeningInfo *listen_tail;
- /**
- * Name of the service.
- */
- char *name;
- /**
- * Name of the binary used.
- */
- char *binary;
- /**
- * Name of the configuration file used.
- */
- char *config;
- /**
- * Client to notify upon kill completion (waitpid), NULL
- * if we should simply restart the process.
- */
- struct GNUNET_SERVER_Client *killing_client;
- /**
- * ID of the request that killed the service (for reporting back).
- */
- uint64_t killing_client_request_id;
- /**
- * Process structure pointer of the child.
- */
- struct GNUNET_OS_Process *proc;
- /**
- * Process exponential backoff time
- */
- struct GNUNET_TIME_Relative backoff;
- /**
- * Absolute time at which the process is scheduled to restart in case of death
- */
- struct GNUNET_TIME_Absolute restart_at;
- /**
- * Time we asked the service to shut down (used to calculate time it took
- * the service to terminate).
- */
- struct GNUNET_TIME_Absolute killed_at;
- /**
- * Is this service to be started by default (or did a client tell us explicitly
- * to start it)? #GNUNET_NO if the service is started only upon 'accept' on a
- * listen socket or possibly explicitly by a client changing the value.
- */
- int force_start;
- /**
- * Should we use pipes to signal this process? (YES for Java binaries and if we
- * are on Windoze).
- */
- int pipe_control;
- };
- /**
- * List of running services.
- */
- static struct ServiceList *running_head;
- /**
- * List of running services.
- */
- static struct ServiceList *running_tail;
- /**
- * Our configuration
- */
- static const struct GNUNET_CONFIGURATION_Handle *cfg;
- /**
- * Command to prepend to each actual command.
- */
- static char *prefix_command;
- /**
- * Option to append to each actual command.
- */
- static char *final_option;
- /**
- * ID of task called whenever we get a SIGCHILD.
- */
- static struct GNUNET_SCHEDULER_Task * child_death_task;
- /**
- * ID of task called whenever the timeout for restarting a child
- * expires.
- */
- static struct GNUNET_SCHEDULER_Task * child_restart_task;
- /**
- * Pipe used to communicate shutdown via signal.
- */
- static struct GNUNET_DISK_PipeHandle *sigpipe;
- /**
- * Are we in shutdown mode?
- */
- static int in_shutdown;
- /**
- * Are we starting user services?
- */
- static int start_user = GNUNET_YES;
- /**
- * Are we starting system services?
- */
- static int start_system = GNUNET_YES;
- /**
- * Handle to our server instance. Our server 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 server
- * (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.
- */
- static struct GNUNET_SERVER_Handle *server;
- /**
- * Context for notifications we need to send to our clients.
- */
- static struct GNUNET_SERVER_NotificationContext *notifier;
- /**
- * Transmit a status result message.
- *
- * @param cls a `unit16_t *` with message type
- * @param size number of bytes available in @a buf
- * @param buf where to copy the message, NULL on error
- * @return number of bytes copied to @a buf
- */
- static size_t
- write_result (void *cls, size_t size, void *buf)
- {
- struct GNUNET_ARM_ResultMessage *msg = cls;
- size_t msize;
- if (NULL == buf)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Could not send status result to client\n"));
- GNUNET_free (msg);
- return 0; /* error, not much we can do */
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending status response %u to client\n",
- (unsigned int) msg->result);
- msize = msg->arm_msg.header.size;
- GNUNET_assert (size >= msize);
- msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
- msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
- msg->result = htonl (msg->result);
- msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
- memcpy (buf, msg, msize);
- GNUNET_free (msg);
- return msize;
- }
- /**
- * Transmit the list of running services.
- *
- * @param cls pointer to `struct GNUNET_ARM_ListResultMessage` with the message
- * @param size number of bytes available in @a buf
- * @param buf where to copy the message, NULL on error
- * @return number of bytes copied to @a buf
- */
- static size_t
- write_list_result (void *cls, size_t size, void *buf)
- {
- struct GNUNET_ARM_ListResultMessage *msg = cls;
- size_t rslt_size;
- if (NULL == buf)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Could not send list result to client\n"));
- GNUNET_free (msg);
- return 0; /* error, not much we can do */
- }
- rslt_size = msg->arm_msg.header.size;
- GNUNET_assert (size >= rslt_size);
- msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
- msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
- msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
- msg->count = htons (msg->count);
- memcpy (buf, msg, rslt_size);
- GNUNET_free (msg);
- return rslt_size;
- }
- /**
- * Signal our client that we will start or stop the
- * service.
- *
- * @param client who is being signalled
- * @param name name of the service
- * @param request_id id of the request that is being responded to.
- * @param result message type to send
- * @return NULL if it was not found
- */
- static void
- signal_result (struct GNUNET_SERVER_Client *client,
- const char *name,
- uint64_t request_id,
- enum GNUNET_ARM_Result result)
- {
- struct GNUNET_ARM_ResultMessage *msg;
- size_t msize;
- msize = sizeof (struct GNUNET_ARM_ResultMessage);
- msg = GNUNET_malloc (msize);
- msg->arm_msg.header.size = msize;
- msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_RESULT;
- msg->result = result;
- msg->arm_msg.request_id = request_id;
- GNUNET_SERVER_notify_transmit_ready (client, msize,
- GNUNET_TIME_UNIT_FOREVER_REL,
- write_result, msg);
- }
- /**
- * Tell all clients about status change of a service.
- *
- * @param name name of the service
- * @param status message type to send
- * @param unicast if not NULL, send to this client only.
- * otherwise, send to all clients in the notifier
- */
- static void
- broadcast_status (const char *name,
- enum GNUNET_ARM_ServiceStatus status,
- struct GNUNET_SERVER_Client *unicast)
- {
- struct GNUNET_ARM_StatusMessage *msg;
- size_t namelen;
- if (NULL == notifier)
- return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending status %u of service `%s' to client\n",
- (unsigned int) status, name);
- namelen = strlen (name);
- msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
- msg->header.size = htons (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_STATUS);
- msg->status = htonl ((uint32_t) (status));
- memcpy ((char *) &msg[1], name, namelen + 1);
- if (NULL == unicast)
- GNUNET_SERVER_notification_context_broadcast (notifier,
- (struct GNUNET_MessageHeader *) msg, GNUNET_YES);
- else
- GNUNET_SERVER_notification_context_unicast (notifier, unicast,
- (const struct GNUNET_MessageHeader *) msg, GNUNET_NO);
- GNUNET_free (msg);
- }
- /**
- * Actually start the process for the given service.
- *
- * @param sl identifies service to start
- * @param client that asked to start the service (may be NULL)
- * @param request_id id of the request in response to which the process is
- * being started. 0 if starting was not requested.
- */
- static void
- start_process (struct ServiceList *sl,
- struct GNUNET_SERVER_Client *client,
- uint64_t request_id)
- {
- char *loprefix;
- char *options;
- char *optpos;
- char *optend;
- const char *next;
- int use_debug;
- char b;
- char *val;
- struct ServiceListeningInfo *sli;
- SOCKTYPE *lsocks;
- unsigned int ls;
- char *binary;
- char *quotedbinary;
- /* calculate listen socket list */
- lsocks = NULL;
- ls = 0;
- for (sli = sl->listen_head; NULL != sli; sli = sli->next)
- {
- GNUNET_array_append (lsocks, ls,
- GNUNET_NETWORK_get_fd (sli->listen_socket));
- if (sli->accept_task != NULL)
- {
- GNUNET_SCHEDULER_cancel (sli->accept_task);
- sli->accept_task = NULL;
- }
- }
- #if WINDOWS
- GNUNET_array_append (lsocks, ls, INVALID_SOCKET);
- #else
- GNUNET_array_append (lsocks, ls, -1);
- #endif
- /* obtain configuration */
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX",
- &loprefix))
- loprefix = GNUNET_strdup (prefix_command);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS",
- &options))
- {
- options = GNUNET_strdup (final_option);
- if (NULL == strstr (options, "%"))
- {
- /* replace '{}' with service name */
- while (NULL != (optpos = strstr (options, "{}")))
- {
- optpos[0] = '%';
- optpos[1] = 's';
- GNUNET_asprintf (&optpos, options, sl->name);
- GNUNET_free (options);
- options = optpos;
- }
- /* replace '$PATH' with value associated with "PATH" */
- while (NULL != (optpos = strstr (options, "$")))
- {
- optend = optpos + 1;
- while (isupper ((unsigned char) *optend))
- optend++;
- b = *optend;
- if ('\0' == b)
- next = "";
- else
- next = optend + 1;
- *optend = '\0';
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
- optpos + 1, &val))
- val = GNUNET_strdup ("");
- *optpos = '\0';
- GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next);
- GNUNET_free (options);
- GNUNET_free (val);
- options = optpos;
- }
- }
- }
- use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG");
- /* actually start process */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting service `%s' using binary `%s' and configuration `%s'\n",
- sl->name, sl->binary, sl->config);
- binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
- GNUNET_asprintf ("edbinary,
- "\"%s\"",
- binary);
- GNUNET_assert (NULL == sl->proc);
- if (GNUNET_YES == use_debug)
- {
- if (NULL == sl->config)
- sl->proc =
- GNUNET_OS_start_process_s (sl->pipe_control,
- GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
- lsocks, loprefix, quotedbinary, "-L",
- "DEBUG", options, NULL);
- else
- sl->proc =
- GNUNET_OS_start_process_s (sl->pipe_control,
- GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
- lsocks, loprefix, quotedbinary, "-c",
- sl->config, "-L",
- "DEBUG", options, NULL);
- }
- else
- {
- if (NULL == sl->config)
- sl->proc =
- GNUNET_OS_start_process_s (sl->pipe_control,
- GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
- lsocks, loprefix, quotedbinary,
- options, NULL);
- else
- sl->proc =
- GNUNET_OS_start_process_s (sl->pipe_control,
- GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
- lsocks, loprefix, quotedbinary, "-c",
- sl->config, options, NULL);
- }
- GNUNET_free (binary);
- GNUNET_free (quotedbinary);
- if (sl->proc == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to start service `%s'\n"),
- sl->name);
- if (client)
- signal_result (client,
- sl->name,
- request_id,
- GNUNET_ARM_RESULT_START_FAILED);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Starting service `%s'\n"),
- sl->name);
- broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
- if (client)
- signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
- }
- /* clean up */
- GNUNET_free (loprefix);
- GNUNET_free (options);
- GNUNET_array_grow (lsocks, ls, 0);
- }
- /**
- * Find the process with the given service
- * name in the given list and return it.
- *
- * @param name which service entry to look up
- * @return NULL if it was not found
- */
- static struct ServiceList *
- find_service (const char *name)
- {
- struct ServiceList *sl;
- sl = running_head;
- while (sl != NULL)
- {
- if (0 == strcasecmp (sl->name, name))
- return sl;
- sl = sl->next;
- }
- return NULL;
- }
- /**
- * First connection has come to the listening socket associated with the service,
- * create the service in order to relay the incoming connection to it
- *
- * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
- * @param tc context
- */
- static void
- accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
- {
- struct ServiceListeningInfo *sli = cls;
- struct ServiceList *sl = sli->sl;
- sli->accept_task = NULL;
- GNUNET_assert (GNUNET_NO == in_shutdown);
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
- start_process (sl, NULL, 0);
- }
- /**
- * Creating a listening socket for each of the service's addresses and
- * wait for the first incoming connection to it
- *
- * @param sa address associated with the service
- * @param addr_len length of @a sa
- * @param sl service entry for the service in question
- */
- static void
- create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
- struct ServiceList *sl)
- {
- static int on = 1;
- struct GNUNET_NETWORK_Handle *sock;
- struct ServiceListeningInfo *sli;
- #ifndef WINDOWS
- int match_uid;
- int match_gid;
- #endif
- switch (sa->sa_family)
- {
- case AF_INET:
- sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
- break;
- case AF_INET6:
- sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
- break;
- case AF_UNIX:
- if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */
- return;
- sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
- break;
- default:
- GNUNET_break (0);
- sock = NULL;
- errno = EAFNOSUPPORT;
- break;
- }
- if (NULL == sock)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Unable to create socket for service `%s': %s\n"),
- sl->name, STRERROR (errno));
- GNUNET_free (sa);
- return;
- }
- if (GNUNET_NETWORK_socket_setsockopt
- (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "setsockopt");
- #ifdef IPV6_V6ONLY
- if ((sa->sa_family == AF_INET6) &&
- (GNUNET_NETWORK_socket_setsockopt
- (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "setsockopt");
- #endif
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _
- ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
- sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
- GNUNET_free (sa);
- return;
- }
- #ifndef WINDOWS
- if ((AF_UNIX == sa->sa_family)
- #ifdef LINUX
- /* Permission settings are not required when abstract sockets are used */
- && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
- #endif
- )
- {
- match_uid =
- GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
- "UNIX_MATCH_UID");
- match_gid =
- GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
- "UNIX_MATCH_GID");
- GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
- match_uid,
- match_gid);
- }
- #endif
- if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
- GNUNET_free (sa);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("ARM now monitors connections to service `%s' at `%s'\n"),
- sl->name, GNUNET_a2s (sa, addr_len));
- sli = GNUNET_new (struct ServiceListeningInfo);
- sli->service_addr = sa;
- sli->service_addr_len = addr_len;
- sli->listen_socket = sock;
- sli->sl = sl;
- sli->accept_task =
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
- &accept_connection, sli);
- GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli);
- }
- /**
- * Remove and free an entry in the service list. Listen sockets
- * must have already been cleaned up. Only to be called during shutdown.
- *
- * @param sl entry to free
- */
- static void
- free_service (struct ServiceList *sl)
- {
- GNUNET_assert (GNUNET_YES == in_shutdown);
- GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl);
- GNUNET_assert (NULL == sl->listen_head);
- GNUNET_free_non_null (sl->config);
- GNUNET_free_non_null (sl->binary);
- GNUNET_free (sl->name);
- GNUNET_free (sl);
- }
- /**
- * Handle START-message.
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- * @return #GNUNET_OK to keep the connection open,
- * #GNUNET_SYSERR to close it (signal serious error)
- */
- static void
- handle_start (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
- {
- const char *servicename;
- struct ServiceList *sl;
- uint16_t size;
- uint64_t request_id;
- struct GNUNET_ARM_Message *amsg;
- amsg = (struct GNUNET_ARM_Message *) message;
- request_id = GNUNET_ntohll (amsg->request_id);
- size = ntohs (amsg->header.size);
- size -= sizeof (struct GNUNET_ARM_Message);
- servicename = (const char *) &amsg[1];
- if ((size == 0) || (servicename[size - 1] != '\0'))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- if (GNUNET_YES == in_shutdown)
- {
- signal_result (client, servicename, request_id,
- GNUNET_ARM_RESULT_IN_SHUTDOWN);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- sl = find_service (servicename);
- if (NULL == sl)
- {
- signal_result (client, servicename, request_id,
- GNUNET_ARM_RESULT_IS_NOT_KNOWN);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- sl->force_start = GNUNET_YES;
- if (NULL != sl->proc)
- {
- signal_result (client, servicename, request_id,
- GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- start_process (sl, client, request_id);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- }
- /**
- * Start a shutdown sequence.
- *
- * @param cls closure (refers to service)
- * @param tc task context
- */
- static void
- trigger_shutdown (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Triggering shutdown\n");
- GNUNET_SCHEDULER_shutdown ();
- }
- /**
- * Handle STOP-message.
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- * @return #GNUNET_OK to keep the connection open,
- * #GNUNET_SYSERR to close it (signal serious error)
- */
- static void
- handle_stop (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
- {
- struct ServiceList *sl;
- const char *servicename;
- uint16_t size;
- uint64_t request_id;
- struct GNUNET_ARM_Message *amsg;
- amsg = (struct GNUNET_ARM_Message *) message;
- request_id = GNUNET_ntohll (amsg->request_id);
- size = ntohs (amsg->header.size);
- size -= sizeof (struct GNUNET_ARM_Message);
- servicename = (const char *) &amsg[1];
- if ((size == 0) || (servicename[size - 1] != '\0'))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Preparing to stop `%s'\n"),
- servicename);
- if (0 == strcasecmp (servicename, "arm"))
- {
- broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
- signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING);
- GNUNET_SERVER_client_persist_ (client);
- GNUNET_SCHEDULER_add_now (trigger_shutdown, NULL);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- sl = find_service (servicename);
- if (sl == NULL)
- {
- signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_NOT_KNOWN);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- sl->force_start = GNUNET_NO;
- if (GNUNET_YES == in_shutdown)
- {
- /* shutdown in progress */
- signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IN_SHUTDOWN);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- if (NULL != sl->killing_client)
- {
- /* killing already in progress */
- signal_result (client, servicename, request_id,
- GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- if (NULL == sl->proc)
- {
- /* process is down */
- signal_result (client, servicename, request_id,
- GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending kill signal to service `%s', waiting for process to die.\n",
- servicename);
- broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
- /* no signal_start - only when it's STOPPED */
- sl->killed_at = GNUNET_TIME_absolute_get ();
- if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
- sl->killing_client = client;
- sl->killing_client_request_id = request_id;
- GNUNET_SERVER_client_keep (client);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- }
- /**
- * Handle LIST-message.
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- */
- static void
- handle_list (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
- {
- struct GNUNET_ARM_ListResultMessage *msg;
- struct GNUNET_ARM_Message *request;
- size_t string_list_size;
- size_t total_size;
- struct ServiceList *sl;
- uint16_t count;
- if (NULL == client)
- return;
- request = (struct GNUNET_ARM_Message *) message;
- GNUNET_break (0 == ntohl (request->reserved));
- count = 0;
- string_list_size = 0;
- /* first count the running processes get their name's size */
- for (sl = running_head; NULL != sl; sl = sl->next)
- {
- if (NULL != sl->proc)
- {
- string_list_size += strlen (sl->name);
- string_list_size += strlen (sl->binary);
- string_list_size += 4;
- count++;
- }
- }
- total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
- + string_list_size;
- msg = GNUNET_malloc (total_size);
- msg->arm_msg.header.size = total_size;
- msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
- msg->arm_msg.reserved = htonl (0);
- msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
- msg->count = count;
- char *pos = (char *)&msg[1];
- for (sl = running_head; NULL != sl; sl = sl->next)
- {
- if (NULL != sl->proc)
- {
- size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
- GNUNET_snprintf (pos, s, "%s (%s)", sl->name, sl->binary);
- pos += s;
- }
- }
- GNUNET_SERVER_notify_transmit_ready (client,
- total_size,
- GNUNET_TIME_UNIT_FOREVER_REL,
- &write_list_result, msg);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- }
- /**
- * We are done with everything. Stop remaining
- * tasks, signal handler and the server.
- */
- static void
- do_shutdown ()
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
- if (NULL != notifier)
- {
- GNUNET_SERVER_notification_context_destroy (notifier);
- notifier = NULL;
- }
- if (NULL != server)
- {
- GNUNET_SERVER_destroy (server);
- server = NULL;
- }
- if (NULL != child_death_task)
- {
- GNUNET_SCHEDULER_cancel (child_death_task);
- child_death_task = NULL;
- }
- }
- /**
- * Count how many services are still active.
- *
- * @param running_head list of services
- * @return number of active services found
- */
- static unsigned int
- list_count (struct ServiceList *running_head)
- {
- struct ServiceList *i;
- unsigned int res = 0;
- for (res = 0, i = running_head; i; i = i->next, res++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s\n",
- i->name);
- return res;
- }
- /**
- * Task run for shutdown.
- *
- * @param cls closure, NULL if we need to self-restart
- * @param tc context
- */
- static void
- shutdown_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
- {
- struct ServiceList *pos;
- struct ServiceList *nxt;
- struct ServiceListeningInfo *sli;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "First shutdown phase\n");
- if (NULL != child_restart_task)
- {
- GNUNET_SCHEDULER_cancel (child_restart_task);
- child_restart_task = NULL;
- }
- in_shutdown = GNUNET_YES;
- /* first, stop listening */
- for (pos = running_head; NULL != pos; pos = pos->next)
- {
- while (NULL != (sli = pos->listen_head))
- {
- GNUNET_CONTAINER_DLL_remove (pos->listen_head,
- pos->listen_tail, sli);
- if (sli->accept_task != NULL)
- {
- GNUNET_SCHEDULER_cancel (sli->accept_task);
- sli->accept_task = NULL;
- }
- GNUNET_break (GNUNET_OK ==
- GNUNET_NETWORK_socket_close (sli->listen_socket));
- GNUNET_free (sli->service_addr);
- GNUNET_free (sli);
- }
- }
- /* then, shutdown all existing service processes */
- nxt = running_head;
- while (NULL != (pos = nxt))
- {
- nxt = pos->next;
- if (pos->proc != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Stopping service `%s'\n",
- pos->name);
- pos->killed_at = GNUNET_TIME_absolute_get ();
- if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
- }
- else
- {
- free_service (pos);
- }
- }
- /* finally, should all service processes be already gone, terminate for real */
- if (running_head == NULL)
- do_shutdown ();
- else
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Delaying shutdown, have %u childs still running\n",
- list_count (running_head));
- }
- /**
- * Task run whenever it is time to restart a child that died.
- *
- * @param cls closure, always NULL
- * @param tc context
- */
- static void
- delayed_restart_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
- {
- struct ServiceList *sl;
- struct GNUNET_TIME_Relative lowestRestartDelay;
- struct ServiceListeningInfo *sli;
- child_restart_task = NULL;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
- GNUNET_assert (GNUNET_NO == in_shutdown);
- lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
- /* check for services that need to be restarted due to
- * configuration changes or because the last restart failed */
- for (sl = running_head; NULL != sl; sl = sl->next)
- {
- if (NULL != sl->proc)
- continue;
- /* service is currently not running */
- if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
- {
- /* restart is now allowed */
- if (sl->force_start)
- {
- /* process should run by default, start immediately */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Restarting service `%s'.\n"),
- sl->name);
- start_process (sl, NULL, 0);
- }
- else
- {
- /* process is run on-demand, ensure it is re-started if there is demand */
- for (sli = sl->listen_head; NULL != sli; sli = sli->next)
- if (NULL == sli->accept_task)
- {
- /* accept was actually paused, so start it again */
- sli->accept_task =
- GNUNET_SCHEDULER_add_read_net
- (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket,
- &accept_connection, sli);
- }
- }
- }
- else
- {
- /* update calculation for earliest time to reactivate a service */
- lowestRestartDelay =
- GNUNET_TIME_relative_min (lowestRestartDelay,
- GNUNET_TIME_absolute_get_remaining
- (sl->restart_at));
- }
- }
- if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Will restart process in %s\n",
- GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
- child_restart_task =
- GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- &delayed_restart_task, NULL);
- }
- }
- /**
- * Task triggered whenever we receive a SIGCHLD (child
- * process died).
- *
- * @param cls closure, NULL if we need to self-restart
- * @param tc context
- */
- static void
- maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
- {
- struct ServiceList *pos;
- struct ServiceList *next;
- struct ServiceListeningInfo *sli;
- const char *statstr;
- int statcode;
- int ret;
- char c[16];
- enum GNUNET_OS_ProcessStatusType statusType;
- unsigned long statusCode;
- const struct GNUNET_DISK_FileHandle *pr;
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- child_death_task = NULL;
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
- {
- /* shutdown scheduled us, ignore! */
- child_death_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr, &maint_child_death, NULL);
- return;
- }
- /* consume the signal */
- GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
- /* check for services that died (WAITPID) */
- next = running_head;
- while (NULL != (pos = next))
- {
- next = pos->next;
- if (pos->proc == NULL)
- {
- if (GNUNET_YES == in_shutdown)
- free_service (pos);
- continue;
- }
- if ((GNUNET_SYSERR ==
- (ret =
- GNUNET_OS_process_status (pos->proc, &statusType, &statusCode)))
- || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED)
- || (statusType == GNUNET_OS_PROCESS_RUNNING)))
- continue;
- if (statusType == GNUNET_OS_PROCESS_EXITED)
- {
- statstr = _( /* process termination method */ "exit");
- statcode = statusCode;
- }
- else if (statusType == GNUNET_OS_PROCESS_SIGNALED)
- {
- statstr = _( /* process termination method */ "signal");
- statcode = statusCode;
- }
- else
- {
- statstr = _( /* process termination method */ "unknown");
- statcode = 0;
- }
- if (0 != pos->killed_at.abs_value_us)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Service `%s' took %s to terminate\n"),
- pos->name,
- GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->killed_at), GNUNET_YES));
- }
- GNUNET_OS_process_destroy (pos->proc);
- pos->proc = NULL;
- broadcast_status (pos->name, GNUNET_ARM_SERVICE_STOPPED, NULL);
- if (NULL != pos->killing_client)
- {
- signal_result (pos->killing_client, pos->name,
- pos->killing_client_request_id, GNUNET_ARM_RESULT_STOPPED);
- GNUNET_SERVER_client_drop (pos->killing_client);
- pos->killing_client = NULL;
- pos->killing_client_request_id = 0;
- }
- if (GNUNET_YES != in_shutdown)
- {
- if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
- {
- /* process terminated normally, allow restart at any time */
- pos->restart_at.abs_value_us = 0;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Service `%s' terminated normally, will restart at any time\n"),
- pos->name);
- /* process can still be re-started on-demand, ensure it is re-started if there is demand */
- for (sli = pos->listen_head; NULL != sli; sli = sli->next)
- {
- GNUNET_break (NULL == sli->accept_task);
- sli->accept_task =
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- sli->listen_socket, &accept_connection, sli);
- }
- }
- else
- {
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
- pos->name, statstr, statcode,
- GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES));
- /* schedule restart */
- pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
- pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
- if (NULL != child_restart_task)
- GNUNET_SCHEDULER_cancel (child_restart_task);
- child_restart_task = GNUNET_SCHEDULER_add_with_priority (
- GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL);
- }
- }
- else
- {
- free_service (pos);
- }
- }
- child_death_task = GNUNET_SCHEDULER_add_read_file (
- GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL);
- if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
- do_shutdown ();
- else if (GNUNET_YES == in_shutdown)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Delaying shutdown after child's death, still have %u children\n",
- list_count (running_head));
- }
- /**
- * Signal handler called for SIGCHLD. Triggers the
- * respective handler by writing to the trigger pipe.
- */
- static void
- sighandler_child_death ()
- {
- static char c;
- int old_errno = errno; /* back-up errno */
- GNUNET_break (1 ==
- GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
- (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno; /* restore errno */
- }
- /**
- * Setup our service record for the given section in the configuration file
- * (assuming the section is for a service).
- *
- * @param cls unused
- * @param section a section in the configuration file
- * @return #GNUNET_OK (continue)
- */
- static void
- setup_service (void *cls, const char *section)
- {
- struct ServiceList *sl;
- char *binary;
- char *config;
- struct stat sbuf;
- struct sockaddr **addrs;
- socklen_t *addr_lens;
- int ret;
- unsigned int i;
- if (strcasecmp (section, "arm") == 0)
- return;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
- {
- /* not a service section */
- return;
- }
- if ((GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (cfg, section, "USER_SERVICE")) &&
- (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "USER_SERVICE")))
- {
- if (GNUNET_NO == start_user)
- {
- GNUNET_free (binary);
- return; /* user service, and we don't deal with those */
- }
- }
- else
- {
- if (GNUNET_NO == start_system)
- {
- GNUNET_free (binary);
- return; /* system service, and we don't deal with those */
- }
- }
- sl = find_service (section);
- if (NULL != sl)
- {
- /* got the same section twice!? */
- GNUNET_break (0);
- GNUNET_free (binary);
- return;
- }
- config = NULL;
- if (( (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG",
- &config)) &&
- (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", "DEFAULTCONFIG",
- &config)) ) ||
- (0 != STAT (config, &sbuf)))
- {
- if (NULL != config)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- section, "CONFIG",
- STRERROR (errno));
- GNUNET_free (config);
- config = NULL;
- }
- }
- sl = GNUNET_new (struct ServiceList);
- sl->name = GNUNET_strdup (section);
- sl->binary = binary;
- sl->config = config;
- sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
- sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS;
- #if WINDOWS
- sl->pipe_control = GNUNET_YES;
- #else
- if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
- sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
- #endif
- GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "FORCESTART"))
- {
- sl->force_start = GNUNET_YES;
- return;
- }
- else
- {
- if (GNUNET_YES !=
- GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
- return;
- }
- if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg,
- &addrs, &addr_lens)))
- return;
- /* this will free (or capture) addrs[i] */
- for (i = 0; i < ret; i++)
- create_listen_socket (addrs[i], addr_lens[i], sl);
- GNUNET_free (addrs);
- GNUNET_free (addr_lens);
- }
- /**
- * A client connected, add it to the notification context.
- *
- * @param cls closure
- * @param client identification of the client
- */
- static void
- handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client)
- {
- /* All clients are considered to be of the "monitor" kind
- * (that is, they don't affect ARM shutdown).
- */
- if (NULL != client)
- GNUNET_SERVER_client_mark_monitor (client);
- }
- /**
- * Handle MONITOR-message.
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- * @return #GNUNET_OK to keep the connection open,
- * #GNUNET_SYSERR to close it (signal serious error)
- */
- static void
- handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
- {
- /* Removal is handled by the server implementation, internally. */
- if ((NULL != client) && (NULL != notifier))
- {
- GNUNET_SERVER_notification_context_add (notifier, client);
- broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- }
- }
- /**
- * Process arm requests.
- *
- * @param cls closure
- * @param serv the initialized server
- * @param c configuration to use
- */
- static void
- run (void *cls, struct GNUNET_SERVER_Handle *serv,
- const struct GNUNET_CONFIGURATION_Handle *c)
- {
- static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
- {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
- {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR,
- sizeof (struct GNUNET_MessageHeader)},
- {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
- sizeof (struct GNUNET_ARM_Message)},
- {NULL, NULL, 0, 0}
- };
- struct ServiceList *sl;
- cfg = c;
- server = serv;
- GNUNET_assert (NULL != serv);
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &shutdown_task,
- NULL);
- child_death_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ),
- &maint_child_death, NULL);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX",
- &prefix_command))
- prefix_command = GNUNET_strdup ("");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
- &final_option))
- final_option = GNUNET_strdup ("");
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "USER_ONLY"))
- {
- GNUNET_break (GNUNET_YES == start_user);
- start_system = GNUNET_NO;
- }
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg, "ARM", "SYSTEM_ONLY"))
- {
- GNUNET_break (GNUNET_YES == start_system);
- start_user = GNUNET_NO;
- }
- GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
- /* start default services... */
- for (sl = running_head; NULL != sl; sl = sl->next)
- if (GNUNET_YES == sl->force_start)
- start_process (sl, NULL, 0);
- notifier
- = GNUNET_SERVER_notification_context_create (server,
- MAX_NOTIFY_QUEUE);
- GNUNET_SERVER_connect_notify (server,
- &handle_client_connecting, NULL);
- /* process client requests */
- GNUNET_SERVER_add_handlers (server,
- handlers);
- }
- /**
- * The main function for the arm service.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
- int
- main (int argc, char *const *argv)
- {
- int ret;
- struct GNUNET_SIGNAL_Context *shc_chld;
- sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
- GNUNET_assert (sigpipe != NULL);
- shc_chld =
- GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
- ret =
- (GNUNET_OK ==
- GNUNET_SERVICE_run (argc, argv, "arm",
- GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
- GNUNET_SIGNAL_handler_uninstall (shc_chld);
- shc_chld = NULL;
- GNUNET_DISK_pipe_close (sigpipe);
- sigpipe = NULL;
- return ret;
- }
- #ifdef LINUX
- #include <malloc.h>
- /**
- * MINIMIZE heap size (way below 128k) since this process doesn't need much.
- */
- void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
- {
- mallopt (M_TRIM_THRESHOLD, 4 * 1024);
- mallopt (M_TOP_PAD, 1 * 1024);
- malloc_trim (0);
- }
- #endif
- /* end of gnunet-service-arm.c */
|