-remove trailing whitespace
[oweals/gnunet.git] / src / util / service.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
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_directories.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 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
39
40 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
41
42 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
43
44
45 /* ******************* access control ******************** */
46
47 /**
48  * @brief IPV4 network in CIDR notation.
49  */
50 struct IPv4NetworkSet
51 {
52   /**
53    * IPv4 address.
54    */
55   struct in_addr network;
56
57   /**
58    * IPv4 netmask.
59    */
60   struct in_addr netmask;
61 };
62
63 /**
64
65  * @brief network in CIDR notation for IPV6.
66  */
67 struct IPv6NetworkSet
68 {
69   /**
70    * IPv6 address.
71    */
72   struct in6_addr network;
73
74   /**
75    * IPv6 netmask.
76    */
77   struct in6_addr netmask;
78 };
79
80
81 /**
82  * Start task that may speed up our system clock artificially
83  *
84  * @param cfg configuration to use
85  * @return GNUNET_OK on success, GNUNET_SYSERR if the speedup was not configured
86  */
87 int
88 GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg);
89
90 /**
91  * Stop tasks that modify clock behavior.
92  */
93 void
94 GNUNET_SPEEDUP_stop_ (void);
95
96
97 /**
98  * Parse a network specification. The argument specifies
99  * a list of networks. The format is
100  * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated
101  * with a semicolon). The network must be given in dotted-decimal
102  * notation. The netmask can be given in CIDR notation (/16) or
103  * in dotted-decimal (/255.255.0.0).
104  *
105  * @param routeList a string specifying the forbidden networks
106  * @return the converted list, NULL if the synatx is flawed
107  */
108 static struct IPv4NetworkSet *
109 parse_ipv4_specification (const char *routeList)
110 {
111   unsigned int count;
112   unsigned int i;
113   unsigned int j;
114   unsigned int len;
115   int cnt;
116   unsigned int pos;
117   unsigned int temps[8];
118   int slash;
119   struct IPv4NetworkSet *result;
120
121   if (NULL == routeList)
122     return NULL;
123   len = strlen (routeList);
124   if (0 == len)
125     return NULL;
126   count = 0;
127   for (i = 0; i < len; i++)
128     if (routeList[i] == ';')
129       count++;
130   result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1));
131   i = 0;
132   pos = 0;
133   while (i < count)
134   {
135     cnt =
136         SSCANF (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0],
137                 &temps[1], &temps[2], &temps[3], &temps[4], &temps[5],
138                 &temps[6], &temps[7]);
139     if (8 == cnt)
140     {
141       for (j = 0; j < 8; j++)
142         if (temps[j] > 0xFF)
143         {
144           LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
145                &routeList[pos]);
146           GNUNET_free (result);
147           return NULL;
148         }
149       result[i].network.s_addr =
150           htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
151                  temps[3]);
152       result[i].netmask.s_addr =
153           htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) +
154                  temps[7]);
155       while (routeList[pos] != ';')
156         pos++;
157       pos++;
158       i++;
159       continue;
160     }
161     /* try second notation */
162     cnt =
163         SSCANF (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1],
164                 &temps[2], &temps[3], &slash);
165     if (5 == cnt)
166     {
167       for (j = 0; j < 4; j++)
168         if (temps[j] > 0xFF)
169         {
170           LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
171                &routeList[pos]);
172           GNUNET_free (result);
173           return NULL;
174         }
175       result[i].network.s_addr =
176           htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
177                  temps[3]);
178       if ((slash <= 32) && (slash >= 0))
179       {
180         result[i].netmask.s_addr = 0;
181         while (slash > 0)
182         {
183           result[i].netmask.s_addr =
184               (result[i].netmask.s_addr >> 1) + 0x80000000;
185           slash--;
186         }
187         result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
188         while (';' != routeList[pos])
189           pos++;
190         pos++;
191         i++;
192         continue;
193       }
194       else
195       {
196         LOG (GNUNET_ERROR_TYPE_ERROR,
197              _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
198              slash);
199         GNUNET_free (result);
200         return NULL;            /* error */
201       }
202     }
203     /* try third notation */
204     slash = 32;
205     cnt =
206         SSCANF (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1],
207                 &temps[2], &temps[3]);
208     if (4 == cnt)
209     {
210       for (j = 0; j < 4; j++)
211         if (temps[j] > 0xFF)
212         {
213           LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
214                &routeList[pos]);
215           GNUNET_free (result);
216           return NULL;
217         }
218       result[i].network.s_addr =
219           htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
220                  temps[3]);
221       result[i].netmask.s_addr = 0;
222       while (slash > 0)
223       {
224         result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000;
225         slash--;
226       }
227       result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
228       while (routeList[pos] != ';')
229         pos++;
230       pos++;
231       i++;
232       continue;
233     }
234     LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
235          &routeList[pos]);
236     GNUNET_free (result);
237     return NULL;                /* error */
238   }
239   if (pos < strlen (routeList))
240   {
241     LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
242          &routeList[pos]);
243     GNUNET_free (result);
244     return NULL;                /* oops */
245   }
246   return result;                /* ok */
247 }
248
249
250 /**
251  * Parse a network specification. The argument specifies
252  * a list of networks. The format is
253  * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated
254  * with a semicolon). The network must be given in colon-hex
255  * notation.  The netmask must be given in CIDR notation (/16) or
256  * can be omitted to specify a single host.
257  *
258  * @param routeListX a string specifying the forbidden networks
259  * @return the converted list, NULL if the synatx is flawed
260  */
261 static struct IPv6NetworkSet *
262 parse_ipv6_specification (const char *routeListX)
263 {
264   unsigned int count;
265   unsigned int i;
266   unsigned int len;
267   unsigned int pos;
268   int start;
269   int slash;
270   int ret;
271   char *routeList;
272   struct IPv6NetworkSet *result;
273   unsigned int bits;
274   unsigned int off;
275   int save;
276
277   if (NULL == routeListX)
278     return NULL;
279   len = strlen (routeListX);
280   if (0 == len)
281     return NULL;
282   routeList = GNUNET_strdup (routeListX);
283   count = 0;
284   for (i = 0; i < len; i++)
285     if (';' == routeList[i])
286       count++;
287   if (';' != routeList[len - 1])
288   {
289     LOG (GNUNET_ERROR_TYPE_ERROR,
290          _("Invalid network notation (does not end with ';': `%s')\n"),
291          routeList);
292     GNUNET_free (routeList);
293     return NULL;
294   }
295
296   result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1));
297   i = 0;
298   pos = 0;
299   while (i < count)
300   {
301     start = pos;
302     while (';' != routeList[pos])
303       pos++;
304     slash = pos;
305     while ((slash >= start) && (routeList[slash] != '/'))
306       slash--;
307     if (slash < start)
308     {
309       memset (&result[i].netmask, 0xFF, sizeof (struct in6_addr));
310       slash = pos;
311     }
312     else
313     {
314       routeList[pos] = '\0';
315       ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask);
316       if (ret <= 0)
317       {
318         save = errno;
319         if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128))
320         {
321           if (0 == ret)
322             LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"),
323                  &routeList[slash + 1]);
324           else
325           {
326             errno = save;
327             LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
328           }
329           GNUNET_free (result);
330           GNUNET_free (routeList);
331           return NULL;
332         }
333         off = 0;
334         while (bits > 8)
335         {
336           result[i].netmask.s6_addr[off++] = 0xFF;
337           bits -= 8;
338         }
339         while (bits > 0)
340         {
341           result[i].netmask.s6_addr[off] =
342               (result[i].netmask.s6_addr[off] >> 1) + 0x80;
343           bits--;
344         }
345       }
346     }
347     routeList[slash] = '\0';
348     ret = inet_pton (AF_INET6, &routeList[start], &result[i].network);
349     if (ret <= 0)
350     {
351       if (0 == ret)
352         LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"),
353              &routeList[slash + 1]);
354       else
355         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
356       GNUNET_free (result);
357       GNUNET_free (routeList);
358       return NULL;
359     }
360     pos++;
361     i++;
362   }
363   GNUNET_free (routeList);
364   return result;
365 }
366
367
368 /**
369  * Check if the given IP address is in the list of IP addresses.
370  *
371  * @param list a list of networks
372  * @param add the IP to check (in network byte order)
373  * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is
374  */
375 static int
376 check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add)
377 {
378   unsigned int i;
379
380   if (NULL == list)
381     return GNUNET_NO;
382   i = 0;
383   while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
384   {
385     if ((add->s_addr & list[i].netmask.s_addr) ==
386         (list[i].network.s_addr & list[i].netmask.s_addr))
387       return GNUNET_YES;
388     i++;
389   }
390   return GNUNET_NO;
391 }
392
393
394 /**
395  * Check if the given IP address is in the list of IP addresses.
396  *
397  * @param list a list of networks
398  * @param ip the IP to check (in network byte order)
399  * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is
400  */
401 static int
402 check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip)
403 {
404   unsigned int i;
405   unsigned int j;
406   struct in6_addr zero;
407
408   if (NULL == list)
409     return GNUNET_NO;
410   memset (&zero, 0, sizeof (struct in6_addr));
411   i = 0;
412 NEXT:
413   while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
414   {
415     for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
416       if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
417           (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
418       {
419         i++;
420         goto NEXT;
421       }
422     return GNUNET_YES;
423   }
424   return GNUNET_NO;
425 }
426
427
428 /* ****************** service struct ****************** */
429
430
431 /**
432  * Context for "service_task".
433  */
434 struct GNUNET_SERVICE_Context
435 {
436   /**
437    * Our configuration.
438    */
439   const struct GNUNET_CONFIGURATION_Handle *cfg;
440
441   /**
442    * Handle for the server.
443    */
444   struct GNUNET_SERVER_Handle *server;
445
446   /**
447    * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
448    * listen sockets.
449    */
450   struct sockaddr **addrs;
451
452   /**
453    * Name of our service.
454    */
455   const char *service_name;
456
457   /**
458    * Main service-specific task to run.
459    */
460   GNUNET_SERVICE_Main task;
461
462   /**
463    * Closure for task.
464    */
465   void *task_cls;
466
467   /**
468    * IPv4 addresses that are not allowed to connect.
469    */
470   struct IPv4NetworkSet *v4_denied;
471
472   /**
473    * IPv6 addresses that are not allowed to connect.
474    */
475   struct IPv6NetworkSet *v6_denied;
476
477   /**
478    * IPv4 addresses that are allowed to connect (if not
479    * set, all are allowed).
480    */
481   struct IPv4NetworkSet *v4_allowed;
482
483   /**
484    * IPv6 addresses that are allowed to connect (if not
485    * set, all are allowed).
486    */
487   struct IPv6NetworkSet *v6_allowed;
488
489   /**
490    * My (default) message handlers.  Adjusted copy
491    * of "defhandlers".
492    */
493   struct GNUNET_SERVER_MessageHandler *my_handlers;
494
495   /**
496    * Array of the lengths of the entries in addrs.
497    */
498   socklen_t *addrlens;
499
500   /**
501    * NULL-terminated array of listen sockets we should take over.
502    */
503   struct GNUNET_NETWORK_Handle **lsocks;
504
505   /**
506    * Task ID of the shutdown task.
507    */
508   GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
509
510   /**
511    * Idle timeout for server.
512    */
513   struct GNUNET_TIME_Relative timeout;
514
515   /**
516    * Overall success/failure of the service start.
517    */
518   int ret;
519
520   /**
521    * If we are daemonizing, this FD is set to the
522    * pipe to the parent.  Send '.' if we started
523    * ok, '!' if not.  -1 if we are not daemonizing.
524    */
525   int ready_confirm_fd;
526
527   /**
528    * Do we close connections if we receive messages
529    * for which we have no handler?
530    */
531   int require_found;
532
533   /**
534    * Do we require a matching UID for UNIX domain socket connections?
535    * GNUNET_NO means that the UID does not have to match (however,
536    * "match_gid" may still impose other access control checks).
537    */
538   int match_uid;
539
540   /**
541    * Do we require a matching GID for UNIX domain socket connections?
542    * Ignored if "match_uid" is GNUNET_YES.  Note that this is about
543    * checking that the client's UID is in our group OR that the
544    * client's GID is our GID.  If both "match_gid" and "match_uid" are
545    * "GNUNET_NO", all users on the local system have access.
546    */
547   int match_gid;
548
549   /**
550    * Our options.
551    */
552   enum GNUNET_SERVICE_Options options;
553
554 };
555
556
557 /* ****************** message handlers ****************** */
558
559 /**
560  * Send a 'TEST' message back to the client.
561  *
562  * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
563  * @param size number of bytes available in 'buf'
564  * @param buf where to copy the message
565  * @return number of bytes written to 'buf'
566  */
567 static size_t
568 write_test (void *cls, size_t size, void *buf)
569 {
570   struct GNUNET_SERVER_Client *client = cls;
571   struct GNUNET_MessageHeader *msg;
572
573   if (size < sizeof (struct GNUNET_MessageHeader))
574   {
575     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
576     return 0;                   /* client disconnected */
577   }
578   msg = (struct GNUNET_MessageHeader *) buf;
579   msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
580   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
581   GNUNET_SERVER_receive_done (client, GNUNET_OK);
582   return sizeof (struct GNUNET_MessageHeader);
583 }
584
585
586 /**
587  * Handler for TEST message.
588  *
589  * @param cls closure (refers to service)
590  * @param client identification of the client
591  * @param message the actual message
592  */
593 static void
594 handle_test (void *cls, struct GNUNET_SERVER_Client *client,
595              const struct GNUNET_MessageHeader *message)
596 {
597   /* simply bounce message back to acknowledge */
598   if (NULL ==
599       GNUNET_SERVER_notify_transmit_ready (client,
600                                            sizeof (struct GNUNET_MessageHeader),
601                                            GNUNET_TIME_UNIT_FOREVER_REL,
602                                            &write_test, client))
603     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
604 }
605
606
607 /**
608  * Default handlers for all services.  Will be copied and the
609  * "callback_cls" fields will be replaced with the specific service
610  * struct.
611  */
612 static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
613   {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
614    sizeof (struct GNUNET_MessageHeader)},
615   {NULL, NULL, 0, 0}
616 };
617
618
619 /* ****************** service core routines ************** */
620
621
622 /**
623  * Check if access to the service is allowed from the given address.
624  *
625  * @param cls closure
626  * @param uc credentials, if available, otherwise NULL
627  * @param addr address
628  * @param addrlen length of address
629  * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
630  *   for unknown address family (will be denied).
631  */
632 static int
633 check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
634               const struct sockaddr *addr, socklen_t addrlen)
635 {
636   struct GNUNET_SERVICE_Context *sctx = cls;
637   const struct sockaddr_in *i4;
638   const struct sockaddr_in6 *i6;
639   int ret;
640
641   switch (addr->sa_family)
642   {
643   case AF_INET:
644     GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
645     i4 = (const struct sockaddr_in *) addr;
646     ret = ((NULL == sctx->v4_allowed) ||
647            (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
648         ((NULL == sctx->v4_denied) ||
649          (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
650     break;
651   case AF_INET6:
652     GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
653     i6 = (const struct sockaddr_in6 *) addr;
654     ret = ((NULL == sctx->v6_allowed) ||
655            (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
656         ((NULL == sctx->v6_denied) ||
657          (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
658     break;
659 #ifndef WINDOWS
660   case AF_UNIX:
661     ret = GNUNET_OK;            /* always OK for now */
662     if (GNUNET_YES == sctx->match_uid)
663     {
664       /* UID match required */
665       ret = (NULL != uc) && ( (0 == uc->uid) || (uc->uid == geteuid ()) );
666     }
667     else if ( (GNUNET_YES == sctx->match_gid) &&
668               ( (NULL == uc) ||
669                 ( (0 != uc->uid) &&
670                   (uc->uid != geteuid ()) ) ) )
671     {
672       /* group match required and UID does not match */
673       if (NULL == uc)
674       {
675         /* no credentials, group match not possible */
676         ret = GNUNET_NO;
677       }
678       else
679       {
680         struct group *grp;
681         unsigned int i;
682
683         if (uc->gid != getegid())
684         {
685           /* default group did not match, but maybe the user is in our group, let's check */
686           grp = getgrgid (getegid ());
687           if (NULL == grp)
688           {
689             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getgrgid");
690             return GNUNET_NO;
691           }
692           ret = GNUNET_NO;
693           for (i=0; NULL != grp->gr_mem[i]; i++)
694           {
695             struct passwd *nam = getpwnam (grp->gr_mem[i]);
696             if (NULL == nam)
697               continue; /* name in group that is not in user DB !? */
698             if (nam->pw_uid == uc->uid)
699             {
700               /* yes, uid is in our group, allow! */
701               ret = GNUNET_YES;
702               break;
703             }
704           }
705         }
706       }
707     }
708     if (GNUNET_NO == ret)
709       LOG (GNUNET_ERROR_TYPE_WARNING, _("Access denied to UID %d / GID %d\n"),
710            (NULL == uc) ? -1 : uc->uid, (NULL == uc) ? -1 : uc->gid);
711     break;
712 #endif
713   default:
714     LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
715          addr->sa_family);
716     return GNUNET_SYSERR;
717   }
718   if (GNUNET_OK != ret)
719   {
720     LOG (GNUNET_ERROR_TYPE_WARNING,
721          _("Access from `%s' denied to service `%s'\n"),
722          GNUNET_a2s (addr, addrlen),
723          sctx->service_name);
724   }
725   return ret;
726 }
727
728
729 /**
730  * Get the name of the file where we will
731  * write the PID of the service.
732  *
733  * @param sctx service context
734  * @return name of the file for the process ID
735  */
736 static char *
737 get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
738 {
739   char *pif;
740
741   if (GNUNET_OK !=
742       GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
743                                                "PIDFILE", &pif))
744     return NULL;
745   return pif;
746 }
747
748
749 /**
750  * Parse an IPv4 access control list.
751  *
752  * @param ret location where to write the ACL (set)
753  * @param sctx service context to use to get the configuration
754  * @param option name of the ACL option to parse
755  * @return GNUNET_SYSERR on parse error, GNUNET_OK on success (including
756  *         no ACL configured)
757  */
758 static int
759 process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
760               const char *option)
761 {
762   char *opt;
763
764   if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
765   {
766     *ret = NULL;
767     return GNUNET_OK;
768   }
769   GNUNET_break (GNUNET_OK ==
770                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
771                                                        sctx->service_name,
772                                                        option, &opt));
773   if (NULL == (*ret = parse_ipv4_specification (opt)))
774   {
775     LOG (GNUNET_ERROR_TYPE_WARNING,
776          _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
777          opt, sctx->service_name, option);
778     GNUNET_free (opt);
779     return GNUNET_SYSERR;
780   }
781   GNUNET_free (opt);
782   return GNUNET_OK;
783 }
784
785
786 /**
787  * Parse an IPv6 access control list.
788  *
789  * @param ret location where to write the ACL (set)
790  * @param sctx service context to use to get the configuration
791  * @param option name of the ACL option to parse
792  * @return GNUNET_SYSERR on parse error, GNUNET_OK on success (including
793  *         no ACL configured)
794  */
795 static int
796 process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
797               const char *option)
798 {
799   char *opt;
800
801   if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
802   {
803     *ret = NULL;
804     return GNUNET_OK;
805   }
806   GNUNET_break (GNUNET_OK ==
807                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
808                                                        sctx->service_name,
809                                                        option, &opt));
810   if (NULL == (*ret = parse_ipv6_specification (opt)))
811   {
812     LOG (GNUNET_ERROR_TYPE_WARNING,
813          _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
814          opt, sctx->service_name, option);
815     GNUNET_free (opt);
816     return GNUNET_SYSERR;
817   }
818   GNUNET_free (opt);
819   return GNUNET_OK;
820 }
821
822
823 /**
824  * Add the given UNIX domain path as an address to the
825  * list (as the first entry).
826  *
827  * @param saddrs array to update
828  * @param saddrlens where to store the address length
829  * @param unixpath path to add
830  */
831 static void
832 add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens,
833               const char *unixpath)
834 {
835 #ifdef AF_UNIX
836   struct sockaddr_un *un;
837   size_t slen;
838
839   un = GNUNET_malloc (sizeof (struct sockaddr_un));
840   un->sun_family = AF_UNIX;
841   slen = strlen (unixpath) + 1;
842   if (slen >= sizeof (un->sun_path))
843     slen = sizeof (un->sun_path) - 1;
844   memcpy (un->sun_path, unixpath, slen);
845   un->sun_path[slen] = '\0';
846   slen = sizeof (struct sockaddr_un);
847 #if LINUX
848   un->sun_path[0] = '\0';
849 #endif
850 #if HAVE_SOCKADDR_IN_SIN_LEN
851   un->sun_len = (u_char) slen;
852 #endif
853   *saddrs = (struct sockaddr *) un;
854   *saddrlens = slen;
855 #else
856   /* this function should never be called
857    * unless AF_UNIX is defined! */
858   GNUNET_assert (0);
859 #endif
860 }
861
862
863 /**
864  * Get the list of addresses that a server for the given service
865  * should bind to.
866  *
867  * @param service_name name of the service
868  * @param cfg configuration (which specifies the addresses)
869  * @param addrs set (call by reference) to an array of pointers to the
870  *              addresses the server should bind to and listen on; the
871  *              array will be NULL-terminated (on success)
872  * @param addr_lens set (call by reference) to an array of the lengths
873  *              of the respective 'struct sockaddr' struct in the 'addrs'
874  *              array (on success)
875  * @return number of addresses found on success,
876  *              GNUNET_SYSERR if the configuration
877  *              did not specify reasonable finding information or
878  *              if it specified a hostname that could not be resolved;
879  *              GNUNET_NO if the number of addresses configured is
880  *              zero (in this case, '*addrs' and '*addr_lens' will be
881  *              set to NULL).
882  */
883 int
884 GNUNET_SERVICE_get_server_addresses (const char *service_name,
885                                      const struct GNUNET_CONFIGURATION_Handle
886                                      *cfg, struct sockaddr ***addrs,
887                                      socklen_t ** addr_lens)
888 {
889   int disablev6;
890   struct GNUNET_NETWORK_Handle *desc;
891   unsigned long long port;
892   char *unixpath;
893   struct addrinfo hints;
894   struct addrinfo *res;
895   struct addrinfo *pos;
896   struct addrinfo *next;
897   unsigned int i;
898   int resi;
899   int ret;
900   struct sockaddr **saddrs;
901   socklen_t *saddrlens;
902   char *hostname;
903
904   *addrs = NULL;
905   *addr_lens = NULL;
906   desc = NULL;
907   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
908   {
909     if (GNUNET_SYSERR ==
910         (disablev6 =
911          GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
912       return GNUNET_SYSERR;
913   }
914   else
915     disablev6 = GNUNET_NO;
916
917   if (!disablev6)
918   {
919     /* probe IPv6 support */
920     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
921     if (NULL == desc)
922     {
923       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
924           (EACCES == errno))
925       {
926         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
927         return GNUNET_SYSERR;
928       }
929       LOG (GNUNET_ERROR_TYPE_INFO,
930            _
931            ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
932            service_name, STRERROR (errno));
933       disablev6 = GNUNET_YES;
934     }
935     else
936     {
937       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
938       desc = NULL;
939     }
940   }
941
942   port = 0;
943   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
944   {
945     if (GNUNET_OK !=
946         GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
947                                                "PORT", &port))
948     {
949       LOG (GNUNET_ERROR_TYPE_ERROR,
950            _("Require valid port number for service `%s' in configuration!\n"),
951            service_name);
952     }
953     if (port > 65535)
954     {
955       LOG (GNUNET_ERROR_TYPE_ERROR,
956            _("Require valid port number for service `%s' in configuration!\n"),
957            service_name);
958       return GNUNET_SYSERR;
959     }
960   }
961
962   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
963   {
964     GNUNET_break (GNUNET_OK ==
965                   GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
966                                                          "BINDTO", &hostname));
967   }
968   else
969     hostname = NULL;
970
971   unixpath = NULL;
972 #ifdef AF_UNIX
973   if ((GNUNET_YES ==
974        GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
975       (GNUNET_OK ==
976        GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH",
977                                               &unixpath)) &&
978       (0 < strlen (unixpath)))
979   {
980     /* probe UNIX support */
981     struct sockaddr_un s_un;
982
983     if (strlen (unixpath) >= sizeof (s_un.sun_path))
984     {
985       LOG (GNUNET_ERROR_TYPE_WARNING,
986            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
987            (unsigned long long) sizeof (s_un.sun_path));
988       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
989       LOG (GNUNET_ERROR_TYPE_INFO,
990            _("Using `%s' instead\n"), unixpath);
991     }
992   }
993   if (NULL != unixpath)
994   {
995     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
996     if (NULL == desc)
997     {
998       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
999           (EACCES == errno))
1000       {
1001         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
1002         GNUNET_free_non_null (hostname);
1003         GNUNET_free (unixpath);
1004         return GNUNET_SYSERR;
1005       }
1006       LOG (GNUNET_ERROR_TYPE_INFO,
1007            _
1008            ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1009            service_name, STRERROR (errno));
1010       GNUNET_free (unixpath);
1011       unixpath = NULL;
1012     }
1013     else
1014     {
1015       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1016       desc = NULL;
1017     }
1018   }
1019 #endif
1020
1021   if ((0 == port) && (NULL == unixpath))
1022   {
1023     LOG (GNUNET_ERROR_TYPE_ERROR,
1024          _
1025          ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1026          service_name);
1027     GNUNET_free_non_null (hostname);
1028     return GNUNET_SYSERR;
1029   }
1030   if (0 == port)
1031   {
1032     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
1033     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
1034     add_unixpath (saddrs, saddrlens, unixpath);
1035     GNUNET_free_non_null (unixpath);
1036     GNUNET_free_non_null (hostname);
1037     *addrs = saddrs;
1038     *addr_lens = saddrlens;
1039     return 1;
1040   }
1041
1042   if (NULL != hostname)
1043   {
1044     LOG (GNUNET_ERROR_TYPE_DEBUG,
1045          "Resolving `%s' since that is where `%s' will bind to.\n", hostname,
1046          service_name);
1047     memset (&hints, 0, sizeof (struct addrinfo));
1048     if (disablev6)
1049       hints.ai_family = AF_INET;
1050     hints.ai_protocol = IPPROTO_TCP;
1051     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1052         (res == NULL))
1053     {
1054       LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname,
1055            gai_strerror (ret));
1056       GNUNET_free (hostname);
1057       GNUNET_free_non_null (unixpath);
1058       return GNUNET_SYSERR;
1059     }
1060     next = res;
1061     i = 0;
1062     while (NULL != (pos = next))
1063     {
1064       next = pos->ai_next;
1065       if ((disablev6) && (pos->ai_family == AF_INET6))
1066         continue;
1067       i++;
1068     }
1069     if (0 == i)
1070     {
1071       LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"),
1072            disablev6 ? "IPv4 " : "", hostname);
1073       freeaddrinfo (res);
1074       GNUNET_free (hostname);
1075       GNUNET_free_non_null (unixpath);
1076       return GNUNET_SYSERR;
1077     }
1078     resi = i;
1079     if (NULL != unixpath)
1080       resi++;
1081     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1082     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1083     i = 0;
1084     if (NULL != unixpath)
1085     {
1086       add_unixpath (saddrs, saddrlens, unixpath);
1087       i++;
1088     }
1089     next = res;
1090     while (NULL != (pos = next))
1091     {
1092       next = pos->ai_next;
1093       if ((disablev6) && (AF_INET6 == pos->ai_family))
1094         continue;
1095       if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1096         continue;               /* not TCP */
1097       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1098         continue;               /* huh? */
1099       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
1100            service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1101       if (AF_INET == pos->ai_family)
1102       {
1103         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
1104         saddrlens[i] = pos->ai_addrlen;
1105         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1106         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1107         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1108       }
1109       else
1110       {
1111         GNUNET_assert (AF_INET6 == pos->ai_family);
1112         GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
1113         saddrlens[i] = pos->ai_addrlen;
1114         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1115         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1116         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1117       }
1118       i++;
1119     }
1120     GNUNET_free (hostname);
1121     freeaddrinfo (res);
1122     resi = i;
1123   }
1124   else
1125   {
1126     /* will bind against everything, just set port */
1127     if (disablev6)
1128     {
1129       /* V4-only */
1130       resi = 1;
1131       if (NULL != unixpath)
1132         resi++;
1133       i = 0;
1134       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1135       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1136       if (NULL != unixpath)
1137       {
1138         add_unixpath (saddrs, saddrlens, unixpath);
1139         i++;
1140       }
1141       saddrlens[i] = sizeof (struct sockaddr_in);
1142       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1143 #if HAVE_SOCKADDR_IN_SIN_LEN
1144       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1145 #endif
1146       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1147       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1148     }
1149     else
1150     {
1151       /* dual stack */
1152       resi = 2;
1153       if (NULL != unixpath)
1154         resi++;
1155       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1156       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1157       i = 0;
1158       if (NULL != unixpath)
1159       {
1160         add_unixpath (saddrs, saddrlens, unixpath);
1161         i++;
1162       }
1163       saddrlens[i] = sizeof (struct sockaddr_in6);
1164       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1165 #if HAVE_SOCKADDR_IN_SIN_LEN
1166       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1167 #endif
1168       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1169       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1170       i++;
1171       saddrlens[i] = sizeof (struct sockaddr_in);
1172       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1173 #if HAVE_SOCKADDR_IN_SIN_LEN
1174       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1175 #endif
1176       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1177       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1178     }
1179   }
1180   GNUNET_free_non_null (unixpath);
1181   *addrs = saddrs;
1182   *addr_lens = saddrlens;
1183   return resi;
1184 }
1185
1186
1187 #ifdef MINGW
1188 /**
1189  * Read listen sockets from the parent process (ARM).
1190  *
1191  * @param sctx service context to initialize
1192  * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself),
1193  * and GNUNET_SYSERR on error.
1194  */
1195 static int
1196 receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
1197 {
1198   const char *env_buf;
1199   int fail;
1200   uint64_t count;
1201   uint64_t i;
1202   HANDLE lsocks_pipe;
1203
1204   env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
1205   if ((NULL == env_buf) || (strlen (env_buf) <= 0))
1206     return GNUNET_NO;
1207   /* Using W32 API directly here, because this pipe will
1208    * never be used outside of this function, and it's just too much of a bother
1209    * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
1210    */
1211   lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
1212   if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
1213     return GNUNET_NO;
1214   fail = 1;
1215   do
1216   {
1217     int ret;
1218     int fail2;
1219     DWORD rd;
1220
1221     ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
1222     if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
1223       break;
1224     sctx->lsocks =
1225         GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
1226
1227     fail2 = 1;
1228     for (i = 0; i < count; i++)
1229     {
1230       WSAPROTOCOL_INFOA pi;
1231       uint64_t size;
1232       SOCKET s;
1233
1234       ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
1235       if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
1236         break;
1237       ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
1238       if ( (0 == ret) || (sizeof (pi) != rd))
1239         break;
1240       s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
1241       sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
1242       if (NULL == sctx->lsocks[i])
1243         break;
1244       else if (i == count - 1)
1245         fail2 = 0;
1246     }
1247     if (fail2)
1248       break;
1249     sctx->lsocks[count] = NULL;
1250     fail = 0;
1251   }
1252   while (fail);
1253
1254   CloseHandle (lsocks_pipe);
1255
1256   if (fail)
1257   {
1258     LOG (GNUNET_ERROR_TYPE_ERROR,
1259          _("Could not access a pre-bound socket, will try to bind myself\n"));
1260     for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
1261       GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
1262     GNUNET_free_non_null (sctx->lsocks);
1263     sctx->lsocks = NULL;
1264     return GNUNET_NO;
1265   }
1266   return GNUNET_YES;
1267 }
1268 #endif
1269
1270
1271 /**
1272  * Setup addr, addrlen, idle_timeout
1273  * based on configuration!
1274  *
1275  * Configuration may specify:
1276  * - PORT (where to bind to for TCP)
1277  * - UNIXPATH (where to bind to for UNIX domain sockets)
1278  * - TIMEOUT (after how many ms does an inactive service timeout);
1279  * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1280  * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1281  * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
1282  * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1283  * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
1284  * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1285  *
1286  * @param sctx service context to initialize
1287  * @return GNUNET_OK if configuration succeeded
1288  */
1289 static int
1290 setup_service (struct GNUNET_SERVICE_Context *sctx)
1291 {
1292   struct GNUNET_TIME_Relative idleout;
1293   int tolerant;
1294
1295 #ifndef MINGW
1296   const char *nfds;
1297   unsigned int cnt;
1298   int flags;
1299 #endif
1300
1301   if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
1302   {
1303     if (GNUNET_OK !=
1304         GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
1305                                              "TIMEOUT", &idleout))
1306     {
1307       LOG (GNUNET_ERROR_TYPE_ERROR,
1308            _("Specified value for `%s' of service `%s' is invalid\n"),
1309            "TIMEOUT", sctx->service_name);
1310       return GNUNET_SYSERR;
1311     }
1312     sctx->timeout = idleout;
1313   }
1314   else
1315     sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1316
1317   if (GNUNET_CONFIGURATION_have_value
1318       (sctx->cfg, sctx->service_name, "TOLERANT"))
1319   {
1320     if (GNUNET_SYSERR ==
1321         (tolerant =
1322          GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1323                                                "TOLERANT")))
1324     {
1325       LOG (GNUNET_ERROR_TYPE_ERROR,
1326            _("Specified value for `%s' of service `%s' is invalid\n"),
1327            "TOLERANT", sctx->service_name);
1328       return GNUNET_SYSERR;
1329     }
1330   }
1331   else
1332     tolerant = GNUNET_NO;
1333
1334 #ifndef MINGW
1335   errno = 0;
1336   if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1337       (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
1338       (cnt + 4 < FD_SETSIZE))
1339   {
1340     sctx->lsocks =
1341         GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
1342     while (0 < cnt--)
1343     {
1344       flags = fcntl (3 + cnt, F_GETFD);
1345       if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
1346           (NULL ==
1347            (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1348       {
1349         LOG (GNUNET_ERROR_TYPE_ERROR,
1350              _
1351              ("Could not access pre-bound socket %u, will try to bind myself\n"),
1352              (unsigned int) 3 + cnt);
1353         cnt++;
1354         while (sctx->lsocks[cnt] != NULL)
1355           GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
1356         GNUNET_free (sctx->lsocks);
1357         sctx->lsocks = NULL;
1358         break;
1359       }
1360     }
1361     unsetenv ("LISTEN_FDS");
1362   }
1363 #else
1364   if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
1365   {
1366     receive_sockets_from_parent (sctx);
1367     putenv ("GNUNET_OS_READ_LSOCKS=");
1368   }
1369 #endif
1370
1371   if ((NULL == sctx->lsocks) &&
1372       (GNUNET_SYSERR ==
1373        GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
1374                                             &sctx->addrs, &sctx->addrlens)))
1375     return GNUNET_SYSERR;
1376   sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1377   sctx->match_uid =
1378       GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1379                                             "UNIX_MATCH_UID");
1380   sctx->match_gid =
1381       GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
1382                                             "UNIX_MATCH_GID");
1383   process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
1384   process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
1385   process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
1386   process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
1387
1388   return GNUNET_OK;
1389 }
1390
1391
1392 /**
1393  * Get the name of the user that'll be used
1394  * to provide the service.
1395  *
1396  * @param sctx service context
1397  * @return value of the 'USERNAME' option
1398  */
1399 static char *
1400 get_user_name (struct GNUNET_SERVICE_Context *sctx)
1401 {
1402   char *un;
1403
1404   if (GNUNET_OK !=
1405       GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
1406                                                "USERNAME", &un))
1407     return NULL;
1408   return un;
1409 }
1410
1411 /**
1412  * Write PID file.
1413  *
1414  * @param sctx service context
1415  * @param pid PID to write (should be equal to 'getpid()'
1416  * @return  GNUNET_OK on success (including no work to be done)
1417  */
1418 static int
1419 write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
1420 {
1421   FILE *pidfd;
1422   char *pif;
1423   char *user;
1424   char *rdir;
1425   int len;
1426
1427   if (NULL == (pif = get_pid_file_name (sctx)))
1428     return GNUNET_OK;           /* no file desired */
1429   user = get_user_name (sctx);
1430   rdir = GNUNET_strdup (pif);
1431   len = strlen (rdir);
1432   while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1433     len--;
1434   rdir[len] = '\0';
1435   if (0 != ACCESS (rdir, F_OK))
1436   {
1437     /* we get to create a directory -- and claim it
1438      * as ours! */
1439     (void) GNUNET_DISK_directory_create (rdir);
1440     if ((NULL != user) && (0 < strlen (user)))
1441       GNUNET_DISK_file_change_owner (rdir, user);
1442   }
1443   if (0 != ACCESS (rdir, W_OK | X_OK))
1444   {
1445     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1446     GNUNET_free (rdir);
1447     GNUNET_free_non_null (user);
1448     GNUNET_free (pif);
1449     return GNUNET_SYSERR;
1450   }
1451   GNUNET_free (rdir);
1452   pidfd = FOPEN (pif, "w");
1453   if (NULL == pidfd)
1454   {
1455     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1456     GNUNET_free (pif);
1457     GNUNET_free_non_null (user);
1458     return GNUNET_SYSERR;
1459   }
1460   if (0 > FPRINTF (pidfd, "%u", pid))
1461     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1462   GNUNET_break (0 == FCLOSE (pidfd));
1463   if ((NULL != user) && (0 < strlen (user)))
1464     GNUNET_DISK_file_change_owner (pif, user);
1465   GNUNET_free_non_null (user);
1466   GNUNET_free (pif);
1467   return GNUNET_OK;
1468 }
1469
1470
1471 /**
1472  * Task run during shutdown.  Stops the server/service.
1473  *
1474  * @param cls the 'struct GNUNET_SERVICE_Context'
1475  * @param tc unused
1476  */
1477 static void
1478 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1479 {
1480   struct GNUNET_SERVICE_Context *service = cls;
1481   struct GNUNET_SERVER_Handle *server = service->server;
1482
1483   service->shutdown_task = GNUNET_SCHEDULER_NO_TASK;
1484   if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
1485     GNUNET_SERVER_stop_listening (server);
1486   else
1487     GNUNET_SERVER_destroy (server);
1488 }
1489
1490
1491 /**
1492  * Initial task for the service.
1493  *
1494  * @param cls service context
1495  * @param tc unused
1496  */
1497 static void
1498 service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1499 {
1500   struct GNUNET_SERVICE_Context *sctx = cls;
1501   unsigned int i;
1502
1503   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
1504     return;
1505   (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
1506   GNUNET_RESOLVER_connect (sctx->cfg);
1507   if (NULL != sctx->lsocks)
1508     sctx->server =
1509         GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
1510                                            sctx->timeout, sctx->require_found);
1511   else
1512     sctx->server =
1513         GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1514                               sctx->timeout, sctx->require_found);
1515   if (NULL == sctx->server)
1516   {
1517     if (NULL != sctx->addrs)
1518     {
1519       i = 0;
1520       while (NULL != sctx->addrs[i])
1521       {
1522         LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"),
1523              sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1524         i++;
1525       }
1526     }
1527     sctx->ret = GNUNET_SYSERR;
1528     return;
1529   }
1530   if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
1531   {
1532     /* install a task that will kill the server
1533      * process if the scheduler ever gets a shutdown signal */
1534     sctx->shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1535                                                         sctx);
1536   }
1537   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1538   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1539   i = 0;
1540   while (NULL != sctx->my_handlers[i].callback)
1541     sctx->my_handlers[i++].callback_cls = sctx;
1542   GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1543   if (-1 != sctx->ready_confirm_fd)
1544   {
1545     GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
1546     GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
1547     sctx->ready_confirm_fd = -1;
1548     write_pid_file (sctx, getpid ());
1549   }
1550   if (NULL != sctx->addrs)
1551   {
1552     i = 0;
1553     while (NULL != sctx->addrs[i])
1554     {
1555       LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
1556            sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1557       i++;
1558     }
1559   }
1560   sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1561 }
1562
1563
1564 /**
1565  * Detach from terminal.
1566  *
1567  * @param sctx service context
1568  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1569  */
1570 static int
1571 detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1572 {
1573 #ifndef MINGW
1574   pid_t pid;
1575   int nullfd;
1576   int filedes[2];
1577
1578   if (0 != PIPE (filedes))
1579   {
1580     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1581     return GNUNET_SYSERR;
1582   }
1583   pid = fork ();
1584   if (pid < 0)
1585   {
1586     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1587     return GNUNET_SYSERR;
1588   }
1589   if (0 != pid)
1590   {
1591     /* Parent */
1592     char c;
1593
1594     GNUNET_break (0 == CLOSE (filedes[1]));
1595     c = 'X';
1596     if (1 != READ (filedes[0], &c, sizeof (char)))
1597       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1598     fflush (stdout);
1599     switch (c)
1600     {
1601     case '.':
1602       exit (0);
1603     case 'I':
1604       LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
1605       break;
1606     case 'S':
1607       LOG (GNUNET_ERROR_TYPE_INFO,
1608            _("Service process could not initialize server function\n"));
1609       break;
1610     case 'X':
1611       LOG (GNUNET_ERROR_TYPE_INFO,
1612            _("Service process failed to report status\n"));
1613       break;
1614     }
1615     exit (1);                   /* child reported error */
1616   }
1617   GNUNET_break (0 == CLOSE (0));
1618   GNUNET_break (0 == CLOSE (1));
1619   GNUNET_break (0 == CLOSE (filedes[0]));
1620   nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
1621   if (nullfd < 0)
1622     return GNUNET_SYSERR;
1623   /* set stdin/stdout to /dev/null */
1624   if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1625   {
1626     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1627     (void) CLOSE (nullfd);
1628     return GNUNET_SYSERR;
1629   }
1630   (void) CLOSE (nullfd);
1631   /* Detach from controlling terminal */
1632   pid = setsid ();
1633   if (-1 == pid)
1634     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1635   sctx->ready_confirm_fd = filedes[1];
1636 #else
1637   /* FIXME: we probably need to do something else
1638    * elsewhere in order to fork the process itself... */
1639   FreeConsole ();
1640 #endif
1641   return GNUNET_OK;
1642 }
1643
1644
1645 /**
1646  * Set user ID.
1647  *
1648  * @param sctx service context
1649  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1650  */
1651 static int
1652 set_user_id (struct GNUNET_SERVICE_Context *sctx)
1653 {
1654   char *user;
1655
1656   if (NULL == (user = get_user_name (sctx)))
1657     return GNUNET_OK;           /* keep */
1658 #ifndef MINGW
1659   struct passwd *pws;
1660
1661   errno = 0;
1662   pws = getpwnam (user);
1663   if (NULL == pws)
1664   {
1665     LOG (GNUNET_ERROR_TYPE_ERROR,
1666          _("Cannot obtain information about user `%s': %s\n"), user,
1667          errno == 0 ? _("No such user") : STRERROR (errno));
1668     GNUNET_free (user);
1669     return GNUNET_SYSERR;
1670   }
1671   if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1672 #if HAVE_INITGROUPS
1673       (0 != initgroups (user, pws->pw_gid)) ||
1674 #endif
1675       (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1676   {
1677     if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1678         (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1679     {
1680       LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
1681            user, STRERROR (errno));
1682       GNUNET_free (user);
1683       return GNUNET_SYSERR;
1684     }
1685   }
1686 #endif
1687   GNUNET_free (user);
1688   return GNUNET_OK;
1689 }
1690
1691
1692 /**
1693  * Delete the PID file that was created by our parent.
1694  *
1695  * @param sctx service context
1696  */
1697 static void
1698 pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
1699 {
1700   char *pif = get_pid_file_name (sctx);
1701
1702   if (NULL == pif)
1703     return;                     /* no PID file */
1704   if (0 != UNLINK (pif))
1705     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1706   GNUNET_free (pif);
1707 }
1708
1709
1710 /**
1711  * Run a standard GNUnet service startup sequence (initialize loggers
1712  * and configuration, parse options).
1713  *
1714  * @param argc number of command line arguments
1715  * @param argv command line arguments
1716  * @param service_name our service name
1717  * @param options service options
1718  * @param task main task of the service
1719  * @param task_cls closure for task
1720  * @return GNUNET_SYSERR on error, GNUNET_OK
1721  *         if we shutdown nicely
1722  */
1723 int
1724 GNUNET_SERVICE_run (int argc, char *const *argv, const char *service_name,
1725                     enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_Main task,
1726                     void *task_cls)
1727 {
1728 #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
1729
1730   int err;
1731   int ret;
1732   char *cfg_fn;
1733   char *loglev;
1734   char *logfile;
1735   int do_daemonize;
1736   unsigned int i;
1737   unsigned long long skew_offset;
1738   unsigned long long skew_variance;
1739   long long clock_offset;
1740   struct GNUNET_SERVICE_Context sctx;
1741   struct GNUNET_CONFIGURATION_Handle *cfg;
1742
1743   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1744     GNUNET_GETOPT_OPTION_CFG_FILE (&cfg_fn),
1745     {'d', "daemonize", NULL,
1746      gettext_noop ("do daemonize (detach from terminal)"), 0,
1747      GNUNET_GETOPT_set_one, &do_daemonize},
1748     GNUNET_GETOPT_OPTION_HELP (NULL),
1749     GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1750     GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1751     GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1752     GNUNET_GETOPT_OPTION_END
1753   };
1754   err = 1;
1755   do_daemonize = 0;
1756   logfile = NULL;
1757   loglev = NULL;
1758   cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
1759   memset (&sctx, 0, sizeof (sctx));
1760   sctx.options = options;
1761   sctx.ready_confirm_fd = -1;
1762   sctx.ret = GNUNET_OK;
1763   sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1764   sctx.task = task;
1765   sctx.task_cls = task_cls;
1766   sctx.service_name = service_name;
1767   sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1768
1769   /* setup subsystems */
1770   ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1771   if (GNUNET_SYSERR == ret)
1772     goto shutdown;
1773   if (GNUNET_NO == ret)
1774   {
1775     err = 0;
1776     goto shutdown;
1777   }
1778   if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1779     HANDLE_ERROR;
1780   if (GNUNET_YES ==
1781       GNUNET_DISK_file_test (cfg_fn))
1782     (void) GNUNET_CONFIGURATION_load (cfg, cfg_fn);
1783   else
1784   {
1785     (void) GNUNET_CONFIGURATION_load (cfg, NULL);
1786     if (0 != strcmp (cfg_fn, GNUNET_DEFAULT_USER_CONFIG_FILE))
1787       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1788                   _("Could not access configuration file `%s'\n"),
1789                   cfg_fn);
1790   }
1791   if (GNUNET_OK != setup_service (&sctx))
1792     goto shutdown;
1793   if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1794     HANDLE_ERROR;
1795   if (GNUNET_OK != set_user_id (&sctx))
1796     goto shutdown;
1797   LOG (GNUNET_ERROR_TYPE_DEBUG,
1798        "Service `%s' runs with configuration from `%s'\n", service_name, cfg_fn);
1799   if ((GNUNET_OK ==
1800        GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
1801                                               "SKEW_OFFSET", &skew_offset)) &&
1802       (GNUNET_OK ==
1803        GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
1804                                               "SKEW_VARIANCE", &skew_variance)))
1805   {
1806     clock_offset = skew_offset - skew_variance;
1807     GNUNET_TIME_set_offset (clock_offset);
1808     LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
1809   }
1810   /* actually run service */
1811   err = 0;
1812   GNUNET_SCHEDULER_run (&service_task, &sctx);
1813   /* shutdown */
1814   if ((1 == do_daemonize) && (NULL != sctx.server))
1815     pid_file_delete (&sctx);
1816   GNUNET_free_non_null (sctx.my_handlers);
1817
1818 shutdown:
1819   if (-1 != sctx.ready_confirm_fd)
1820   {
1821     if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1822       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1823     GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
1824   }
1825 #if HAVE_MALLINFO
1826   {
1827     char *counter;
1828
1829     if ( (GNUNET_YES ==
1830           GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
1831                                            "GAUGER_HEAP")) &&
1832          (GNUNET_OK ==
1833           GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
1834                                                  "GAUGER_HEAP",
1835                                                  &counter)) )
1836     {
1837       struct mallinfo mi;
1838
1839       mi = mallinfo ();
1840       GAUGER (service_name, counter, mi.usmblks, "blocks");
1841       GNUNET_free (counter);
1842     }
1843   }
1844 #endif
1845   GNUNET_SPEEDUP_stop_ ();
1846   GNUNET_CONFIGURATION_destroy (cfg);
1847   i = 0;
1848   if (NULL != sctx.addrs)
1849     while (NULL != sctx.addrs[i])
1850       GNUNET_free (sctx.addrs[i++]);
1851   GNUNET_free_non_null (sctx.addrs);
1852   GNUNET_free_non_null (sctx.addrlens);
1853   GNUNET_free_non_null (logfile);
1854   GNUNET_free_non_null (loglev);
1855   GNUNET_free (cfg_fn);
1856   GNUNET_free_non_null (sctx.v4_denied);
1857   GNUNET_free_non_null (sctx.v6_denied);
1858   GNUNET_free_non_null (sctx.v4_allowed);
1859   GNUNET_free_non_null (sctx.v6_allowed);
1860
1861   return err ? GNUNET_SYSERR : sctx.ret;
1862 }
1863
1864
1865 /**
1866  * Run a service startup sequence within an existing
1867  * initialized system.
1868  *
1869  * @param service_name our service name
1870  * @param cfg configuration to use
1871  * @param options service options
1872  * @return NULL on error, service handle
1873  */
1874 struct GNUNET_SERVICE_Context *
1875 GNUNET_SERVICE_start (const char *service_name,
1876                       const struct GNUNET_CONFIGURATION_Handle *cfg,
1877                       enum GNUNET_SERVICE_Options options)
1878 {
1879   int i;
1880   struct GNUNET_SERVICE_Context *sctx;
1881
1882   sctx = GNUNET_malloc (sizeof (struct GNUNET_SERVICE_Context));
1883   sctx->ready_confirm_fd = -1;  /* no daemonizing */
1884   sctx->ret = GNUNET_OK;
1885   sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1886   sctx->service_name = service_name;
1887   sctx->cfg = cfg;
1888   sctx->options = options;
1889
1890   /* setup subsystems */
1891   if (GNUNET_OK != setup_service (sctx))
1892   {
1893     GNUNET_SERVICE_stop (sctx);
1894     return NULL;
1895   }
1896   if (NULL != sctx->lsocks)
1897     sctx->server =
1898         GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
1899                                            sctx->timeout, sctx->require_found);
1900   else
1901     sctx->server =
1902         GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
1903                               sctx->timeout, sctx->require_found);
1904
1905   if (NULL == sctx->server)
1906   {
1907     GNUNET_SERVICE_stop (sctx);
1908     return NULL;
1909   }
1910   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1911   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1912   i = 0;
1913   while ((sctx->my_handlers[i].callback != NULL))
1914     sctx->my_handlers[i++].callback_cls = sctx;
1915   GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1916   return sctx;
1917 }
1918
1919
1920 /**
1921  * Obtain the server used by a service.  Note that the server must NOT
1922  * be destroyed by the caller.
1923  *
1924  * @param ctx the service context returned from the start function
1925  * @return handle to the server for this service, NULL if there is none
1926  */
1927 struct GNUNET_SERVER_Handle *
1928 GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
1929 {
1930   return ctx->server;
1931 }
1932
1933
1934 /**
1935  * Stop a service that was started with "GNUNET_SERVICE_start".
1936  *
1937  * @param sctx the service context returned from the start function
1938  */
1939 void
1940 GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
1941 {
1942   unsigned int i;
1943
1944 #if HAVE_MALLINFO
1945   {
1946     char *counter;
1947
1948     if ( (GNUNET_YES ==
1949           GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
1950                                            "GAUGER_HEAP")) &&
1951          (GNUNET_OK ==
1952           GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
1953                                                  "GAUGER_HEAP",
1954                                                  &counter)) )
1955     {
1956       struct mallinfo mi;
1957
1958       mi = mallinfo ();
1959       GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1960       GNUNET_free (counter);
1961     }
1962   }
1963 #endif
1964   if (GNUNET_SCHEDULER_NO_TASK != sctx->shutdown_task)
1965   {
1966     GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1967     sctx->shutdown_task = GNUNET_SCHEDULER_NO_TASK;
1968   }
1969   if (NULL != sctx->server)
1970     GNUNET_SERVER_destroy (sctx->server);
1971   GNUNET_free_non_null (sctx->my_handlers);
1972   if (NULL != sctx->addrs)
1973   {
1974     i = 0;
1975     while (NULL != sctx->addrs[i])
1976       GNUNET_free (sctx->addrs[i++]);
1977     GNUNET_free (sctx->addrs);
1978   }
1979   GNUNET_free_non_null (sctx->addrlens);
1980   GNUNET_free_non_null (sctx->v4_denied);
1981   GNUNET_free_non_null (sctx->v6_denied);
1982   GNUNET_free_non_null (sctx->v4_allowed);
1983   GNUNET_free_non_null (sctx->v6_allowed);
1984   GNUNET_free (sctx);
1985 }
1986
1987
1988 /* end of service.c */