error handling
[oweals/gnunet.git] / src / transport / tcp_service_legacy.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file util/service.c
23  * @brief functions related to starting services
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_resolver_service.h"
31
32 #if HAVE_MALLINFO
33 #include <malloc.h>
34 #include "gauger.h"
35 #endif
36
37
38 /* ******************* access control ******************** */
39
40 /**
41  * Check if the given IP address is in the list of IP addresses.
42  *
43  * @param list a list of networks
44  * @param add the IP to check (in network byte order)
45  * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
46  */
47 static int
48 check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
49                    const struct in_addr *add)
50 {
51   unsigned int i;
52
53   if (NULL == list)
54     return GNUNET_NO;
55   i = 0;
56   while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
57   {
58     if ((add->s_addr & list[i].netmask.s_addr) ==
59         (list[i].network.s_addr & list[i].netmask.s_addr))
60       return GNUNET_YES;
61     i++;
62   }
63   return GNUNET_NO;
64 }
65
66
67 /**
68  * Check if the given IP address is in the list of IP addresses.
69  *
70  * @param list a list of networks
71  * @param ip the IP to check (in network byte order)
72  * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
73  */
74 static int
75 check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
76                    const struct in6_addr *ip)
77 {
78   unsigned int i;
79   unsigned int j;
80   struct in6_addr zero;
81
82   if (NULL == list)
83     return GNUNET_NO;
84   memset (&zero, 0, sizeof(struct in6_addr));
85   i = 0;
86 NEXT:
87   while (0 != memcmp (&zero, &list[i].network, sizeof(struct in6_addr)))
88   {
89     for (j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
90       if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
91           (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
92       {
93         i++;
94         goto NEXT;
95       }
96     return GNUNET_YES;
97   }
98   return GNUNET_NO;
99 }
100
101
102 /* ****************** service struct ****************** */
103
104
105 /**
106  * Context for "service_task".
107  */
108 struct LEGACY_SERVICE_Context
109 {
110   /**
111    * Our configuration.
112    */
113   const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115   /**
116    * Handle for the server.
117    */
118   struct GNUNET_SERVER_Handle *server;
119
120   /**
121    * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
122    * listen sockets.
123    */
124   struct sockaddr **addrs;
125
126   /**
127    * Name of our service.
128    */
129   const char *service_name;
130
131   /**
132    * Main service-specific task to run.
133    */
134   LEGACY_SERVICE_Main task;
135
136   /**
137    * Closure for @e task.
138    */
139   void *task_cls;
140
141   /**
142    * IPv4 addresses that are not allowed to connect.
143    */
144   struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
145
146   /**
147    * IPv6 addresses that are not allowed to connect.
148    */
149   struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
150
151   /**
152    * IPv4 addresses that are allowed to connect (if not
153    * set, all are allowed).
154    */
155   struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
156
157   /**
158    * IPv6 addresses that are allowed to connect (if not
159    * set, all are allowed).
160    */
161   struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
162
163   /**
164    * My (default) message handlers.  Adjusted copy
165    * of "defhandlers".
166    */
167   struct GNUNET_SERVER_MessageHandler *my_handlers;
168
169   /**
170    * Array of the lengths of the entries in addrs.
171    */
172   socklen_t *addrlens;
173
174   /**
175    * NULL-terminated array of listen sockets we should take over.
176    */
177   struct GNUNET_NETWORK_Handle **lsocks;
178
179   /**
180    * Task ID of the shutdown task.
181    */
182   struct GNUNET_SCHEDULER_Task *shutdown_task;
183
184   /**
185    * Idle timeout for server.
186    */
187   struct GNUNET_TIME_Relative timeout;
188
189   /**
190    * Overall success/failure of the service start.
191    */
192   int ret;
193
194   /**
195    * If we are daemonizing, this FD is set to the
196    * pipe to the parent.  Send '.' if we started
197    * ok, '!' if not.  -1 if we are not daemonizing.
198    */
199   int ready_confirm_fd;
200
201   /**
202    * Do we close connections if we receive messages
203    * for which we have no handler?
204    */
205   int require_found;
206
207   /**
208    * Do we require a matching UID for UNIX domain socket connections?
209    * #GNUNET_NO means that the UID does not have to match (however,
210    * @e match_gid may still impose other access control checks).
211    */
212   int match_uid;
213
214   /**
215    * Do we require a matching GID for UNIX domain socket connections?
216    * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
217    * checking that the client's UID is in our group OR that the
218    * client's GID is our GID.  If both "match_gid" and @e match_uid are
219    * #GNUNET_NO, all users on the local system have access.
220    */
221   int match_gid;
222
223   /**
224    * Our options.
225    */
226   enum LEGACY_SERVICE_Options options;
227 };
228
229
230 /* ****************** message handlers ****************** */
231
232 /**
233  * Send a 'TEST' message back to the client.
234  *
235  * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
236  * @param size number of bytes available in 'buf'
237  * @param buf where to copy the message
238  * @return number of bytes written to 'buf'
239  */
240 static size_t
241 write_test (void *cls, size_t size, void *buf)
242 {
243   struct GNUNET_SERVER_Client *client = cls;
244   struct GNUNET_MessageHeader *msg;
245
246   if (size < sizeof(struct GNUNET_MessageHeader))
247   {
248     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
249     return 0;   /* client disconnected */
250   }
251   msg = (struct GNUNET_MessageHeader *) buf;
252   msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
253   msg->size = htons (sizeof(struct GNUNET_MessageHeader));
254   GNUNET_SERVER_receive_done (client, GNUNET_OK);
255   return sizeof(struct GNUNET_MessageHeader);
256 }
257
258
259 /**
260  * Handler for TEST message.
261  *
262  * @param cls closure (refers to service)
263  * @param client identification of the client
264  * @param message the actual message
265  */
266 static void
267 handle_test (void *cls,
268              struct GNUNET_SERVER_Client *client,
269              const struct GNUNET_MessageHeader *message)
270 {
271   /* simply bounce message back to acknowledge */
272   if (NULL ==
273       GNUNET_SERVER_notify_transmit_ready (client,
274                                            sizeof(struct GNUNET_MessageHeader),
275                                            GNUNET_TIME_UNIT_FOREVER_REL,
276                                            &write_test,
277                                            client))
278     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
279 }
280
281
282 /**
283  * Default handlers for all services.  Will be copied and the
284  * "callback_cls" fields will be replaced with the specific service
285  * struct.
286  */
287 static const struct GNUNET_SERVER_MessageHandler defhandlers[] =
288 { { &handle_test,
289     NULL,
290     GNUNET_MESSAGE_TYPE_TEST,
291     sizeof(struct GNUNET_MessageHeader) },
292   { NULL, NULL, 0, 0 } };
293
294
295 /* ****************** service core routines ************** */
296
297
298 /**
299  * Check if access to the service is allowed from the given address.
300  *
301  * @param cls closure
302  * @param uc credentials, if available, otherwise NULL
303  * @param addr address
304  * @param addrlen length of address
305  * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
306  *   for unknown address family (will be denied).
307  */
308 static int
309 check_access (void *cls,
310               const struct GNUNET_CONNECTION_Credentials *uc,
311               const struct sockaddr *addr,
312               socklen_t addrlen)
313 {
314   struct LEGACY_SERVICE_Context *sctx = cls;
315   const struct sockaddr_in *i4;
316   const struct sockaddr_in6 *i6;
317   int ret;
318
319   switch (addr->sa_family)
320   {
321   case AF_INET:
322     GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
323     i4 = (const struct sockaddr_in *) addr;
324     ret = ((NULL == sctx->v4_allowed) ||
325            (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
326           ((NULL == sctx->v4_denied) ||
327            (! check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
328     break;
329
330   case AF_INET6:
331     GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
332     i6 = (const struct sockaddr_in6 *) addr;
333     ret = ((NULL == sctx->v6_allowed) ||
334            (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
335           ((NULL == sctx->v6_denied) ||
336            (! check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
337     break;
338
339   case AF_UNIX:
340     ret = GNUNET_OK;   /* controlled using file-system ACL now */
341     break;
342
343   default:
344     LOG (GNUNET_ERROR_TYPE_WARNING,
345          _ ("Unknown address family %d\n"),
346          addr->sa_family);
347     return GNUNET_SYSERR;
348   }
349   if (GNUNET_OK != ret)
350   {
351     LOG (GNUNET_ERROR_TYPE_WARNING,
352          _ ("Access from `%s' denied to service `%s'\n"),
353          GNUNET_a2s (addr, addrlen),
354          sctx->service_name);
355   }
356   return ret;
357 }
358
359
360 /**
361  * Get the name of the file where we will
362  * write the PID of the service.
363  *
364  * @param sctx service context
365  * @return name of the file for the process ID
366  */
367 static char *
368 get_pid_file_name (struct LEGACY_SERVICE_Context *sctx)
369 {
370   char *pif;
371
372   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
373                                                             sctx->service_name,
374                                                             "PIDFILE",
375                                                             &pif))
376     return NULL;
377   return pif;
378 }
379
380
381 /**
382  * Parse an IPv4 access control list.
383  *
384  * @param ret location where to write the ACL (set)
385  * @param sctx service context to use to get the configuration
386  * @param option name of the ACL option to parse
387  * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
388  *         no ACL configured)
389  */
390 static int
391 process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
392               struct LEGACY_SERVICE_Context *sctx,
393               const char *option)
394 {
395   char *opt;
396
397   if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
398   {
399     *ret = NULL;
400     return GNUNET_OK;
401   }
402   GNUNET_break (GNUNET_OK ==
403                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
404                                                        sctx->service_name,
405                                                        option,
406                                                        &opt));
407   if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
408   {
409     LOG (GNUNET_ERROR_TYPE_WARNING,
410          _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
411          opt,
412          sctx->service_name,
413          option);
414     GNUNET_free (opt);
415     return GNUNET_SYSERR;
416   }
417   GNUNET_free (opt);
418   return GNUNET_OK;
419 }
420
421
422 /**
423  * Parse an IPv6 access control list.
424  *
425  * @param ret location where to write the ACL (set)
426  * @param sctx service context to use to get the configuration
427  * @param option name of the ACL option to parse
428  * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
429  *         no ACL configured)
430  */
431 static int
432 process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
433               struct LEGACY_SERVICE_Context *sctx,
434               const char *option)
435 {
436   char *opt;
437
438   if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
439   {
440     *ret = NULL;
441     return GNUNET_OK;
442   }
443   GNUNET_break (GNUNET_OK ==
444                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
445                                                        sctx->service_name,
446                                                        option,
447                                                        &opt));
448   if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
449   {
450     LOG (GNUNET_ERROR_TYPE_WARNING,
451          _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
452          opt,
453          sctx->service_name,
454          option);
455     GNUNET_free (opt);
456     return GNUNET_SYSERR;
457   }
458   GNUNET_free (opt);
459   return GNUNET_OK;
460 }
461
462
463 /**
464  * Add the given UNIX domain path as an address to the
465  * list (as the first entry).
466  *
467  * @param saddrs array to update
468  * @param saddrlens where to store the address length
469  * @param unixpath path to add
470  * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
471  *          parameter is ignore on systems other than LINUX
472  */
473 static void
474 add_unixpath (struct sockaddr **saddrs,
475               socklen_t *saddrlens,
476               const char *unixpath,
477               int abstract)
478 {
479 #ifdef AF_UNIX
480   struct sockaddr_un *un;
481
482   un = GNUNET_new (struct sockaddr_un);
483   un->sun_family = AF_UNIX;
484   GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
485 #ifdef __linux__
486   if (GNUNET_YES == abstract)
487     un->sun_path[0] = '\0';
488 #endif
489 #if HAVE_SOCKADDR_UN_SUN_LEN
490   un->sun_len = (u_char) sizeof(struct sockaddr_un);
491 #endif
492   *saddrs = (struct sockaddr *) un;
493   *saddrlens = sizeof(struct sockaddr_un);
494 #else
495   /* this function should never be called
496    * unless AF_UNIX is defined! */
497   GNUNET_assert (0);
498 #endif
499 }
500
501
502 /**
503  * Get the list of addresses that a server for the given service
504  * should bind to.
505  *
506  * @param service_name name of the service
507  * @param cfg configuration (which specifies the addresses)
508  * @param addrs set (call by reference) to an array of pointers to the
509  *              addresses the server should bind to and listen on; the
510  *              array will be NULL-terminated (on success)
511  * @param addr_lens set (call by reference) to an array of the lengths
512  *              of the respective `struct sockaddr` struct in the @a addrs
513  *              array (on success)
514  * @return number of addresses found on success,
515  *              #GNUNET_SYSERR if the configuration
516  *              did not specify reasonable finding information or
517  *              if it specified a hostname that could not be resolved;
518  *              #GNUNET_NO if the number of addresses configured is
519  *              zero (in this case, `*addrs` and `*addr_lens` will be
520  *              set to NULL).
521  */
522 int
523 LEGACY_SERVICE_get_server_addresses (
524   const char *service_name,
525   const struct GNUNET_CONFIGURATION_Handle *cfg,
526   struct sockaddr ***addrs,
527   socklen_t **addr_lens)
528 {
529   int disablev6;
530   struct GNUNET_NETWORK_Handle *desc;
531   unsigned long long port;
532   char *unixpath;
533   struct addrinfo hints;
534   struct addrinfo *res;
535   struct addrinfo *pos;
536   struct addrinfo *next;
537   unsigned int i;
538   int resi;
539   int ret;
540   int abstract;
541   struct sockaddr **saddrs;
542   socklen_t *saddrlens;
543   char *hostname;
544
545   *addrs = NULL;
546   *addr_lens = NULL;
547   desc = NULL;
548   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
549   {
550     if (GNUNET_SYSERR ==
551         (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
552                                                            service_name,
553                                                            "DISABLEV6")))
554       return GNUNET_SYSERR;
555   }
556   else
557     disablev6 = GNUNET_NO;
558
559   if (! disablev6)
560   {
561     /* probe IPv6 support */
562     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
563     if (NULL == desc)
564     {
565       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
566           (EACCES == errno))
567       {
568         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
569         return GNUNET_SYSERR;
570       }
571       LOG (GNUNET_ERROR_TYPE_INFO,
572            _ (
573              "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
574            service_name,
575            strerror (errno));
576       disablev6 = GNUNET_YES;
577     }
578     else
579     {
580       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
581       desc = NULL;
582     }
583   }
584
585   port = 0;
586   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
587   {
588     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
589                                                             service_name,
590                                                             "PORT",
591                                                             &port))
592     {
593       LOG (GNUNET_ERROR_TYPE_ERROR,
594            _ ("Require valid port number for service `%s' in configuration!\n"),
595            service_name);
596     }
597     if (port > 65535)
598     {
599       LOG (GNUNET_ERROR_TYPE_ERROR,
600            _ ("Require valid port number for service `%s' in configuration!\n"),
601            service_name);
602       return GNUNET_SYSERR;
603     }
604   }
605
606   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
607   {
608     GNUNET_break (GNUNET_OK ==
609                   GNUNET_CONFIGURATION_get_value_string (cfg,
610                                                          service_name,
611                                                          "BINDTO",
612                                                          &hostname));
613   }
614   else
615     hostname = NULL;
616
617   unixpath = NULL;
618   abstract = GNUNET_NO;
619 #ifdef AF_UNIX
620   if ((GNUNET_YES ==
621        GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
622       (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
623                                                              service_name,
624                                                              "UNIXPATH",
625                                                              &unixpath)) &&
626       (0 < strlen (unixpath)))
627   {
628     /* probe UNIX support */
629     struct sockaddr_un s_un;
630
631     if (strlen (unixpath) >= sizeof(s_un.sun_path))
632     {
633       LOG (GNUNET_ERROR_TYPE_WARNING,
634            _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
635            unixpath,
636            (unsigned long long) sizeof(s_un.sun_path));
637       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
638       LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
639     }
640 #ifdef __linux__
641     abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
642                                                      "TESTING",
643                                                      "USE_ABSTRACT_SOCKETS");
644     if (GNUNET_SYSERR == abstract)
645       abstract = GNUNET_NO;
646 #endif
647     if ((GNUNET_YES != abstract) &&
648         (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
649       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
650   }
651   if (NULL != unixpath)
652   {
653     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
654     if (NULL == desc)
655     {
656       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
657           (EACCES == errno))
658       {
659         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
660         GNUNET_free_non_null (hostname);
661         GNUNET_free (unixpath);
662         return GNUNET_SYSERR;
663       }
664       LOG (GNUNET_ERROR_TYPE_INFO,
665            _ (
666              "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
667            service_name,
668            strerror (errno));
669       GNUNET_free (unixpath);
670       unixpath = NULL;
671     }
672     else
673     {
674       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
675       desc = NULL;
676     }
677   }
678 #endif
679
680   if ((0 == port) && (NULL == unixpath))
681   {
682     LOG (GNUNET_ERROR_TYPE_ERROR,
683          _ (
684            "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
685          service_name);
686     GNUNET_free_non_null (hostname);
687     return GNUNET_SYSERR;
688   }
689   if (0 == port)
690   {
691     saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
692     saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
693     add_unixpath (saddrs, saddrlens, unixpath, abstract);
694     GNUNET_free_non_null (unixpath);
695     GNUNET_free_non_null (hostname);
696     *addrs = saddrs;
697     *addr_lens = saddrlens;
698     return 1;
699   }
700
701   if (NULL != hostname)
702   {
703     LOG (GNUNET_ERROR_TYPE_DEBUG,
704          "Resolving `%s' since that is where `%s' will bind to.\n",
705          hostname,
706          service_name);
707     memset (&hints, 0, sizeof(struct addrinfo));
708     if (disablev6)
709       hints.ai_family = AF_INET;
710     hints.ai_protocol = IPPROTO_TCP;
711     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
712         (NULL == res))
713     {
714       LOG (GNUNET_ERROR_TYPE_ERROR,
715            _ ("Failed to resolve `%s': %s\n"),
716            hostname,
717            gai_strerror (ret));
718       GNUNET_free (hostname);
719       GNUNET_free_non_null (unixpath);
720       return GNUNET_SYSERR;
721     }
722     next = res;
723     i = 0;
724     while (NULL != (pos = next))
725     {
726       next = pos->ai_next;
727       if ((disablev6) && (pos->ai_family == AF_INET6))
728         continue;
729       i++;
730     }
731     if (0 == i)
732     {
733       LOG (GNUNET_ERROR_TYPE_ERROR,
734            _ ("Failed to find %saddress for `%s'.\n"),
735            disablev6 ? "IPv4 " : "",
736            hostname);
737       freeaddrinfo (res);
738       GNUNET_free (hostname);
739       GNUNET_free_non_null (unixpath);
740       return GNUNET_SYSERR;
741     }
742     resi = i;
743     if (NULL != unixpath)
744       resi++;
745     saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
746     saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
747     i = 0;
748     if (NULL != unixpath)
749     {
750       add_unixpath (saddrs, saddrlens, unixpath, abstract);
751       i++;
752     }
753     next = res;
754     while (NULL != (pos = next))
755     {
756       next = pos->ai_next;
757       if ((disablev6) && (AF_INET6 == pos->ai_family))
758         continue;
759       if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
760         continue;     /* not TCP */
761       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
762         continue;     /* huh? */
763       LOG (GNUNET_ERROR_TYPE_DEBUG,
764            "Service `%s' will bind to `%s'\n",
765            service_name,
766            GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
767       if (AF_INET == pos->ai_family)
768       {
769         GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
770         saddrlens[i] = pos->ai_addrlen;
771         saddrs[i] = GNUNET_malloc (saddrlens[i]);
772         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
773         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
774       }
775       else
776       {
777         GNUNET_assert (AF_INET6 == pos->ai_family);
778         GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
779         saddrlens[i] = pos->ai_addrlen;
780         saddrs[i] = GNUNET_malloc (saddrlens[i]);
781         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
782         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
783       }
784       i++;
785     }
786     GNUNET_free (hostname);
787     freeaddrinfo (res);
788     resi = i;
789   }
790   else
791   {
792     /* will bind against everything, just set port */
793     if (disablev6)
794     {
795       /* V4-only */
796       resi = 1;
797       if (NULL != unixpath)
798         resi++;
799       i = 0;
800       saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
801       saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
802       if (NULL != unixpath)
803       {
804         add_unixpath (saddrs, saddrlens, unixpath, abstract);
805         i++;
806       }
807       saddrlens[i] = sizeof(struct sockaddr_in);
808       saddrs[i] = GNUNET_malloc (saddrlens[i]);
809 #if HAVE_SOCKADDR_IN_SIN_LEN
810       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
811 #endif
812       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
813       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
814     }
815     else
816     {
817       /* dual stack */
818       resi = 2;
819       if (NULL != unixpath)
820         resi++;
821       saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
822       saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
823       i = 0;
824       if (NULL != unixpath)
825       {
826         add_unixpath (saddrs, saddrlens, unixpath, abstract);
827         i++;
828       }
829       saddrlens[i] = sizeof(struct sockaddr_in6);
830       saddrs[i] = GNUNET_malloc (saddrlens[i]);
831 #if HAVE_SOCKADDR_IN_SIN_LEN
832       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
833 #endif
834       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
835       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
836       i++;
837       saddrlens[i] = sizeof(struct sockaddr_in);
838       saddrs[i] = GNUNET_malloc (saddrlens[i]);
839 #if HAVE_SOCKADDR_IN_SIN_LEN
840       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
841 #endif
842       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
843       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
844     }
845   }
846   GNUNET_free_non_null (unixpath);
847   *addrs = saddrs;
848   *addr_lens = saddrlens;
849   return resi;
850 }
851
852
853 /**
854  * Setup addr, addrlen, idle_timeout
855  * based on configuration!
856  *
857  * Configuration may specify:
858  * - PORT (where to bind to for TCP)
859  * - UNIXPATH (where to bind to for UNIX domain sockets)
860  * - TIMEOUT (after how many ms does an inactive service timeout);
861  * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
862  * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
863  * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
864  * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
865  * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
866  * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
867  *
868  * @param sctx service context to initialize
869  * @return #GNUNET_OK if configuration succeeded
870  */
871 static int
872 setup_service (struct LEGACY_SERVICE_Context *sctx)
873 {
874   struct GNUNET_TIME_Relative idleout;
875   int tolerant;
876   const char *nfds;
877   unsigned int cnt;
878   int flags;
879
880   if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
881                                        sctx->service_name,
882                                        "TIMEOUT"))
883   {
884     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg,
885                                                           sctx->service_name,
886                                                           "TIMEOUT",
887                                                           &idleout))
888     {
889       LOG (GNUNET_ERROR_TYPE_ERROR,
890            _ ("Specified value for `%s' of service `%s' is invalid\n"),
891            "TIMEOUT",
892            sctx->service_name);
893       return GNUNET_SYSERR;
894     }
895     sctx->timeout = idleout;
896   }
897   else
898     sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
899
900   if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
901                                        sctx->service_name,
902                                        "TOLERANT"))
903   {
904     if (GNUNET_SYSERR ==
905         (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
906                                                           sctx->service_name,
907                                                           "TOLERANT")))
908     {
909       LOG (GNUNET_ERROR_TYPE_ERROR,
910            _ ("Specified value for `%s' of service `%s' is invalid\n"),
911            "TOLERANT",
912            sctx->service_name);
913       return GNUNET_SYSERR;
914     }
915   }
916   else
917     tolerant = GNUNET_NO;
918
919   errno = 0;
920   if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
921       (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
922       (cnt + 4 < FD_SETSIZE))
923   {
924     sctx->lsocks =
925       GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle *) * (cnt + 1));
926     while (0 < cnt--)
927     {
928       flags = fcntl (3 + cnt, F_GETFD);
929       if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
930           (NULL ==
931            (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
932       {
933         LOG (GNUNET_ERROR_TYPE_ERROR,
934              _ (
935                "Could not access pre-bound socket %u, will try to bind myself\n"),
936              (unsigned int) 3 + cnt);
937         cnt++;
938         while (sctx->lsocks[cnt] != NULL)
939           GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
940         GNUNET_free (sctx->lsocks);
941         sctx->lsocks = NULL;
942         break;
943       }
944     }
945     unsetenv ("LISTEN_FDS");
946   }
947
948   if ((NULL == sctx->lsocks) &&
949       (GNUNET_SYSERR == LEGACY_SERVICE_get_server_addresses (sctx->service_name,
950                                                              sctx->cfg,
951                                                              &sctx->addrs,
952                                                              &sctx->addrlens)))
953     return GNUNET_SYSERR;
954   sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
955   sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
956                                                           sctx->service_name,
957                                                           "UNIX_MATCH_UID");
958   sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
959                                                           sctx->service_name,
960                                                           "UNIX_MATCH_GID");
961   process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
962   process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
963   process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
964   process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
965
966   return GNUNET_OK;
967 }
968
969
970 /**
971  * Get the name of the user that'll be used
972  * to provide the service.
973  *
974  * @param sctx service context
975  * @return value of the 'USERNAME' option
976  */
977 static char *
978 get_user_name (struct LEGACY_SERVICE_Context *sctx)
979 {
980   char *un;
981
982   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
983                                                             sctx->service_name,
984                                                             "USERNAME",
985                                                             &un))
986     return NULL;
987   return un;
988 }
989
990
991 /**
992  * Write PID file.
993  *
994  * @param sctx service context
995  * @param pid PID to write (should be equal to 'getpid()'
996  * @return  #GNUNET_OK on success (including no work to be done)
997  */
998 static int
999 write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid)
1000 {
1001   FILE *pidfd;
1002   char *pif;
1003   char *user;
1004   char *rdir;
1005   int len;
1006
1007   if (NULL == (pif = get_pid_file_name (sctx)))
1008     return GNUNET_OK; /* no file desired */
1009   user = get_user_name (sctx);
1010   rdir = GNUNET_strdup (pif);
1011   len = strlen (rdir);
1012   while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1013     len--;
1014   rdir[len] = '\0';
1015   if (0 != access (rdir, F_OK))
1016   {
1017     /* we get to create a directory -- and claim it
1018      * as ours! */
1019     (void) GNUNET_DISK_directory_create (rdir);
1020     if ((NULL != user) && (0 < strlen (user)))
1021       GNUNET_DISK_file_change_owner (rdir, user);
1022   }
1023   if (0 != access (rdir, W_OK | X_OK))
1024   {
1025     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1026     GNUNET_free (rdir);
1027     GNUNET_free_non_null (user);
1028     GNUNET_free (pif);
1029     return GNUNET_SYSERR;
1030   }
1031   GNUNET_free (rdir);
1032   pidfd = fopen (pif, "w");
1033   if (NULL == pidfd)
1034   {
1035     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1036     GNUNET_free (pif);
1037     GNUNET_free_non_null (user);
1038     return GNUNET_SYSERR;
1039   }
1040   if (0 > fprintf (pidfd, "%u", pid))
1041     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1042   GNUNET_break (0 == fclose (pidfd));
1043   if ((NULL != user) && (0 < strlen (user)))
1044     GNUNET_DISK_file_change_owner (pif, user);
1045   GNUNET_free_non_null (user);
1046   GNUNET_free (pif);
1047   return GNUNET_OK;
1048 }
1049
1050
1051 /**
1052  * Task run during shutdown.  Stops the server/service.
1053  *
1054  * @param cls the `struct LEGACY_SERVICE_Context`
1055  */
1056 static void
1057 shutdown_task (void *cls)
1058 {
1059   struct LEGACY_SERVICE_Context *service = cls;
1060   struct GNUNET_SERVER_Handle *server = service->server;
1061
1062   service->shutdown_task = NULL;
1063   if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN))
1064     GNUNET_SERVER_stop_listening (server);
1065   else
1066     GNUNET_SERVER_destroy (server);
1067 }
1068
1069
1070 /**
1071  * Initial task for the service.
1072  *
1073  * @param cls service context
1074  */
1075 static void
1076 service_task (void *cls)
1077 {
1078   struct LEGACY_SERVICE_Context *sctx = cls;
1079   unsigned int i;
1080
1081   GNUNET_RESOLVER_connect (sctx->cfg);
1082   if (NULL != sctx->lsocks)
1083     sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1084                                                       sctx,
1085                                                       sctx->lsocks,
1086                                                       sctx->timeout,
1087                                                       sctx->require_found);
1088   else
1089     sctx->server = GNUNET_SERVER_create (&check_access,
1090                                          sctx,
1091                                          sctx->addrs,
1092                                          sctx->addrlens,
1093                                          sctx->timeout,
1094                                          sctx->require_found);
1095   if (NULL == sctx->server)
1096   {
1097     if (NULL != sctx->addrs)
1098       for (i = 0; NULL != sctx->addrs[i]; i++)
1099         LOG (GNUNET_ERROR_TYPE_INFO,
1100              _ ("Failed to start `%s' at `%s'\n"),
1101              sctx->service_name,
1102              GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1103     sctx->ret = GNUNET_SYSERR;
1104     return;
1105   }
1106
1107   if (NULL != sctx->addrs)
1108     for (i = 0; NULL != sctx->addrs[i]; i++)
1109       if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1110           ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1111         GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1112                                       sctx->addrs[i])
1113                                      ->sun_path,
1114                                      sctx->match_uid,
1115                                      sctx->match_gid);
1116
1117   if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN))
1118   {
1119     /* install a task that will kill the server
1120      * process if the scheduler ever gets a shutdown signal */
1121     sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, sctx);
1122   }
1123   sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1124   GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1125   i = 0;
1126   while (NULL != sctx->my_handlers[i].callback)
1127     sctx->my_handlers[i++].callback_cls = sctx;
1128   GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1129   if (-1 != sctx->ready_confirm_fd)
1130   {
1131     GNUNET_break (1 == write (sctx->ready_confirm_fd, ".", 1));
1132     GNUNET_break (0 == close (sctx->ready_confirm_fd));
1133     sctx->ready_confirm_fd = -1;
1134     write_pid_file (sctx, getpid ());
1135   }
1136   if (NULL != sctx->addrs)
1137   {
1138     i = 0;
1139     while (NULL != sctx->addrs[i])
1140     {
1141       LOG (GNUNET_ERROR_TYPE_INFO,
1142            _ ("Service `%s' runs at %s\n"),
1143            sctx->service_name,
1144            GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1145       i++;
1146     }
1147   }
1148   sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1149 }
1150
1151
1152 /**
1153  * Detach from terminal.
1154  *
1155  * @param sctx service context
1156  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1157  */
1158 static int
1159 detach_terminal (struct LEGACY_SERVICE_Context *sctx)
1160 {
1161   pid_t pid;
1162   int nullfd;
1163   int filedes[2];
1164
1165   if (0 != pipe (filedes))
1166   {
1167     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1168     return GNUNET_SYSERR;
1169   }
1170   pid = fork ();
1171   if (pid < 0)
1172   {
1173     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1174     return GNUNET_SYSERR;
1175   }
1176   if (0 != pid)
1177   {
1178     /* Parent */
1179     char c;
1180
1181     GNUNET_break (0 == close (filedes[1]));
1182     c = 'X';
1183     if (1 != read (filedes[0], &c, sizeof(char)))
1184       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1185     fflush (stdout);
1186     switch (c)
1187     {
1188     case '.':
1189       exit (0);
1190
1191     case 'I':
1192       LOG (GNUNET_ERROR_TYPE_INFO,
1193            _ ("Service process failed to initialize\n"));
1194       break;
1195
1196     case 'S':
1197       LOG (GNUNET_ERROR_TYPE_INFO,
1198            _ ("Service process could not initialize server function\n"));
1199       break;
1200
1201     case 'X':
1202       LOG (GNUNET_ERROR_TYPE_INFO,
1203            _ ("Service process failed to report status\n"));
1204       break;
1205     }
1206     exit (1);  /* child reported error */
1207   }
1208   GNUNET_break (0 == close (0));
1209   GNUNET_break (0 == close (1));
1210   GNUNET_break (0 == close (filedes[0]));
1211   nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1212   if (nullfd < 0)
1213     return GNUNET_SYSERR;
1214   /* set stdin/stdout to /dev/null */
1215   if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1216   {
1217     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1218     (void) close (nullfd);
1219     return GNUNET_SYSERR;
1220   }
1221   (void) close (nullfd);
1222   /* Detach from controlling terminal */
1223   pid = setsid ();
1224   if (-1 == pid)
1225     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1226   sctx->ready_confirm_fd = filedes[1];
1227
1228   return GNUNET_OK;
1229 }
1230
1231
1232 /**
1233  * Set user ID.
1234  *
1235  * @param sctx service context
1236  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1237  */
1238 static int
1239 set_user_id (struct LEGACY_SERVICE_Context *sctx)
1240 {
1241   char *user;
1242
1243   if (NULL == (user = get_user_name (sctx)))
1244     return GNUNET_OK; /* keep */
1245
1246   struct passwd *pws;
1247
1248   errno = 0;
1249   pws = getpwnam (user);
1250   if (NULL == pws)
1251   {
1252     LOG (GNUNET_ERROR_TYPE_ERROR,
1253          _ ("Cannot obtain information about user `%s': %s\n"),
1254          user,
1255          errno == 0 ? _ ("No such user") : strerror (errno));
1256     GNUNET_free (user);
1257     return GNUNET_SYSERR;
1258   }
1259   if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1260 #if HAVE_INITGROUPS
1261       (0 != initgroups (user, pws->pw_gid)) ||
1262 #endif
1263       (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1264   {
1265     if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1266         (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1267     {
1268       LOG (GNUNET_ERROR_TYPE_ERROR,
1269            _ ("Cannot change user/group to `%s': %s\n"),
1270            user,
1271            strerror (errno));
1272       GNUNET_free (user);
1273       return GNUNET_SYSERR;
1274     }
1275   }
1276
1277   GNUNET_free (user);
1278   return GNUNET_OK;
1279 }
1280
1281
1282 /**
1283  * Delete the PID file that was created by our parent.
1284  *
1285  * @param sctx service context
1286  */
1287 static void
1288 pid_file_delete (struct LEGACY_SERVICE_Context *sctx)
1289 {
1290   char *pif = get_pid_file_name (sctx);
1291
1292   if (NULL == pif)
1293     return; /* no PID file */
1294   if (0 != unlink (pif))
1295     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1296   GNUNET_free (pif);
1297 }
1298
1299
1300 /**
1301  * Run a standard GNUnet service startup sequence (initialize loggers
1302  * and configuration, parse options).
1303  *
1304  * @param argc number of command line arguments
1305  * @param argv command line arguments
1306  * @param service_name our service name
1307  * @param options service options
1308  * @param task main task of the service
1309  * @param task_cls closure for @a task
1310  * @return #GNUNET_SYSERR on error, #GNUNET_OK
1311  *         if we shutdown nicely
1312  */
1313 int
1314 LEGACY_SERVICE_run (int argc,
1315                     char *const *argv,
1316                     const char *service_name,
1317                     enum LEGACY_SERVICE_Options options,
1318                     LEGACY_SERVICE_Main task,
1319                     void *task_cls)
1320 {
1321 #define HANDLE_ERROR  \
1322   do                  \
1323   {                   \
1324     GNUNET_break (0); \
1325     goto shutdown;    \
1326   } while (0)
1327
1328   int err;
1329   int ret;
1330   char *cfg_fn;
1331   char *opt_cfg_fn;
1332   char *loglev;
1333   char *logfile;
1334   int do_daemonize;
1335   unsigned int i;
1336   unsigned long long skew_offset;
1337   unsigned long long skew_variance;
1338   long long clock_offset;
1339   struct LEGACY_SERVICE_Context sctx;
1340   struct GNUNET_CONFIGURATION_Handle *cfg;
1341   const char *xdg;
1342
1343   struct GNUNET_GETOPT_CommandLineOption service_options[] =
1344   { GNUNET_GETOPT_option_cfgfile (&opt_cfg_fn),
1345     GNUNET_GETOPT_option_flag ('d',
1346                                "daemonize",
1347                                gettext_noop (
1348                                  "do daemonize (detach from terminal)"),
1349                                &do_daemonize),
1350     GNUNET_GETOPT_option_help (NULL),
1351     GNUNET_GETOPT_option_loglevel (&loglev),
1352     GNUNET_GETOPT_option_logfile (&logfile),
1353     GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
1354     GNUNET_GETOPT_OPTION_END };
1355   err = 1;
1356   do_daemonize = 0;
1357   logfile = NULL;
1358   loglev = NULL;
1359   opt_cfg_fn = NULL;
1360   xdg = getenv ("XDG_CONFIG_HOME");
1361   if (NULL != xdg)
1362     GNUNET_asprintf (&cfg_fn,
1363                      "%s%s%s",
1364                      xdg,
1365                      DIR_SEPARATOR_STR,
1366                      GNUNET_OS_project_data_get ()->config_file);
1367   else
1368     cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1369   memset (&sctx, 0, sizeof(sctx));
1370   sctx.options = options;
1371   sctx.ready_confirm_fd = -1;
1372   sctx.ret = GNUNET_OK;
1373   sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1374   sctx.task = task;
1375   sctx.task_cls = task_cls;
1376   sctx.service_name = service_name;
1377   sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1378
1379   /* setup subsystems */
1380   ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1381   if (GNUNET_SYSERR == ret)
1382     goto shutdown;
1383   if (GNUNET_NO == ret)
1384   {
1385     err = 0;
1386     goto shutdown;
1387   }
1388   if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1389     HANDLE_ERROR;
1390   if (NULL == opt_cfg_fn)
1391     opt_cfg_fn = GNUNET_strdup (cfg_fn);
1392   if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
1393   {
1394     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
1395     {
1396       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1397                   _ ("Malformed configuration file `%s', exit ...\n"),
1398                   opt_cfg_fn);
1399       goto shutdown;
1400     }
1401   }
1402   else
1403   {
1404     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1405     {
1406       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407                   _ ("Malformed configuration, exit ...\n"));
1408       goto shutdown;
1409     }
1410     if (0 != strcmp (opt_cfg_fn, cfg_fn))
1411       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412                   _ ("Could not access configuration file `%s'\n"),
1413                   opt_cfg_fn);
1414   }
1415   if (GNUNET_OK != setup_service (&sctx))
1416     goto shutdown;
1417   if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1418     HANDLE_ERROR;
1419   if (GNUNET_OK != set_user_id (&sctx))
1420     goto shutdown;
1421   LOG (GNUNET_ERROR_TYPE_DEBUG,
1422        "Service `%s' runs with configuration from `%s'\n",
1423        service_name,
1424        opt_cfg_fn);
1425   if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1426                                                            "TESTING",
1427                                                            "SKEW_OFFSET",
1428                                                            &skew_offset)) &&
1429       (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1430                                                            "TESTING",
1431                                                            "SKEW_VARIANCE",
1432                                                            &skew_variance)))
1433   {
1434     clock_offset = skew_offset - skew_variance;
1435     GNUNET_TIME_set_offset (clock_offset);
1436     LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
1437   }
1438   /* actually run service */
1439   err = 0;
1440   GNUNET_SCHEDULER_run (&service_task, &sctx);
1441   /* shutdown */
1442   if ((1 == do_daemonize) && (NULL != sctx.server))
1443     pid_file_delete (&sctx);
1444   GNUNET_free_non_null (sctx.my_handlers);
1445
1446 shutdown:
1447   if (-1 != sctx.ready_confirm_fd)
1448   {
1449     if (1 != write (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1450       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1451     GNUNET_break (0 == close (sctx.ready_confirm_fd));
1452   }
1453 #if HAVE_MALLINFO
1454   {
1455     char *counter;
1456
1457     if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx.cfg,
1458                                                         service_name,
1459                                                         "GAUGER_HEAP")) &&
1460         (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx.cfg,
1461                                                              service_name,
1462                                                              "GAUGER_HEAP",
1463                                                              &counter)))
1464     {
1465       struct mallinfo mi;
1466
1467       mi = mallinfo ();
1468       GAUGER (service_name, counter, mi.usmblks, "blocks");
1469       GNUNET_free (counter);
1470     }
1471   }
1472 #endif
1473   GNUNET_CONFIGURATION_destroy (cfg);
1474   i = 0;
1475   if (NULL != sctx.addrs)
1476     while (NULL != sctx.addrs[i])
1477       GNUNET_free (sctx.addrs[i++]);
1478   GNUNET_free_non_null (sctx.addrs);
1479   GNUNET_free_non_null (sctx.addrlens);
1480   GNUNET_free_non_null (logfile);
1481   GNUNET_free_non_null (loglev);
1482   GNUNET_free (cfg_fn);
1483   GNUNET_free_non_null (opt_cfg_fn);
1484   GNUNET_free_non_null (sctx.v4_denied);
1485   GNUNET_free_non_null (sctx.v6_denied);
1486   GNUNET_free_non_null (sctx.v4_allowed);
1487   GNUNET_free_non_null (sctx.v6_allowed);
1488
1489   return err ? GNUNET_SYSERR : sctx.ret;
1490 }
1491
1492
1493 /**
1494  * Run a service startup sequence within an existing
1495  * initialized system.
1496  *
1497  * @param service_name our service name
1498  * @param cfg configuration to use
1499  * @param options service options
1500  * @return NULL on error, service handle
1501  */
1502 struct LEGACY_SERVICE_Context *
1503 LEGACY_SERVICE_start (const char *service_name,
1504                       const struct GNUNET_CONFIGURATION_Handle *cfg,
1505                       enum LEGACY_SERVICE_Options options)
1506 {
1507   int i;
1508   struct LEGACY_SERVICE_Context *sctx;
1509
1510   sctx = GNUNET_new (struct LEGACY_SERVICE_Context);
1511   sctx->ready_confirm_fd = -1; /* no daemonizing */
1512   sctx->ret = GNUNET_OK;
1513   sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1514   sctx->service_name = service_name;
1515   sctx->cfg = cfg;
1516   sctx->options = options;
1517
1518   /* setup subsystems */
1519   if (GNUNET_OK != setup_service (sctx))
1520   {
1521     LEGACY_SERVICE_stop (sctx);
1522     return NULL;
1523   }
1524   if (NULL != sctx->lsocks)
1525     sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1526                                                       sctx,
1527                                                       sctx->lsocks,
1528                                                       sctx->timeout,
1529                                                       sctx->require_found);
1530   else
1531     sctx->server = GNUNET_SERVER_create (&check_access,
1532                                          sctx,
1533                                          sctx->addrs,
1534                                          sctx->addrlens,
1535                                          sctx->timeout,
1536                                          sctx->require_found);
1537
1538   if (NULL == sctx->server)
1539   {
1540     LEGACY_SERVICE_stop (sctx);
1541     return NULL;
1542   }
1543
1544   if (NULL != sctx->addrs)
1545     for (i = 0; NULL != sctx->addrs[i]; i++)
1546       if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1547           ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1548         GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1549                                       sctx->addrs[i])
1550                                      ->sun_path,
1551                                      sctx->match_uid,
1552                                      sctx->match_gid);
1553
1554   sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1555   GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1556   i = 0;
1557   while ((sctx->my_handlers[i].callback != NULL))
1558     sctx->my_handlers[i++].callback_cls = sctx;
1559   GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1560   return sctx;
1561 }
1562
1563
1564 /**
1565  * Obtain the server used by a service.  Note that the server must NOT
1566  * be destroyed by the caller.
1567  *
1568  * @param ctx the service context returned from the start function
1569  * @return handle to the server for this service, NULL if there is none
1570  */
1571 struct GNUNET_SERVER_Handle *
1572 LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx)
1573 {
1574   return ctx->server;
1575 }
1576
1577
1578 /**
1579  * Get the NULL-terminated array of listen sockets for this service.
1580  *
1581  * @param ctx service context to query
1582  * @return NULL if there are no listen sockets, otherwise NULL-terminated
1583  *              array of listen sockets.
1584  */
1585 struct GNUNET_NETWORK_Handle *const *
1586 LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx)
1587 {
1588   return ctx->lsocks;
1589 }
1590
1591
1592 /**
1593  * Stop a service that was started with "LEGACY_SERVICE_start".
1594  *
1595  * @param sctx the service context returned from the start function
1596  */
1597 void
1598 LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1599 {
1600   unsigned int i;
1601
1602 #if HAVE_MALLINFO
1603   {
1604     char *counter;
1605
1606     if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx->cfg,
1607                                                         sctx->service_name,
1608                                                         "GAUGER_HEAP")) &&
1609         (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
1610                                                              sctx->service_name,
1611                                                              "GAUGER_HEAP",
1612                                                              &counter)))
1613     {
1614       struct mallinfo mi;
1615
1616       mi = mallinfo ();
1617       GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1618       GNUNET_free (counter);
1619     }
1620   }
1621 #endif
1622   if (NULL != sctx->shutdown_task)
1623   {
1624     GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1625     sctx->shutdown_task = NULL;
1626   }
1627   if (NULL != sctx->server)
1628     GNUNET_SERVER_destroy (sctx->server);
1629   GNUNET_free_non_null (sctx->my_handlers);
1630   if (NULL != sctx->addrs)
1631   {
1632     i = 0;
1633     while (NULL != sctx->addrs[i])
1634       GNUNET_free (sctx->addrs[i++]);
1635     GNUNET_free (sctx->addrs);
1636   }
1637   GNUNET_free_non_null (sctx->addrlens);
1638   GNUNET_free_non_null (sctx->v4_denied);
1639   GNUNET_free_non_null (sctx->v6_denied);
1640   GNUNET_free_non_null (sctx->v4_allowed);
1641   GNUNET_free_non_null (sctx->v6_allowed);
1642   GNUNET_free (sctx);
1643 }
1644
1645
1646 /* end of service.c */