setup code for new service api
[oweals/gnunet.git] / src / util / service_new.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2016 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file util/service_new.c
23  * @brief functions related to starting services (redesign)
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
33 /**
34  * Information the service tracks per listen operation.
35  */
36 struct ServiceListenContext
37 {
38
39   /**
40    * Kept in a DLL.
41    */
42   struct ServiceListenContext *next;
43
44   /**
45    * Kept in a DLL.
46    */
47   struct ServiceListenContext *prev;
48
49   /**
50    * Service this listen context belongs to.
51    */
52   struct GNUNET_SERVICE_Handle *sh;
53
54   /**
55    * Socket we are listening on.
56    */
57   struct GNUNET_NETWORK_Handle *listen_socket;
58
59   /**
60    * Task scheduled to do the listening.
61    */
62   struct GNUNET_SCHEDULER_Task *listen_task;
63
64 };
65
66
67 /**
68  * Handle to a service.
69  */
70 struct GNUNET_SERVICE_Handle
71 {
72   /**
73    * Our configuration.
74    */
75   const struct GNUNET_CONFIGURATION_Handle *cfg;
76
77   /**
78    * Name of our service.
79    */
80   const char *service_name;
81
82   /**
83    * Main service-specific task to run.
84    */
85   GNUNET_SERVICE_InitCallback service_init_cb;
86
87   /**
88    * Function to call when clients connect.
89    */
90   GNUNET_SERVICE_ConnectHandler connect_cb;
91
92   /**
93    * Function to call when clients disconnect / are disconnected.
94    */
95   GNUNET_SERVICE_DisconnectHandler disconnect_cb;
96
97   /**
98    * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
99    */
100   void *cb_cls;
101
102   /**
103    * DLL of listen sockets used to accept new connections.
104    */
105   struct ServiceListenContext *slc_head;
106
107   /**
108    * DLL of listen sockets used to accept new connections.
109    */
110   struct ServiceListenContext *slc_tail;
111
112   /**
113    * Our clients, kept in a DLL.
114    */
115   struct GNUNET_SERVICE_Client *clients_head;
116
117   /**
118    * Our clients, kept in a DLL.
119    */
120   struct GNUNET_SERVICE_Client *clients_tail;
121
122   /**
123    * Message handlers to use for all clients.
124    */
125   const struct GNUNET_MQ_MessageHandler *handlers;
126
127   /**
128    * Closure for @e task.
129    */
130   void *task_cls;
131
132   /**
133    * IPv4 addresses that are not allowed to connect.
134    */
135   struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
136
137   /**
138    * IPv6 addresses that are not allowed to connect.
139    */
140   struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
141
142   /**
143    * IPv4 addresses that are allowed to connect (if not
144    * set, all are allowed).
145    */
146   struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
147
148   /**
149    * IPv6 addresses that are allowed to connect (if not
150    * set, all are allowed).
151    */
152   struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
153
154   /**
155    * Do we require a matching UID for UNIX domain socket connections?
156    * #GNUNET_NO means that the UID does not have to match (however,
157    * @e match_gid may still impose other access control checks).
158    */
159   int match_uid;
160
161   /**
162    * Do we require a matching GID for UNIX domain socket connections?
163    * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
164    * checking that the client's UID is in our group OR that the
165    * client's GID is our GID.  If both "match_gid" and @e match_uid are
166    * #GNUNET_NO, all users on the local system have access.
167    */
168   int match_gid;
169
170   /**
171    * Set to #GNUNET_YES if we got a shutdown signal and terminate
172    * the service if #have_non_monitor_clients() returns #GNUNET_YES.
173    */
174   int got_shutdown;
175
176   /**
177    * Our options.
178    */
179   enum GNUNET_SERVICE_Options options;
180
181   /**
182    * If we are daemonizing, this FD is set to the
183    * pipe to the parent.  Send '.' if we started
184    * ok, '!' if not.  -1 if we are not daemonizing.
185    */
186   int ready_confirm_fd;
187
188   /**
189    * Overall success/failure of the service start.
190    */
191   int ret;
192
193   /**
194    * Inherited listening sockets, only
195    * used during initialization.
196    * FIXME: remove from struct
197    */
198   struct GNUNET_NETWORK_Handle **lsocks;
199 };
200
201
202 /**
203  * Handle to a client that is connected to a service.
204  */
205 struct GNUNET_SERVICE_Client
206 {
207
208   /**
209    * Kept in a DLL.
210    */
211   struct GNUNET_SERVICE_Client *next;
212
213   /**
214    * Kept in a DLL.
215    */
216   struct GNUNET_SERVICE_Client *prev;
217
218   /**
219    * Server that this client belongs to.
220    */
221   struct GNUNET_SERVER_Handle *sh;
222
223   /**
224    * Socket of this client.
225    */
226   struct GNUNET_NETWORK_Handle *sock;
227
228   /**
229    * Message queue for the client.
230    */
231   struct GNUNET_MQ_Handle *mq;
232
233   /**
234    * Tokenizer we use for processing incoming data.
235    */
236   struct GNUNET_SERVER_MessageStreamTokenizer *mst;
237
238   /**
239    * Task that warns about missing calls to
240    * #GNUNET_SERVICE_client_continue().
241    */
242   struct GNUNET_SCHEDULER_Task *warn_task;
243
244   /**
245    * Task that receives data from the client to
246    * pass it to the handlers.
247    */
248   struct GNUNET_SCHEDULER_Task *recv_task;
249
250   /**
251    * Task that transmit data to the client.
252    */
253   struct GNUNET_SCHEDULER_Task *send_task;
254
255   /**
256    * User context value, value returned from
257    * the connect callback.
258    */
259   void *user_context;
260
261   /**
262    * Persist the file handle for this client no matter what happens,
263    * force the OS to close once the process actually dies.  Should only
264    * be used in special cases!
265    */
266   int persist;
267
268   /**
269    * Is this client a 'monitor' client that should not be counted
270    * when deciding on destroying the server during soft shutdown?
271    * (see also #GNUNET_SERVICE_start)
272    */
273   int is_monitor;
274
275   /**
276    * Type of last message processed (for warn_no_receive_done).
277    */
278   uint16_t warn_type;
279 };
280
281
282 /**
283  * Check if any of the clients we have left are unrelated to
284  * monitoring.
285  *
286  * @param sh service to check clients for
287  * @return #GNUNET_YES if we have non-monitoring clients left
288  */
289 static int
290 have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
291 {
292   struct GNUNET_SERVICE_Client *client;
293
294   for (client = sh->clients_head;NULL != client; client = client->next)
295   {
296     if (client->is_monitor)
297       continue;
298     return GNUNET_YES;
299   }
300   return GNUNET_NO;
301 }
302
303
304 /**
305  * Shutdown task triggered when a service should be terminated.
306  * This considers active clients and the service options to see
307  * how this specific service is to be terminated, and depending
308  * on this proceeds with the shutdown logic.
309  *
310  * @param cls our `struct GNUNET_SERVICE_Handle`
311  */
312 static void
313 service_main (void *cls)
314 {
315   struct GNUNET_SERVICE_Handle *sh = cls;
316   struct GNUNET_SERVICE_Client *client;
317   int alive;
318
319   switch (sh->options)
320   {
321   case GNUNET_SERVICE_OPTION_NONE:
322     GNUNET_SERVICE_shutdown (sh);
323     break;
324   case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
325     /* This task should never be run if we are using
326        the manual shutdown. */
327     GNUNET_assert (0);
328     break;
329   case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
330     sh->got_shutdown = GNUNET_YES;
331     GNUNET_SERVICE_suspend (sh);
332     if (GNUNET_NO == have_non_monitor_clients (sh))
333       GNUNET_SERVICE_shutdown (sh);
334     break;
335   }
336 }
337
338
339 /**
340  * First task run by any service.  Initializes our shutdown task,
341  * starts the listening operation on our listen sockets and launches
342  * the custom logic of the application service.
343  *
344  * @param cls our `struct GNUNET_SERVICE_Handle`
345  */
346 static void
347 service_main (void *cls)
348 {
349   struct GNUNET_SERVICE_Handle *sh = cls;
350
351   if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options)
352     GNUNET_SCHEDULER_add_shutdown (&service_shutdown,
353                                    sh);
354   GNUNET_SERVICE_resume (sh);
355   sh->service_init_cb (sh->cb_cls,
356                        sh->cfg,
357                        sh);
358 }
359
360
361 /**
362  * Parse an IPv4 access control list.
363  *
364  * @param ret location where to write the ACL (set)
365  * @param sh service context to use to get the configuration
366  * @param option name of the ACL option to parse
367  * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
368  *         no ACL configured)
369  */
370 static int
371 process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
372               struct GNUNET_SERVICE_Context *sh,
373               const char *option)
374 {
375   char *opt;
376
377   if (!GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
378   {
379     *ret = NULL;
380     return GNUNET_OK;
381   }
382   GNUNET_break (GNUNET_OK ==
383                 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
384                                                        sh->service_name,
385                                                        option, &opt));
386   if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
387   {
388     LOG (GNUNET_ERROR_TYPE_WARNING,
389          _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
390          opt, sh->service_name, option);
391     GNUNET_free (opt);
392     return GNUNET_SYSERR;
393   }
394   GNUNET_free (opt);
395   return GNUNET_OK;
396 }
397
398
399 /**
400  * Parse an IPv6 access control list.
401  *
402  * @param ret location where to write the ACL (set)
403  * @param sh service context to use to get the configuration
404  * @param option name of the ACL option to parse
405  * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
406  *         no ACL configured)
407  */
408 static int
409 process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
410               struct GNUNET_SERVICE_Context *sh,
411               const char *option)
412 {
413   char *opt;
414
415   if (!GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
416   {
417     *ret = NULL;
418     return GNUNET_OK;
419   }
420   GNUNET_break (GNUNET_OK ==
421                 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
422                                                        sh->service_name,
423                                                        option, &opt));
424   if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
425   {
426     LOG (GNUNET_ERROR_TYPE_WARNING,
427          _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
428          opt, sh->service_name, option);
429     GNUNET_free (opt);
430     return GNUNET_SYSERR;
431   }
432   GNUNET_free (opt);
433   return GNUNET_OK;
434 }
435
436
437 /**
438  * Get the list of addresses that a server for the given service
439  * should bind to.
440  *
441  * @param service_name name of the service
442  * @param cfg configuration (which specifies the addresses)
443  * @param addrs set (call by reference) to an array of pointers to the
444  *              addresses the server should bind to and listen on; the
445  *              array will be NULL-terminated (on success)
446  * @param addr_lens set (call by reference) to an array of the lengths
447  *              of the respective `struct sockaddr` struct in the @a addrs
448  *              array (on success)
449  * @return number of addresses found on success,
450  *              #GNUNET_SYSERR if the configuration
451  *              did not specify reasonable finding information or
452  *              if it specified a hostname that could not be resolved;
453  *              #GNUNET_NO if the number of addresses configured is
454  *              zero (in this case, `*addrs` and `*addr_lens` will be
455  *              set to NULL).
456  */
457 static int
458 get_server_addresses (const char *service_name,
459                                      const struct GNUNET_CONFIGURATION_Handle *cfg,
460                                      struct sockaddr ***addrs,
461                                      socklen_t ** addr_lens)
462 {
463   int disablev6;
464   struct GNUNET_NETWORK_Handle *desc;
465   unsigned long long port;
466   char *unixpath;
467   struct addrinfo hints;
468   struct addrinfo *res;
469   struct addrinfo *pos;
470   struct addrinfo *next;
471   unsigned int i;
472   int resi;
473   int ret;
474   int abstract;
475   struct sockaddr **saddrs;
476   socklen_t *saddrlens;
477   char *hostname;
478
479   *addrs = NULL;
480   *addr_lens = NULL;
481   desc = NULL;
482   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
483   {
484     if (GNUNET_SYSERR ==
485         (disablev6 =
486          GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
487       return GNUNET_SYSERR;
488   }
489   else
490     disablev6 = GNUNET_NO;
491
492   if (! disablev6)
493   {
494     /* probe IPv6 support */
495     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
496     if (NULL == desc)
497     {
498       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
499           (EACCES == errno))
500       {
501         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
502         return GNUNET_SYSERR;
503       }
504       LOG (GNUNET_ERROR_TYPE_INFO,
505            _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
506            service_name, STRERROR (errno));
507       disablev6 = GNUNET_YES;
508     }
509     else
510     {
511       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
512       desc = NULL;
513     }
514   }
515
516   port = 0;
517   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
518   {
519     if (GNUNET_OK !=
520         GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
521                                                "PORT", &port))
522     {
523       LOG (GNUNET_ERROR_TYPE_ERROR,
524            _("Require valid port number for service `%s' in configuration!\n"),
525            service_name);
526     }
527     if (port > 65535)
528     {
529       LOG (GNUNET_ERROR_TYPE_ERROR,
530            _("Require valid port number for service `%s' in configuration!\n"),
531            service_name);
532       return GNUNET_SYSERR;
533     }
534   }
535
536   if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
537   {
538     GNUNET_break (GNUNET_OK ==
539                   GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
540                                                          "BINDTO", &hostname));
541   }
542   else
543     hostname = NULL;
544
545   unixpath = NULL;
546   abstract = GNUNET_NO;
547 #ifdef AF_UNIX
548   if ((GNUNET_YES ==
549        GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
550       (GNUNET_OK ==
551        GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
552                                               &unixpath)) &&
553       (0 < strlen (unixpath)))
554   {
555     /* probe UNIX support */
556     struct sockaddr_un s_un;
557
558     if (strlen (unixpath) >= sizeof (s_un.sun_path))
559     {
560       LOG (GNUNET_ERROR_TYPE_WARNING,
561            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
562            (unsigned long long) sizeof (s_un.sun_path));
563       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
564       LOG (GNUNET_ERROR_TYPE_INFO,
565            _("Using `%s' instead\n"),
566            unixpath);
567     }
568 #ifdef LINUX
569     abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
570                                                      "TESTING",
571                                                      "USE_ABSTRACT_SOCKETS");
572     if (GNUNET_SYSERR == abstract)
573       abstract = GNUNET_NO;
574 #endif
575     if ((GNUNET_YES != abstract)
576         && (GNUNET_OK !=
577             GNUNET_DISK_directory_create_for_file (unixpath)))
578       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
579                                 "mkdir",
580                                 unixpath);
581   }
582   if (NULL != unixpath)
583   {
584     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
585     if (NULL == desc)
586     {
587       if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
588           (EACCES == errno))
589       {
590         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
591         GNUNET_free_non_null (hostname);
592         GNUNET_free (unixpath);
593         return GNUNET_SYSERR;
594       }
595       LOG (GNUNET_ERROR_TYPE_INFO,
596            _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
597            service_name,
598            STRERROR (errno));
599       GNUNET_free (unixpath);
600       unixpath = NULL;
601     }
602     else
603     {
604       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
605       desc = NULL;
606     }
607   }
608 #endif
609
610   if ((0 == port) && (NULL == unixpath))
611   {
612     LOG (GNUNET_ERROR_TYPE_ERROR,
613          _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
614          service_name);
615     GNUNET_free_non_null (hostname);
616     return GNUNET_SYSERR;
617   }
618   if (0 == port)
619   {
620     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
621     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
622     add_unixpath (saddrs, saddrlens, unixpath, abstract);
623     GNUNET_free_non_null (unixpath);
624     GNUNET_free_non_null (hostname);
625     *addrs = saddrs;
626     *addr_lens = saddrlens;
627     return 1;
628   }
629
630   if (NULL != hostname)
631   {
632     LOG (GNUNET_ERROR_TYPE_DEBUG,
633          "Resolving `%s' since that is where `%s' will bind to.\n",
634          hostname,
635          service_name);
636     memset (&hints, 0, sizeof (struct addrinfo));
637     if (disablev6)
638       hints.ai_family = AF_INET;
639     hints.ai_protocol = IPPROTO_TCP;
640     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
641         (NULL == res))
642     {
643       LOG (GNUNET_ERROR_TYPE_ERROR,
644            _("Failed to resolve `%s': %s\n"),
645            hostname,
646            gai_strerror (ret));
647       GNUNET_free (hostname);
648       GNUNET_free_non_null (unixpath);
649       return GNUNET_SYSERR;
650     }
651     next = res;
652     i = 0;
653     while (NULL != (pos = next))
654     {
655       next = pos->ai_next;
656       if ((disablev6) && (pos->ai_family == AF_INET6))
657         continue;
658       i++;
659     }
660     if (0 == i)
661     {
662       LOG (GNUNET_ERROR_TYPE_ERROR,
663            _("Failed to find %saddress for `%s'.\n"),
664            disablev6 ? "IPv4 " : "",
665            hostname);
666       freeaddrinfo (res);
667       GNUNET_free (hostname);
668       GNUNET_free_non_null (unixpath);
669       return GNUNET_SYSERR;
670     }
671     resi = i;
672     if (NULL != unixpath)
673       resi++;
674     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
675     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
676     i = 0;
677     if (NULL != unixpath)
678     {
679       add_unixpath (saddrs, saddrlens, unixpath, abstract);
680       i++;
681     }
682     next = res;
683     while (NULL != (pos = next))
684     {
685       next = pos->ai_next;
686       if ((disablev6) && (AF_INET6 == pos->ai_family))
687         continue;
688       if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
689         continue;               /* not TCP */
690       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
691         continue;               /* huh? */
692       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
693            service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
694       if (AF_INET == pos->ai_family)
695       {
696         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
697         saddrlens[i] = pos->ai_addrlen;
698         saddrs[i] = GNUNET_malloc (saddrlens[i]);
699         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
700         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
701       }
702       else
703       {
704         GNUNET_assert (AF_INET6 == pos->ai_family);
705         GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
706         saddrlens[i] = pos->ai_addrlen;
707         saddrs[i] = GNUNET_malloc (saddrlens[i]);
708         GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
709         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
710       }
711       i++;
712     }
713     GNUNET_free (hostname);
714     freeaddrinfo (res);
715     resi = i;
716   }
717   else
718   {
719     /* will bind against everything, just set port */
720     if (disablev6)
721     {
722       /* V4-only */
723       resi = 1;
724       if (NULL != unixpath)
725         resi++;
726       i = 0;
727       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
728       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
729       if (NULL != unixpath)
730       {
731         add_unixpath (saddrs, saddrlens, unixpath, abstract);
732         i++;
733       }
734       saddrlens[i] = sizeof (struct sockaddr_in);
735       saddrs[i] = GNUNET_malloc (saddrlens[i]);
736 #if HAVE_SOCKADDR_IN_SIN_LEN
737       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
738 #endif
739       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
740       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
741     }
742     else
743     {
744       /* dual stack */
745       resi = 2;
746       if (NULL != unixpath)
747         resi++;
748       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
749       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
750       i = 0;
751       if (NULL != unixpath)
752       {
753         add_unixpath (saddrs, saddrlens, unixpath, abstract);
754         i++;
755       }
756       saddrlens[i] = sizeof (struct sockaddr_in6);
757       saddrs[i] = GNUNET_malloc (saddrlens[i]);
758 #if HAVE_SOCKADDR_IN_SIN_LEN
759       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
760 #endif
761       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
762       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
763       i++;
764       saddrlens[i] = sizeof (struct sockaddr_in);
765       saddrs[i] = GNUNET_malloc (saddrlens[i]);
766 #if HAVE_SOCKADDR_IN_SIN_LEN
767       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
768 #endif
769       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
770       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
771     }
772   }
773   GNUNET_free_non_null (unixpath);
774   *addrs = saddrs;
775   *addr_lens = saddrlens;
776   return resi;
777 }
778
779
780 #ifdef MINGW
781 /**
782  * Read listen sockets from the parent process (ARM).
783  *
784  * @param sh service context to initialize
785  * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
786  * and #GNUNET_SYSERR on error.
787  */
788 static int
789 receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sh)
790 {
791   const char *env_buf;
792   int fail;
793   uint64_t count;
794   uint64_t i;
795   HANDLE lsocks_pipe;
796
797   env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
798   if ((NULL == env_buf) || (strlen (env_buf) <= 0))
799     return GNUNET_NO;
800   /* Using W32 API directly here, because this pipe will
801    * never be used outside of this function, and it's just too much of a bother
802    * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
803    */
804   lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
805   if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
806     return GNUNET_NO;
807   fail = 1;
808   do
809   {
810     int ret;
811     int fail2;
812     DWORD rd;
813
814     ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
815     if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
816       break;
817     sh->lsocks =
818         GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
819
820     fail2 = 1;
821     for (i = 0; i < count; i++)
822     {
823       WSAPROTOCOL_INFOA pi;
824       uint64_t size;
825       SOCKET s;
826
827       ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
828       if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
829         break;
830       ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
831       if ( (0 == ret) || (sizeof (pi) != rd))
832         break;
833       s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
834       sh->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
835       if (NULL == sh->lsocks[i])
836         break;
837       else if (i == count - 1)
838         fail2 = 0;
839     }
840     if (fail2)
841       break;
842     sh->lsocks[count] = NULL;
843     fail = 0;
844   }
845   while (fail);
846
847   CloseHandle (lsocks_pipe);
848
849   if (fail)
850   {
851     LOG (GNUNET_ERROR_TYPE_ERROR,
852          _("Could not access a pre-bound socket, will try to bind myself\n"));
853     for (i = 0; (i < count) && (NULL != sh->lsocks[i]); i++)
854       GNUNET_break (0 == GNUNET_NETWORK_socket_close (sh->lsocks[i]));
855     GNUNET_free_non_null (sh->lsocks);
856     sh->lsocks = NULL;
857     return GNUNET_NO;
858   }
859   return GNUNET_YES;
860 }
861 #endif
862
863
864 /**
865  * Create and initialize a listen socket for the server.
866  *
867  * @param server_addr address to listen on
868  * @param socklen length of @a server_addr
869  * @return NULL on error, otherwise the listen socket
870  */
871 static struct GNUNET_NETWORK_Handle *
872 open_listen_socket (const struct sockaddr *server_addr,
873                     socklen_t socklen)
874 {
875   struct GNUNET_NETWORK_Handle *sock;
876   uint16_t port;
877   int eno;
878
879   switch (server_addr->sa_family)
880   {
881   case AF_INET:
882     port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
883     break;
884   case AF_INET6:
885     port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
886     break;
887   case AF_UNIX:
888     port = 0;
889     break;
890   default:
891     GNUNET_break (0);
892     port = 0;
893     break;
894   }
895   sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
896   if (NULL == sock)
897   {
898     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
899     errno = 0;
900     return NULL;
901   }
902   /* bind the socket */
903   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
904   {
905     eno = errno;
906     if (EADDRINUSE != errno)
907     {
908       /* we don't log 'EADDRINUSE' here since an IPv4 bind may
909        * fail if we already took the port on IPv6; if both IPv4 and
910        * IPv6 binds fail, then our caller will log using the
911        * errno preserved in 'eno' */
912       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
913                     "bind");
914       if (0 != port)
915         LOG (GNUNET_ERROR_TYPE_ERROR,
916              _("`%s' failed for port %d (%s).\n"),
917              "bind",
918              port,
919              (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
920       eno = 0;
921     }
922     else
923     {
924       if (0 != port)
925         LOG (GNUNET_ERROR_TYPE_WARNING,
926              _("`%s' failed for port %d (%s): address already in use\n"),
927              "bind", port,
928              (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
929       else if (AF_UNIX == server_addr->sa_family)
930       {
931         LOG (GNUNET_ERROR_TYPE_WARNING,
932              _("`%s' failed for `%s': address already in use\n"),
933              "bind",
934              GNUNET_a2s (server_addr, socklen));
935       }
936     }
937     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
938     errno = eno;
939     return NULL;
940   }
941   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
942   {
943     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
944                   "listen");
945     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
946     errno = 0;
947     return NULL;
948   }
949   if (0 != port)
950     LOG (GNUNET_ERROR_TYPE_DEBUG,
951          "Server starts to listen on port %u.\n",
952          port);
953   return sock;
954 }
955
956
957
958
959 /**
960  * Setup service handle
961  *
962  * Configuration may specify:
963  * - PORT (where to bind to for TCP)
964  * - UNIXPATH (where to bind to for UNIX domain sockets)
965  * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
966  * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
967  * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
968  * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
969  * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
970  * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
971  *
972  * @param sh service context to initialize
973  * @return #GNUNET_OK if configuration succeeded
974  */
975 static int
976 setup_service (struct GNUNET_SERVICE_Handle *sh)
977 {
978   struct GNUNET_TIME_Relative idleout;
979   int tolerant;
980
981 #ifndef MINGW
982   const char *nfds;
983   unsigned int cnt;
984   int flags;
985 #endif
986
987   if (GNUNET_CONFIGURATION_have_value
988       (sh->cfg, sh->service_name, "TOLERANT"))
989   {
990     if (GNUNET_SYSERR ==
991         (tolerant =
992          GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name,
993                                                "TOLERANT")))
994     {
995       LOG (GNUNET_ERROR_TYPE_ERROR,
996            _("Specified value for `%s' of service `%s' is invalid\n"),
997            "TOLERANT", sh->service_name);
998       return GNUNET_SYSERR;
999     }
1000   }
1001   else
1002     tolerant = GNUNET_NO;
1003
1004 #ifndef MINGW
1005   errno = 0;
1006   if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1007       (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
1008       (cnt + 4 < FD_SETSIZE))
1009   {
1010     sh->lsocks =
1011         GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
1012     while (0 < cnt--)
1013     {
1014       flags = fcntl (3 + cnt, F_GETFD);
1015       if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
1016           (NULL ==
1017            (sh->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1018       {
1019         LOG (GNUNET_ERROR_TYPE_ERROR,
1020              _
1021              ("Could not access pre-bound socket %u, will try to bind myself\n"),
1022              (unsigned int) 3 + cnt);
1023         cnt++;
1024         while (sh->lsocks[cnt] != NULL)
1025           GNUNET_break (0 == GNUNET_NETWORK_socket_close (sh->lsocks[cnt++]));
1026         GNUNET_free (sh->lsocks);
1027         sh->lsocks = NULL;
1028         break;
1029       }
1030     }
1031     unsetenv ("LISTEN_FDS");
1032   }
1033 #else
1034   if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
1035   {
1036     receive_sockets_from_parent (sh);
1037     putenv ("GNUNET_OS_READ_LSOCKS=");
1038   }
1039 #endif
1040
1041   if (NULL != sh->lsocks)
1042   {
1043     /* listen only on inherited sockets if we have any */
1044     struct GNUNET_NETWORK_Handle **ls = sh->lsocks;
1045     for (; NULL != *ls; ls++)
1046     {
1047       struct ServiceListenContext *slc;
1048
1049       slc = GNUNET_new (struct ServiceListenContext);
1050       slc->listen_socket = *ls;
1051       GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1052     }
1053     GNUNET_free_non_null (sh->lsocks);
1054   }
1055   else
1056   {
1057     struct sockaddr **addrs;
1058     socklen_t *addrlens;
1059     int num;
1060
1061     num = get_server_addresses (sh->service_name, sh->cfg,
1062                                                &addrs, &addrlens)));
1063     if (GNUNET_SYSERR == num)
1064       return GNUNET_SYSERR;
1065
1066     for (int i = 0; i < num; i++)
1067     {
1068       struct ServiceListenContext *slc;
1069
1070       slc = GNUNET_new (struct ServiceListenContext);
1071       slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]);
1072       GNUNET_break (NULL != slc->listen_socket);
1073       GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1074     }
1075   }
1076
1077   sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1078   sh->match_uid =
1079       GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name,
1080                                             "UNIX_MATCH_UID");
1081   sh->match_gid =
1082       GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, sh->service_name,
1083                                             "UNIX_MATCH_GID");
1084   process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1085   process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1086   process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1087   process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1088
1089   return GNUNET_OK;
1090 }
1091
1092
1093 /**
1094  * Creates the "main" function for a GNUnet service.  You
1095  * should almost always use the #GNUNET_SERVICE_MAIN macro
1096  * instead of calling this function directly (except
1097  * for ARM, which should call this function directly).
1098  *
1099  * The function will launch the service with the name @a service_name
1100  * using the @a service_options to configure its shutdown
1101  * behavior. Once the service is ready, the @a init_cb will be called
1102  * for service-specific initialization.  @a init_cb will be given the
1103  * service handler which can be used to control the service's
1104  * availability.  When clients connect or disconnect, the respective
1105  * @a connect_cb or @a disconnect_cb functions will be called. For
1106  * messages received from the clients, the respective @a handlers will
1107  * be invoked; for the closure of the handlers we use the return value
1108  * from the @a connect_cb invocation of the respective client.
1109  *
1110  * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1111  * message to receive further messages from this client.  If
1112  * #GNUNET_SERVICE_client_continue() is not called within a short
1113  * time, a warning will be logged. If delays are expected, services
1114  * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1115  * disable the warning.
1116  *
1117  * Clients sending invalid messages (based on @a handlers) will be
1118  * dropped. Additionally, clients can be dropped at any time using
1119  * #GNUNET_SERVICE_client_drop().
1120  *
1121  * @param argc number of command-line arguments in @a argv
1122  * @param argv array of command-line arguments
1123  * @param service_name name of the service to run
1124  * @param options options controlling shutdown of the service
1125  * @param service_init_cb function to call once the service is ready
1126  * @param connect_cb function to call whenever a client connects
1127  * @param disconnect_cb function to call whenever a client disconnects
1128  * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1129  * @param handlers NULL-terminated array of message handlers for the service,
1130  *                 the closure will be set to the value returned by
1131  *                 the @a connect_cb for the respective connection
1132  * @return 0 on success, non-zero on error
1133  */
1134 int
1135 GNUNET_SERVICE_ruN_ (int argc,
1136                      char *const *argv,
1137                      const char *service_name,
1138                      enum GNUNET_SERVICE_Options options,
1139                      GNUNET_SERVICE_InitCallback service_init_cb,
1140                      GNUNET_SERVICE_ConnectHandler connect_cb,
1141                      GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1142                      void *cls,
1143                      const struct GNUNET_MQ_MessageHandler *handlers)
1144 {
1145   struct GNUNET_SERVICE_Handle sh;
1146   char *cfg_filename;
1147   char *opt_cfg_filename;
1148   char *loglev;
1149   const char *xdg;
1150   char *logfile;
1151   int do_daemonize;
1152   unsigned int i;
1153   unsigned long long skew_offset;
1154   unsigned long long skew_variance;
1155   long long clock_offset;
1156   struct GNUNET_SERVICE_Context sh;
1157   struct GNUNET_CONFIGURATION_Handle *cfg;
1158
1159   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1160     GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
1161     {'d', "daemonize", NULL,
1162      gettext_noop ("do daemonize (detach from terminal)"), 0,
1163      GNUNET_GETOPT_set_one, &do_daemonize},
1164     GNUNET_GETOPT_OPTION_HELP (NULL),
1165     GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1166     GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1167     GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
1168     GNUNET_GETOPT_OPTION_END
1169   };
1170
1171   xdg = getenv ("XDG_CONFIG_HOME");
1172   if (NULL != xdg)
1173     GNUNET_asprintf (&cfg_filename,
1174                      "%s%s%s",
1175                      xdg,
1176                      DIR_SEPARATOR_STR,
1177                      GNUNET_OS_project_data_get ()->config_file);
1178   else
1179     cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1180
1181   sh.options = options;
1182   sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
1183   sh.service_init_cb = service_init_cb;
1184   sh.connect_cb = connect_cb;
1185   sh.disconnect_cb = disconnect_cb;
1186   sh.cb_cls = cls;
1187   sh.handlers = handlers;
1188
1189   /* setup subsystems */
1190   ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1191   if (GNUNET_SYSERR == ret)
1192     goto shutdown;
1193   if (GNUNET_NO == ret)
1194   {
1195     err = 0;
1196     goto shutdown;
1197   }
1198   if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1199     HANDLE_ERROR;
1200   if (NULL == opt_cfg_filename)
1201     opt_cfg_filename = GNUNET_strdup (cfg_filename);
1202   if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
1203   {
1204     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename))
1205     {
1206       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1207                   _("Malformed configuration file `%s', exit ...\n"),
1208                   opt_cfg_filename);
1209       goto shutdown;
1210     }
1211   }
1212   else
1213   {
1214     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1215     {
1216       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1217                   _("Malformed configuration, exit ...\n"));
1218       goto shutdown;
1219     }
1220     if (0 != strcmp (opt_cfg_filename, cfg_filename))
1221       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1222                   _("Could not access configuration file `%s'\n"),
1223                   opt_cfg_filename);
1224   }
1225   if (GNUNET_OK != setup_service (&sh))
1226     goto shutdown;
1227   if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh)))
1228   {
1229     GNUNET_break (0);
1230     goto shutdown;
1231   }
1232   if (GNUNET_OK != set_user_id (&sh))
1233     goto shutdown;
1234   LOG (GNUNET_ERROR_TYPE_DEBUG,
1235        "Service `%s' runs with configuration from `%s'\n",
1236        service_name,
1237        opt_cfg_filename);
1238   if ((GNUNET_OK ==
1239        GNUNET_CONFIGURATION_get_value_number (sh.cfg, "TESTING",
1240                                               "SKEW_OFFSET", &skew_offset)) &&
1241       (GNUNET_OK ==
1242        GNUNET_CONFIGURATION_get_value_number (sh.cfg, "TESTING",
1243                                               "SKEW_VARIANCE", &skew_variance)))
1244   {
1245     clock_offset = skew_offset - skew_variance;
1246     GNUNET_TIME_set_offset (clock_offset);
1247     LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
1248   }
1249   /* actually run service */
1250   err = 0;
1251   GNUNET_SCHEDULER_run (&service_main, &sh);
1252   /* shutdown */
1253   if ((1 == do_daemonize) && (NULL != sh.server))
1254     pid_file_delete (&sh);
1255   GNUNET_free_non_null (sh.my_handlers);
1256
1257 shutdown:
1258   if (-1 != sh.ready_confirm_fd)
1259   {
1260     if (1 != WRITE (sh.ready_confirm_fd, err ? "I" : "S", 1))
1261       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1262     GNUNET_break (0 == CLOSE (sh.ready_confirm_fd));
1263   }
1264 #if HAVE_MALLINFO
1265   {
1266     char *counter;
1267
1268     if ( (GNUNET_YES ==
1269           GNUNET_CONFIGURATION_have_value (sh.cfg, service_name,
1270                                            "GAUGER_HEAP")) &&
1271          (GNUNET_OK ==
1272           GNUNET_CONFIGURATION_get_value_string (sh.cfg, service_name,
1273                                                  "GAUGER_HEAP",
1274                                                  &counter)) )
1275     {
1276       struct mallinfo mi;
1277
1278       mi = mallinfo ();
1279       GAUGER (service_name, counter, mi.usmblks, "blocks");
1280       GNUNET_free (counter);
1281     }
1282   }
1283 #endif
1284   GNUNET_SPEEDUP_stop_ ();
1285   GNUNET_CONFIGURATION_destroy (cfg);
1286
1287   while (NULL != sh->slc_head)
1288   {
1289     struct ServiceListenContext *slc = sh->slc_head;
1290     sh->slc_head = slc->next;
1291     // FIXME: destroy slc
1292     GNUNET_free (slc);
1293   }
1294
1295   GNUNET_free_non_null (logfile);
1296   GNUNET_free_non_null (loglev);
1297   GNUNET_free (cfg_filename);
1298   GNUNET_free_non_null (opt_cfg_filename);
1299   GNUNET_free_non_null (sh.v4_denied);
1300   GNUNET_free_non_null (sh.v6_denied);
1301   GNUNET_free_non_null (sh.v4_allowed);
1302   GNUNET_free_non_null (sh.v6_allowed);
1303
1304   return err ? GNUNET_SYSERR : sh.ret;
1305 }
1306
1307
1308 /**
1309  * Suspend accepting connections from the listen socket temporarily.
1310  * Resume activity using #GNUNET_SERVICE_resume.
1311  *
1312  * @param sh service to stop accepting connections.
1313  */
1314 void
1315 GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
1316 {
1317   struct ServiceListenContext *slc;
1318
1319   for (slc = slc_head; NULL != slc; slc = slc->next)
1320   {
1321     if (NULL != slc->listen_task)
1322       {
1323         GNUNET_SCHEDULER_cancel (slc->listen_task);
1324         slc->listen_task = NULL;
1325       }
1326   }
1327 }
1328
1329
1330 /**
1331  * Signature of functions implementing the sending functionality of a
1332  * message queue.
1333  *
1334  * @param mq the message queue
1335  * @param msg the message to send
1336  * @param impl_state state of the implementation
1337  */
1338 static void
1339 service_mq_send (struct GNUNET_MQ_Handle *mq,
1340                  const struct GNUNET_MessageHeader *msg,
1341                  void *impl_state)
1342 {
1343   struct GNUNET_SERVICE_Client *client = cls;
1344
1345   // FIXME 1: setup "client->send_task" for transmission.
1346   // FIXME 2: I seriously hope we do not need to make a copy of `msg`!
1347   // OPTIMIZATION: ideally, we'd like the ability to peak at the rest of
1348   //               the queue and transmit more than one message if possible.
1349 }
1350
1351
1352 /**
1353  * Implementation function that cancels the currently sent message.
1354  *
1355  * @param mq message queue
1356  * @param impl_state state specific to the implementation
1357  */
1358 static void
1359 service_mq_cancel (struct GNUNET_MQ_Handle *mq,
1360                    void *impl_state)
1361 {
1362   struct GNUNET_SERVICE_Client *client = cls;
1363
1364   // FIXME: stop transmission! (must be possible, otherwise
1365   // we must have told MQ that the message was sent!)
1366 }
1367
1368
1369 /**
1370  * Generic error handler, called with the appropriate
1371  * error code and the same closure specified at the creation of
1372  * the message queue.
1373  * Not every message queue implementation supports an error handler.
1374  *
1375  * @param cls closure
1376  * @param error error code
1377  */
1378 static void
1379 service_mq_error_handler (void *cls,
1380                           enum GNUNET_MQ_Error error)
1381 {
1382   struct GNUNET_SERVICE_Client *client = cls;
1383
1384   // FIXME!
1385 }
1386
1387
1388 /**
1389  * Functions with this signature are called whenever a
1390  * complete message is received by the tokenizer for a client.
1391  *
1392  * Do not call #GNUNET_SERVER_mst_destroy() from within
1393  * the scope of this callback.
1394  *
1395  * @param cls closure with the `struct GNUNET_SERVICE_Client *`
1396  * @param client closure with the `struct GNUNET_SERVICE_Client *`
1397  * @param message the actual message
1398  * @return #GNUNET_OK on success (always)
1399  */
1400 static int
1401 service_client_mst_cb (void *cls,
1402                        void *client,
1403                        const struct GNUNET_MessageHeader *message)
1404 {
1405   struct GNUNET_SERVICE_Client *client = cls;
1406
1407   GNUNET_MQ_inject_message (client->mq,
1408                             message);
1409   return GNUNET_OK;
1410 }
1411
1412
1413 /**
1414  * A client sent us data. Receive and process it.  If we are done,
1415  * reschedule this task.
1416  *
1417  * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
1418  */
1419 static void
1420 service_client_recv (void *cls)
1421 {
1422   struct GNUNET_SERVICE_Client *client = cls;
1423
1424   // FIXME: read into buffer, pass to MST, then client->mq inject!
1425   // FIXME: revise MST API to avoid the memcpy!
1426   // i.e.: GNUNET_MST_read (client->sock);
1427 }
1428
1429
1430 /**
1431  * We have successfully accepted a connection from a client.  Now
1432  * setup the client (with the scheduler) and tell the application.
1433  *
1434  * @param sh service that accepted the client
1435  * @param sock socket associated with the client
1436  */
1437 static void
1438 start_client (struct GNUNET_SERVICE_Handle *sh,
1439               struct GNUNET_NETWORK_Handle *csock)
1440 {
1441   struct GNUNET_SERVICE_Client *client;
1442
1443   client = GNUNET_new (struct GNUNET_SERVICE_Client);
1444   GNUNET_CONTAINER_DLL_insert (sh->clients_head,
1445                                sh->clients_tail,
1446                                client);
1447   client->sh = sh;
1448   client->sock = csock;
1449   client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
1450                                               NULL,
1451                                               &service_mq_cancel,
1452                                               client,
1453                                               sh->handlers,
1454                                               &service_mq_error_handler,
1455                                               client);
1456   client->mst = GNUNET_SERVER_mst_create (&service_client_mst_cb,
1457                                           client);
1458   client->user_context = sh->connect_cb (sh->cb_cls,
1459                                          client,
1460                                          client->mq);
1461   GNUNET_MQ_set_handlers_closure (client->mq,
1462                                   client->user_context);
1463   client->recv_task = GNUNET_SCHEDULER_add_read (client->sock,
1464                                                  &service_client_recv,
1465                                                  client);
1466 }
1467
1468
1469 /**
1470  * We have a client. Accept the incoming socket(s) (and reschedule
1471  * the listen task).
1472  *
1473  * @param cls the `struct ServiceListenContext` of the ready listen socket
1474  */
1475 static void
1476 accept_client (void *cls)
1477 {
1478   struct ServiceListenContext *slc = cls;
1479
1480   slc->listen_task = NULL;
1481   while (1)
1482     {
1483       struct GNUNET_NETWORK_Handle *sock;
1484       struct sockaddr_in *v4;
1485       struct sockaddr_in6 *v6;
1486       struct sockaddr_storage sa;
1487       socklen_t addrlen;
1488       int ok;
1489
1490       addrlen = sizeof (sa);
1491       sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
1492                                            (struct sockaddr *) &sa,
1493                                            &addrlen);
1494       if (NULL == sock)
1495         break;
1496       switch (sa.sa_family)
1497       {
1498       case AF_INET:
1499         GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
1500         v4 = (const struct sockaddr_in *) addr;
1501         ok = ( ( (NULL == sh->v4_allowed) ||
1502                  (check_ipv4_listed (sh->v4_allowed,
1503                                      &i4->sin_addr))) &&
1504                ( (NULL == sh->v4_denied) ||
1505                  (! check_ipv4_listed (sh->v4_denied,
1506                                        &i4->sin_addr)) ) );
1507         break;
1508       case AF_INET6:
1509         GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
1510         v6 = (const struct sockaddr_in6 *) addr;
1511         ok = ( ( (NULL == sh->v6_allowed) ||
1512                  (check_ipv6_listed (sh->v6_allowed,
1513                                      &i6->sin6_addr))) &&
1514                ( (NULL == sh->v6_denied) ||
1515                  (! check_ipv6_listed (sh->v6_denied,
1516                                        &i6->sin6_addr)) ) );
1517         break;
1518 #ifndef WINDOWS
1519       case AF_UNIX:
1520         ok = GNUNET_OK;            /* controlled using file-system ACL now */
1521         break;
1522 #endif
1523       default:
1524         LOG (GNUNET_ERROR_TYPE_WARNING,
1525              _("Unknown address family %d\n"),
1526              addr->sa_family);
1527         return GNUNET_SYSERR;
1528       }
1529       if (! ok)
1530         {
1531           LOG (GNUNET_ERROR_TYPE_DEBUG,
1532                "Service rejected incoming connection from %s due to policy.\n",
1533                GNUNET_a2s ((const struct sockaddr *) &sa,
1534                            addrlen));
1535           GNUNET_NETWORK_socket_close (sock);
1536           continue;
1537         }
1538       LOG (GNUNET_ERROR_TYPE_DEBUG,
1539            "Service accepted incoming connection from %s.\n",
1540            GNUNET_a2s ((const struct sockaddr *) &sa,
1541                        addrlen));
1542       start_client (slc->sh,
1543                     sock);
1544     }
1545   slc->listen_task = GNUNET_SCHEDULER_add_read (slc->listen_socket,
1546                                                 &accept_client,
1547                                                 slc);
1548 }
1549
1550
1551 /**
1552  * Resume accepting connections from the listen socket.
1553  *
1554  * @param sh service to resume accepting connections.
1555  */
1556 void
1557 GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
1558 {
1559   struct ServiceListenContext *slc;
1560
1561   for (slc = slc_head; NULL != slc; slc = slc->next)
1562   {
1563     GNUNET_assert (NULL == slc->listen_task);
1564     slc->listen_task = GNUNET_SCHEDULER_add_read (slc->listen_socket,
1565                                                   &accept_client,
1566                                                   slc);
1567   }
1568 }
1569
1570
1571 /**
1572  * Continue receiving further messages from the given client.
1573  * Must be called after each message received.
1574  *
1575  * @param c the client to continue receiving from
1576  */
1577 void
1578 GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
1579 {
1580   GNUNET_break (0); // not implemented
1581 }
1582
1583
1584 /**
1585  * Disable the warning the server issues if a message is not
1586  * acknowledged in a timely fashion.  Use this call if a client is
1587  * intentionally delayed for a while.  Only applies to the current
1588  * message.
1589  *
1590  * @param c client for which to disable the warning
1591  */
1592 void
1593 GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
1594 {
1595   GNUNET_break (NULL != c->warn_task);
1596   if (NULL != c->warn_task)
1597   {
1598     GNUNET_SCHEDULER_cancel (c->warn_task);
1599     c->warn_task = NULL;
1600   }
1601 }
1602
1603
1604 /**
1605  * Ask the server to disconnect from the given client.  This is the
1606  * same as returning #GNUNET_SYSERR within the check procedure when
1607  * handling a message, wexcept that it allows dropping of a client even
1608  * when not handling a message from that client.  The `disconnect_cb`
1609  * will be called on @a c even if the application closes the connection
1610  * using this function.
1611  *
1612  * @param c client to disconnect now
1613  */
1614 void
1615 GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
1616 {
1617   struct GNUNET_SERVICE_Handle *sh = c->sh;
1618
1619   GNUNET_CONTAINER_DLL_remove (sh->clients_head,
1620                                sh->clients_tail,
1621                                c);
1622   sh->disconnect_cb (sh->cb_cls,
1623                      c,
1624                      c->user_context);
1625   if (NULL != c->warn_task)
1626   {
1627     GNUNET_SCHEDULER_cancel (c->warn_task);
1628     c->warn_task = NULL;
1629   }
1630   if (NULL != c->recv_task)
1631   {
1632     GNUNET_SCHEDULER_cancel (c->recv_task);
1633     c->recv_task = NULL;
1634   }
1635   if (NULL != c->send_task)
1636   {
1637     GNUNET_SCHEDULER_cancel (c->send_task);
1638     c->send_task = NULL;
1639   }
1640   GNUNET_SERVER_mst_destroy (c->mst);
1641   GNUNET_MQ_destroy (c->mq);
1642   if (GNUNET_NO == c->persist)
1643   {
1644     GNUNET_NETWORK_socket_close (c->sock);
1645   }
1646   else
1647   {
1648     GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
1649   }
1650   GNUNET_free (c);
1651   if ( (GNUNET_YES == sh->got_shutdown) &&
1652        (GNUNET_NO == have_non_monitor_clients (sh)) )
1653     GNUNET_SERVICE_shutdown (sh);
1654 }
1655
1656
1657 /**
1658  * Explicitly stops the service.
1659  *
1660  * @param sh server to shutdown
1661  */
1662 void
1663 GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
1664 {
1665   struct GNUNET_SERVICE_Client *client;
1666
1667   GNUNET_SERVICE_suspend (sh);
1668   sh->got_shutdown = GNUNET_NO;
1669   while (NULL != (client = sh->clients_head))
1670     GNUNET_SERVICE_client_drop (client);
1671 }
1672
1673
1674 /**
1675  * Set the 'monitor' flag on this client.  Clients which have been
1676  * marked as 'monitors' won't prevent the server from shutting down
1677  * once #GNUNET_SERVICE_stop_listening() has been invoked.  The idea is
1678  * that for "normal" clients we likely want to allow them to process
1679  * their requests; however, monitor-clients are likely to 'never'
1680  * disconnect during shutdown and thus will not be considered when
1681  * determining if the server should continue to exist after
1682  * shutdown has been triggered.
1683  *
1684  * @param c client to mark as a monitor
1685  */
1686 void
1687 GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
1688 {
1689   c->is_monitor = GNUNET_YES;
1690   if ( (GNUNET_YES == sh->got_shutdown) &&
1691        (GNUNET_NO == have_non_monitor_clients (sh)) )
1692     GNUNET_SERVICE_shutdown (sh);
1693 }
1694
1695
1696 /**
1697  * Set the persist option on this client.  Indicates that the
1698  * underlying socket or fd should never really be closed.  Used for
1699  * indicating process death.
1700  *
1701  * @param c client to persist the socket (never to be closed)
1702  */
1703 void
1704 GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
1705 {
1706   c->persist = GNUNET_YES;
1707 }
1708
1709
1710 /* end of service_new.c */