ede31b558a68d424dd9eb7f4f59b6190d28079b2
[oweals/gnunet.git] / src / util / server.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 2, 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/server.c
23  * @brief library for building GNUnet network servers
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_connection_lib.h"
30 #include "gnunet_scheduler_lib.h"
31 #include "gnunet_server_lib.h"
32 #include "gnunet_time_lib.h"
33 #include "gnunet_disk_lib.h"
34 #include "gnunet_protocols.h"
35
36 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
37
38 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
39
40 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
41
42
43 /**
44  * List of arrays of message handlers.
45  */
46 struct HandlerList
47 {
48   /**
49    * This is a linked list.
50    */
51   struct HandlerList *next;
52
53   /**
54    * NULL-terminated array of handlers.
55    */
56   const struct GNUNET_SERVER_MessageHandler *handlers;
57 };
58
59
60 /**
61  * List of arrays of message handlers.
62  */
63 struct NotifyList
64 {
65   /**
66    * This is a linked list.
67    */
68   struct NotifyList *next;
69
70   /**
71    * Function to call.
72    */
73   GNUNET_SERVER_DisconnectCallback callback;
74
75   /**
76    * Closure for callback.
77    */
78   void *callback_cls;
79 };
80
81
82 /**
83  * @brief handle for a server
84  */
85 struct GNUNET_SERVER_Handle
86 {
87   /**
88    * List of handlers for incoming messages.
89    */
90   struct HandlerList *handlers;
91
92   /**
93    * List of our current clients.
94    */
95   struct GNUNET_SERVER_Client *clients;
96
97   /**
98    * Linked list of functions to call on disconnects by clients.
99    */
100   struct NotifyList *disconnect_notify_list;
101
102   /**
103    * Function to call for access control.
104    */
105   GNUNET_CONNECTION_AccessCheck access;
106
107   /**
108    * Closure for access.
109    */
110   void *access_cls;
111
112   /**
113    * NULL-terminated array of sockets used to listen for new
114    * connections.
115    */
116   struct GNUNET_NETWORK_Handle **listen_sockets;
117
118   /**
119    * After how long should an idle connection time
120    * out (on write).
121    */
122   struct GNUNET_TIME_Relative idle_timeout;
123
124   /**
125    * Task scheduled to do the listening.
126    */
127   GNUNET_SCHEDULER_TaskIdentifier listen_task;
128
129   /**
130    * Do we ignore messages of types that we do not understand or do we
131    * require that a handler is found (and if not kill the connection)?
132    */
133   int require_found;
134
135   /**
136    * Should all of the clients of this server continue to process
137    * connections as usual even if we get a shutdown request? (the
138    * listen socket always ignores shutdown).
139    */
140   int clients_ignore_shutdown;
141
142   /**
143    * Alternative function to create a MST instance.
144    */
145   GNUNET_SERVER_MstCreateCallback mst_create;
146
147   /**
148    * Alternative function to destroy a MST instance.
149    */
150   GNUNET_SERVER_MstDestroyCallback mst_destroy;
151
152   /**
153    * Alternative function to give data to a MST instance.
154    */
155   GNUNET_SERVER_MstReceiveCallback mst_receive;
156
157   /**
158    * Closure for 'mst_'-callbacks.
159    */
160   void *mst_cls;
161 };
162
163
164 /**
165  * Handle server returns for aborting transmission to a client.
166  */
167 struct GNUNET_SERVER_TransmitHandle
168 {
169   /**
170    * Function to call to get the message.
171    */
172   GNUNET_CONNECTION_TransmitReadyNotify callback;
173
174   /**
175    * Closure for 'callback'
176    */
177   void *callback_cls;
178
179   /**
180    * Active connection transmission handle.
181    */
182   struct GNUNET_CONNECTION_TransmitHandle *cth;
183
184 };
185
186
187 /**
188  * @brief handle for a client of the server
189  */
190 struct GNUNET_SERVER_Client
191 {
192
193   /**
194    * This is a linked list.
195    */
196   struct GNUNET_SERVER_Client *next;
197
198   /**
199    * Processing of incoming data.
200    */
201   void *mst;
202
203   /**
204    * Server that this client belongs to.
205    */
206   struct GNUNET_SERVER_Handle *server;
207
208   /**
209    * Client closure for callbacks.
210    */
211   struct GNUNET_CONNECTION_Handle *connection;
212
213   /**
214    * ID of task used to restart processing.
215    */
216   GNUNET_SCHEDULER_TaskIdentifier restart_task;
217
218   /**
219    * Task that warns about missing calls to 'GNUNET_SERVER_receive_done'.
220    */
221   GNUNET_SCHEDULER_TaskIdentifier warn_task;
222
223   /**
224    * Time when the warn task was started.
225    */
226   struct GNUNET_TIME_Absolute warn_start;
227
228   /**
229    * Last activity on this socket (used to time it out
230    * if reference_count == 0).
231    */
232   struct GNUNET_TIME_Absolute last_activity;
233
234   /**
235    * Transmission handle we return for this client from
236    * GNUNET_SERVER_notify_transmit_ready.
237    */
238   struct GNUNET_SERVER_TransmitHandle th;
239
240   /**
241    * After how long should an idle connection time
242    * out (on write).
243    */
244   struct GNUNET_TIME_Relative idle_timeout;
245
246   /**
247    * Number of external entities with a reference to
248    * this client object.
249    */
250   unsigned int reference_count;
251
252   /**
253    * Was processing if incoming messages suspended while
254    * we were still processing data already received?
255    * This is a counter saying how often processing was
256    * suspended (once per handler invoked).
257    */
258   unsigned int suspended;
259
260   /**
261    * Are we currently in the "process_client_buffer" function (and
262    * will hence restart the receive job on exit if suspended == 0 once
263    * we are done?).  If this is set, then "receive_done" will
264    * essentially only decrement suspended; if this is not set, then
265    * "receive_done" may need to restart the receive process (either
266    * from the side-buffer or via select/recv).
267    */
268   int in_process_client_buffer;
269
270   /**
271    * We're about to close down this client due to some serious
272    * error.
273    */
274   int shutdown_now;
275
276   /**
277    * Are we currently trying to receive? (YES if we are, NO if we are not,
278    * SYSERR if data is already available in MST).
279    */
280   int receive_pending;
281
282   /**
283    * Finish pending write when disconnecting?
284    */
285   int finish_pending_write;
286
287   /**
288    * Persist the file handle for this client no matter what happens,
289    * force the OS to close once the process actually dies.  Should only
290    * be used in special cases!
291    */
292   int persist;
293
294   /**
295    * Type of last message processed (for warn_no_receive_done).
296    */
297   uint16_t warn_type;
298 };
299
300
301 /**
302  * Scheduler says our listen socket is ready.  Process it!
303  *
304  * @param cls handle to our server for which we are processing the listen
305  *        socket
306  * @param tc reason why we are running right now
307  */
308 static void
309 process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
310 {
311   struct GNUNET_SERVER_Handle *server = cls;
312   struct GNUNET_CONNECTION_Handle *sock;
313   struct GNUNET_SERVER_Client *client;
314   struct GNUNET_NETWORK_FDSet *r;
315   unsigned int i;
316
317   server->listen_task = GNUNET_SCHEDULER_NO_TASK;
318   r = GNUNET_NETWORK_fdset_create ();
319   i = 0;
320   while (NULL != server->listen_sockets[i])
321     GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
322   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
323   {
324     /* ignore shutdown, someone else will take care of it! */
325     server->listen_task =
326         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
327                                      GNUNET_SCHEDULER_NO_TASK,
328                                      GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
329                                      &process_listen_socket, server);
330     GNUNET_NETWORK_fdset_destroy (r);
331     return;
332   }
333   i = 0;
334   while (NULL != server->listen_sockets[i])
335   {
336     if (GNUNET_NETWORK_fdset_isset (tc->read_ready, server->listen_sockets[i]))
337     {
338       sock =
339           GNUNET_CONNECTION_create_from_accept (server->access,
340                                                 server->access_cls,
341                                                 server->listen_sockets[i]);
342       if (sock != NULL)
343       {
344         LOG (GNUNET_ERROR_TYPE_DEBUG, "Server accepted incoming connection.\n");
345         client = GNUNET_SERVER_connect_socket (server, sock);
346         GNUNET_CONNECTION_ignore_shutdown (sock,
347                                            server->clients_ignore_shutdown);
348         /* decrement reference count, we don't keep "client" alive */
349         GNUNET_SERVER_client_drop (client);
350       }
351     }
352     i++;
353   }
354   /* listen for more! */
355   server->listen_task =
356       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
357                                    GNUNET_SCHEDULER_NO_TASK,
358                                    GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
359                                    &process_listen_socket, server);
360   GNUNET_NETWORK_fdset_destroy (r);
361 }
362
363
364 /**
365  * Create and initialize a listen socket for the server.
366  *
367  * @param serverAddr address to listen on
368  * @param socklen length of address
369  * @return NULL on error, otherwise the listen socket
370  */
371 static struct GNUNET_NETWORK_Handle *
372 open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
373 {
374   const static int on = 1;
375   struct GNUNET_NETWORK_Handle *sock;
376   uint16_t port;
377   int eno;
378
379   switch (serverAddr->sa_family)
380   {
381   case AF_INET:
382     port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port);
383     break;
384   case AF_INET6:
385     port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port);
386     break;
387   case AF_UNIX:
388     port = 0;
389     break;
390   default:
391     GNUNET_break (0);
392     port = 0;
393     break;
394   }
395   sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0);
396   if (NULL == sock)
397   {
398     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
399     errno = 0;
400     return NULL;
401   }
402   if (port != 0)
403   {
404     if (GNUNET_NETWORK_socket_setsockopt
405         (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
406       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
407                     "setsockopt");
408 #ifdef IPV6_V6ONLY
409     if ((serverAddr->sa_family == AF_INET6) &&
410         (GNUNET_NETWORK_socket_setsockopt
411          (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
412       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
413                     "setsockopt");
414 #endif
415   }
416   /* bind the socket */
417   if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK)
418   {
419     eno = errno;
420     if (errno != EADDRINUSE)
421     {
422       /* we don't log 'EADDRINUSE' here since an IPv4 bind may
423        * fail if we already took the port on IPv6; if both IPv4 and
424        * IPv6 binds fail, then our caller will log using the
425        * errno preserved in 'eno' */
426       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
427       if (port != 0)
428         LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed for port %d (%s).\n"),
429              "bind", port,
430              (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6");
431       eno = 0;
432     }
433     else
434     {
435       if (port != 0)
436         LOG (GNUNET_ERROR_TYPE_WARNING,
437              _("`%s' failed for port %d (%s): address already in use\n"),
438              "bind", port,
439              (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6");
440       else if (serverAddr->sa_family == AF_UNIX)
441         LOG (GNUNET_ERROR_TYPE_WARNING,
442              _("`%s' failed for `%s': address already in use\n"), "bind",
443              ((const struct sockaddr_un *) serverAddr)->sun_path);
444
445     }
446     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
447     errno = eno;
448     return NULL;
449   }
450   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
451   {
452     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen");
453     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
454     errno = 0;
455     return NULL;
456   }
457   if (port != 0)
458     LOG (GNUNET_ERROR_TYPE_DEBUG, "Server starts to listen on port %u.\n",
459          port);
460   return sock;
461 }
462
463
464 /**
465  * Create a new server.
466  *
467  * @param access function for access control
468  * @param access_cls closure for access
469  * @param lsocks NULL-terminated array of listen sockets
470  * @param idle_timeout after how long should we timeout idle connections?
471  * @param require_found if YES, connections sending messages of unknown type
472  *        will be closed
473  * @return handle for the new server, NULL on error
474  *         (typically, "port" already in use)
475  */
476 struct GNUNET_SERVER_Handle *
477 GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access,
478                                    void *access_cls,
479                                    struct GNUNET_NETWORK_Handle **lsocks,
480                                    struct GNUNET_TIME_Relative idle_timeout,
481                                    int require_found)
482 {
483   struct GNUNET_SERVER_Handle *ret;
484   struct GNUNET_NETWORK_FDSet *r;
485   int i;
486
487   ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle));
488   ret->idle_timeout = idle_timeout;
489   ret->listen_sockets = lsocks;
490   ret->access = access;
491   ret->access_cls = access_cls;
492   ret->require_found = require_found;
493   if (lsocks != NULL)
494   {
495     r = GNUNET_NETWORK_fdset_create ();
496     i = 0;
497     while (NULL != ret->listen_sockets[i])
498       GNUNET_NETWORK_fdset_set (r, ret->listen_sockets[i++]);
499     ret->listen_task =
500         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
501                                      GNUNET_SCHEDULER_NO_TASK,
502                                      GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
503                                      &process_listen_socket, ret);
504     GNUNET_NETWORK_fdset_destroy (r);
505   }
506   return ret;
507 }
508
509
510 /**
511  * Create a new server.
512  *
513  * @param access function for access control
514  * @param access_cls closure for access
515  * @param serverAddr address to listen on (including port), NULL terminated array
516  * @param socklen length of serverAddr
517  * @param idle_timeout after how long should we timeout idle connections?
518  * @param require_found if YES, connections sending messages of unknown type
519  *        will be closed
520  * @return handle for the new server, NULL on error
521  *         (typically, "port" already in use)
522  */
523 struct GNUNET_SERVER_Handle *
524 GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls,
525                       struct sockaddr *const *serverAddr,
526                       const socklen_t * socklen,
527                       struct GNUNET_TIME_Relative idle_timeout,
528                       int require_found)
529 {
530   struct GNUNET_NETWORK_Handle **lsocks;
531   unsigned int i;
532   unsigned int j;
533
534   i = 0;
535   while (serverAddr[i] != NULL)
536     i++;
537   if (i > 0)
538   {
539     lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
540     i = 0;
541     j = 0;
542     while (serverAddr[i] != NULL)
543     {
544       lsocks[j] = open_listen_socket (serverAddr[i], socklen[i]);
545       if (lsocks[j] != NULL)
546         j++;
547       i++;
548     }
549     if (j == 0)
550     {
551       if (errno != 0)
552         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
553       GNUNET_free (lsocks);
554       lsocks = NULL;
555     }
556   }
557   else
558   {
559     lsocks = NULL;
560   }
561   return GNUNET_SERVER_create_with_sockets (access, access_cls, lsocks,
562                                             idle_timeout, require_found);
563 }
564
565
566 /**
567  * Free resources held by this server.
568  *
569  * @param s server to destroy
570  */
571 void
572 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s)
573 {
574   struct HandlerList *hpos;
575   struct NotifyList *npos;
576   unsigned int i;
577
578   LOG (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n");
579   if (GNUNET_SCHEDULER_NO_TASK != s->listen_task)
580   {
581     GNUNET_SCHEDULER_cancel (s->listen_task);
582     s->listen_task = GNUNET_SCHEDULER_NO_TASK;
583   }
584   if (s->listen_sockets != NULL)
585   {
586     i = 0;
587     while (s->listen_sockets[i] != NULL)
588       GNUNET_break (GNUNET_OK ==
589                     GNUNET_NETWORK_socket_close (s->listen_sockets[i++]));
590     GNUNET_free (s->listen_sockets);
591     s->listen_sockets = NULL;
592   }
593   while (s->clients != NULL)
594     GNUNET_SERVER_client_disconnect (s->clients);
595   while (NULL != (hpos = s->handlers))
596   {
597     s->handlers = hpos->next;
598     GNUNET_free (hpos);
599   }
600   while (NULL != (npos = s->disconnect_notify_list))
601   {
602     npos->callback (npos->callback_cls, NULL);
603     s->disconnect_notify_list = npos->next;
604     GNUNET_free (npos);
605   }
606   GNUNET_free (s);
607 }
608
609
610 /**
611  * Add additional handlers to an existing server.
612  *
613  * @param server the server to add handlers to
614  * @param handlers array of message handlers for
615  *        incoming messages; the last entry must
616  *        have "NULL" for the "callback"; multiple
617  *        entries for the same type are allowed,
618  *        they will be called in order of occurence.
619  *        These handlers can be removed later;
620  *        the handlers array must exist until removed
621  *        (or server is destroyed).
622  */
623 void
624 GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
625                             const struct GNUNET_SERVER_MessageHandler *handlers)
626 {
627   struct HandlerList *p;
628
629   p = GNUNET_malloc (sizeof (struct HandlerList));
630   p->handlers = handlers;
631   p->next = server->handlers;
632   server->handlers = p;
633 }
634
635
636 void
637 GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
638                              GNUNET_SERVER_MstCreateCallback create,
639                              GNUNET_SERVER_MstDestroyCallback destroy,
640                              GNUNET_SERVER_MstReceiveCallback receive,
641                              void *cls)
642 {
643   server->mst_create = create;
644   server->mst_destroy = destroy;
645   server->mst_receive = receive;
646   server->mst_cls = cls;
647 }
648
649
650 /**
651  * Task run to warn about missing calls to 'GNUNET_SERVER_receive_done'.
652  *
653  * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from
654  * @param tc scheduler context (unused)
655  */
656 static void
657 warn_no_receive_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
658 {
659   struct GNUNET_SERVER_Client *client = cls;
660
661   client->warn_task =
662       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
663                                     &warn_no_receive_done, client);
664   if (0 == (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
665     LOG (GNUNET_ERROR_TYPE_WARNING,
666          _
667          ("Processing code for message of type %u did not call GNUNET_SERVER_receive_done after %llums\n"),
668          (unsigned int) client->warn_type,
669          (unsigned long long)
670          GNUNET_TIME_absolute_get_duration (client->warn_start).rel_value);
671 }
672
673
674 /**
675  * Disable the warning the server issues if a message is not acknowledged
676  * in a timely fashion.  Use this call if a client is intentionally delayed
677  * for a while.  Only applies to the current message.
678  *
679  * @param client client for which to disable the warning
680  */
681 void
682 GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
683 {
684   if (GNUNET_SCHEDULER_NO_TASK != client->warn_task)
685   {
686     GNUNET_SCHEDULER_cancel (client->warn_task);
687     client->warn_task = GNUNET_SCHEDULER_NO_TASK;
688   }
689 }
690
691
692 /**
693  * Inject a message into the server, pretend it came
694  * from the specified client.  Delivery of the message
695  * will happen instantly (if a handler is installed;
696  * otherwise the call does nothing).
697  *
698  * @param server the server receiving the message
699  * @param sender the "pretended" sender of the message
700  *        can be NULL!
701  * @param message message to transmit
702  * @return GNUNET_OK if the message was OK and the
703  *                   connection can stay open
704  *         GNUNET_SYSERR if the connection to the
705  *         client should be shut down
706  */
707 int
708 GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
709                       struct GNUNET_SERVER_Client *sender,
710                       const struct GNUNET_MessageHeader *message)
711 {
712   struct HandlerList *pos;
713   const struct GNUNET_SERVER_MessageHandler *mh;
714   unsigned int i;
715   uint16_t type;
716   uint16_t size;
717   int found;
718
719   type = ntohs (message->type);
720   size = ntohs (message->size);
721   LOG (GNUNET_ERROR_TYPE_DEBUG,
722        "Server schedules transmission of %u-byte message of type %u to client.\n",
723        size, type);
724   pos = server->handlers;
725   found = GNUNET_NO;
726   while (pos != NULL)
727   {
728     i = 0;
729     while (pos->handlers[i].callback != NULL)
730     {
731       mh = &pos->handlers[i];
732       if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
733       {
734         if ((mh->expected_size != 0) && (mh->expected_size != size))
735         {
736 #if GNUNET8_NETWORK_IS_DEAD
737           LOG (GNUNET_ERROR_TYPE_WARNING,
738                "Expected %u bytes for message of type %u, got %u\n",
739                mh->expected_size, mh->type, size);
740           GNUNET_break_op (0);
741 #endif
742           return GNUNET_SYSERR;
743         }
744         if (sender != NULL)
745         {
746           if (0 == sender->suspended)
747           {
748             sender->warn_start = GNUNET_TIME_absolute_get ();
749             sender->warn_task =
750                 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
751                                               &warn_no_receive_done, sender);
752             sender->warn_type = type;
753           }
754           sender->suspended++;
755         }
756         mh->callback (mh->callback_cls, sender, message);
757         found = GNUNET_YES;
758       }
759       i++;
760     }
761     pos = pos->next;
762   }
763   if (found == GNUNET_NO)
764   {
765     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
766          "Received message of unknown type %d\n", type);
767     if (server->require_found == GNUNET_YES)
768       return GNUNET_SYSERR;
769   }
770   return GNUNET_OK;
771 }
772
773
774 /**
775  * We are receiving an incoming message.  Process it.
776  *
777  * @param cls our closure (handle for the client)
778  * @param buf buffer with data received from network
779  * @param available number of bytes available in buf
780  * @param addr address of the sender
781  * @param addrlen length of addr
782  * @param errCode code indicating errors receiving, 0 for success
783  */
784 static void
785 process_incoming (void *cls, const void *buf, size_t available,
786                   const struct sockaddr *addr, socklen_t addrlen, int errCode);
787
788
789 /**
790  * Process messages from the client's message tokenizer until either
791  * the tokenizer is empty (and then schedule receiving more), or
792  * until some handler is not immediately done (then wait for restart_processing)
793  * or shutdown.
794  *
795  * @param client the client to process, RC must have already been increased
796  *        using GNUNET_SERVER_client_keep and will be decreased by one in this
797  *        function
798  * @param ret GNUNET_NO to start processing from the buffer,
799  *            GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
800  *            GNUNET_SYSERR if we should instantly abort due to error in a previous step
801  */
802 static void
803 process_mst (struct GNUNET_SERVER_Client *client, int ret)
804 {
805   while ((ret != GNUNET_SYSERR) && (client->server != NULL) &&
806          (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
807   {
808     if (ret == GNUNET_OK)
809     {
810       LOG (GNUNET_ERROR_TYPE_DEBUG,
811            "Server re-enters receive loop, timeout: %llu.\n",
812            client->idle_timeout.rel_value);
813       client->receive_pending = GNUNET_YES;
814       GNUNET_CONNECTION_receive (client->connection,
815                                  GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
816                                  client->idle_timeout, &process_incoming,
817                                  client);
818       break;
819     }
820     LOG (GNUNET_ERROR_TYPE_DEBUG,
821          "Server processes additional messages instantly.\n");
822     if (client->server->mst_receive != NULL)
823       ret =
824           client->server->mst_receive (client->server->mst_cls, client->mst,
825                                        client, NULL, 0, GNUNET_NO, GNUNET_YES);
826     else
827       ret =
828           GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
829                                      GNUNET_YES);
830   }
831   LOG (GNUNET_ERROR_TYPE_DEBUG,
832        "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
833        ret, client->server, client->shutdown_now, client->suspended);
834   if (ret == GNUNET_NO)
835   {
836     LOG (GNUNET_ERROR_TYPE_DEBUG,
837          "Server has more data pending but is suspended.\n");
838     client->receive_pending = GNUNET_SYSERR;    /* data pending */
839   }
840   if ((ret == GNUNET_SYSERR) || (GNUNET_YES == client->shutdown_now))
841     GNUNET_SERVER_client_disconnect (client);
842   GNUNET_SERVER_client_drop (client);
843 }
844
845
846 /**
847  * We are receiving an incoming message.  Process it.
848  *
849  * @param cls our closure (handle for the client)
850  * @param buf buffer with data received from network
851  * @param available number of bytes available in buf
852  * @param addr address of the sender
853  * @param addrlen length of addr
854  * @param errCode code indicating errors receiving, 0 for success
855  */
856 static void
857 process_incoming (void *cls, const void *buf, size_t available,
858                   const struct sockaddr *addr, socklen_t addrlen, int errCode)
859 {
860   struct GNUNET_SERVER_Client *client = cls;
861   struct GNUNET_SERVER_Handle *server = client->server;
862   struct GNUNET_TIME_Absolute end;
863   struct GNUNET_TIME_Absolute now;
864   int ret;
865
866   GNUNET_assert (client->receive_pending == GNUNET_YES);
867   client->receive_pending = GNUNET_NO;
868   now = GNUNET_TIME_absolute_get ();
869   end = GNUNET_TIME_absolute_add (client->last_activity, client->idle_timeout);
870
871   if ((buf == NULL) && (available == 0) && (addr == NULL) && (errCode == 0) &&
872       (client->shutdown_now != GNUNET_YES) && (server != NULL) &&
873       (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
874       (end.abs_value > now.abs_value))
875   {
876     /* wait longer, timeout changed (i.e. due to us sending) */
877     LOG (GNUNET_ERROR_TYPE_DEBUG,
878          "Receive time out, but no disconnect due to sending (%p)\n",
879          GNUNET_a2s (addr, addrlen));
880     client->receive_pending = GNUNET_YES;
881     GNUNET_CONNECTION_receive (client->connection,
882                                GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
883                                GNUNET_TIME_absolute_get_remaining (end),
884                                &process_incoming, client);
885     return;
886   }
887   if ((buf == NULL) || (available == 0) || (errCode != 0) || (server == NULL) ||
888       (client->shutdown_now == GNUNET_YES) ||
889       (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)))
890   {
891     /* other side closed connection, error connecting, etc. */
892     GNUNET_SERVER_client_disconnect (client);
893     return;
894   }
895   LOG (GNUNET_ERROR_TYPE_DEBUG, "Server receives %u bytes from `%s'.\n",
896        (unsigned int) available, GNUNET_a2s (addr, addrlen));
897   GNUNET_SERVER_client_keep (client);
898   client->last_activity = now;
899
900   if (server->mst_receive != NULL)
901     ret =
902         client->server->mst_receive (client->server->mst_cls, client->mst,
903                                      client, buf, available, GNUNET_NO, GNUNET_YES);
904   else
905     ret =
906         GNUNET_SERVER_mst_receive (client->mst, client, buf, available, GNUNET_NO,
907                                    GNUNET_YES);
908
909   process_mst (client, ret);
910 }
911
912
913 /**
914  * Task run to start again receiving from the network
915  * and process requests.
916  *
917  * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from
918  * @param tc scheduler context (unused)
919  */
920 static void
921 restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
922 {
923   struct GNUNET_SERVER_Client *client = cls;
924   struct GNUNET_SERVER_Handle *server = client->server;
925
926   client->restart_task = GNUNET_SCHEDULER_NO_TASK;
927   if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
928       (GNUNET_NO == server->clients_ignore_shutdown))
929   {
930     GNUNET_SERVER_client_disconnect (client);
931     return;
932   }
933   if (client->receive_pending == GNUNET_NO)
934   {
935     LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
936     client->receive_pending = GNUNET_YES;
937     GNUNET_CONNECTION_receive (client->connection,
938                                GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
939                                client->idle_timeout, &process_incoming, client);
940     return;
941   }
942   LOG (GNUNET_ERROR_TYPE_DEBUG,
943        "Server continues processing messages still in the buffer.\n");
944   GNUNET_SERVER_client_keep (client);
945   client->receive_pending = GNUNET_NO;
946   process_mst (client, GNUNET_NO);
947 }
948
949
950 /**
951  * This function is called whenever our inbound message tokenizer has
952  * received a complete message.
953  *
954  * @param cls closure (struct GNUNET_SERVER_Handle)
955  * @param client identification of the client (struct GNUNET_SERVER_Client*)
956  * @param message the actual message
957  */
958 static void
959 client_message_tokenizer_callback (void *cls, void *client,
960                                    const struct GNUNET_MessageHeader *message)
961 {
962   struct GNUNET_SERVER_Handle *server = cls;
963   struct GNUNET_SERVER_Client *sender = client;
964   int ret;
965
966   LOG (GNUNET_ERROR_TYPE_DEBUG,
967        "Tokenizer gives server message of type %u from client\n",
968        ntohs (message->type));
969   sender->in_process_client_buffer = GNUNET_YES;
970   ret = GNUNET_SERVER_inject (server, sender, message);
971   sender->in_process_client_buffer = GNUNET_NO;
972   if (GNUNET_OK != ret)
973     GNUNET_SERVER_client_disconnect (sender);
974 }
975
976
977 /**
978  * Add a TCP socket-based connection to the set of handles managed by
979  * this server.  Use this function for outgoing (P2P) connections that
980  * we initiated (and where this server should process incoming
981  * messages).
982  *
983  * @param server the server to use
984  * @param connection the connection to manage (client must
985  *        stop using this connection from now on)
986  * @return the client handle (client should call
987  *         "client_drop" on the return value eventually)
988  */
989 struct GNUNET_SERVER_Client *
990 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
991                               struct GNUNET_CONNECTION_Handle *connection)
992 {
993   struct GNUNET_SERVER_Client *client;
994
995   client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
996   client->connection = connection;
997   client->reference_count = 1;
998   client->server = server;
999   client->last_activity = GNUNET_TIME_absolute_get ();
1000   client->next = server->clients;
1001   client->idle_timeout = server->idle_timeout;
1002   server->clients = client;
1003   if (NULL != server->mst_create)
1004     client->mst =
1005         server->mst_create (server->mst_cls, client);
1006   else
1007     client->mst =
1008         GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server);
1009   client->receive_pending = GNUNET_YES;
1010   GNUNET_CONNECTION_receive (client->connection,
1011                              GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1012                              client->idle_timeout, &process_incoming, client);
1013   return client;
1014 }
1015
1016
1017 /**
1018  * Change the timeout for a particular client.  Decreasing the timeout
1019  * may not go into effect immediately (only after the previous timeout
1020  * times out or activity happens on the socket).
1021  *
1022  * @param client the client to update
1023  * @param timeout new timeout for activities on the socket
1024  */
1025 void
1026 GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
1027                                   struct GNUNET_TIME_Relative timeout)
1028 {
1029   client->idle_timeout = timeout;
1030 }
1031
1032
1033 /**
1034  * Notify the server that the given client handle should
1035  * be kept (keeps the connection up if possible, increments
1036  * the internal reference counter).
1037  *
1038  * @param client the client to keep
1039  */
1040 void
1041 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1042 {
1043   client->reference_count++;
1044 }
1045
1046
1047 /**
1048  * Notify the server that the given client handle is no
1049  * longer required.  Decrements the reference counter.  If
1050  * that counter reaches zero an inactive connection maybe
1051  * closed.
1052  *
1053  * @param client the client to drop
1054  */
1055 void
1056 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1057 {
1058   GNUNET_assert (client->reference_count > 0);
1059   client->reference_count--;
1060   if ((client->shutdown_now == GNUNET_YES) && (client->reference_count == 0))
1061     GNUNET_SERVER_client_disconnect (client);
1062 }
1063
1064
1065 /**
1066  * Obtain the network address of the other party.
1067  *
1068  * @param client the client to get the address for
1069  * @param addr where to store the address
1070  * @param addrlen where to store the length of the address
1071  * @return GNUNET_OK on success
1072  */
1073 int
1074 GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1075                                   void **addr, size_t * addrlen)
1076 {
1077   return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
1078 }
1079
1080
1081 /**
1082  * Ask the server to notify us whenever a client disconnects.
1083  * This function is called whenever the actual network connection
1084  * is closed; the reference count may be zero or larger than zero
1085  * at this point.
1086  *
1087  * @param server the server manageing the clients
1088  * @param callback function to call on disconnect
1089  * @param callback_cls closure for callback
1090  */
1091 void
1092 GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1093                                  GNUNET_SERVER_DisconnectCallback callback,
1094                                  void *callback_cls)
1095 {
1096   struct NotifyList *n;
1097
1098   n = GNUNET_malloc (sizeof (struct NotifyList));
1099   n->callback = callback;
1100   n->callback_cls = callback_cls;
1101   n->next = server->disconnect_notify_list;
1102   server->disconnect_notify_list = n;
1103 }
1104
1105
1106 /**
1107  * Ask the server to stop notifying us whenever a client disconnects.
1108  *
1109  * @param server the server manageing the clients
1110  * @param callback function to call on disconnect
1111  * @param callback_cls closure for callback
1112  */
1113 void
1114 GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1115                                         GNUNET_SERVER_DisconnectCallback
1116                                         callback, void *callback_cls)
1117 {
1118   struct NotifyList *pos;
1119   struct NotifyList *prev;
1120
1121   prev = NULL;
1122   pos = server->disconnect_notify_list;
1123   while (pos != NULL)
1124   {
1125     if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1126       break;
1127     prev = pos;
1128     pos = pos->next;
1129   }
1130   if (pos == NULL)
1131   {
1132     GNUNET_break (0);
1133     return;
1134   }
1135   if (prev == NULL)
1136     server->disconnect_notify_list = pos->next;
1137   else
1138     prev->next = pos->next;
1139   GNUNET_free (pos);
1140 }
1141
1142
1143 /**
1144  * Ask the server to disconnect from the given client.
1145  * This is the same as returning GNUNET_SYSERR from a message
1146  * handler, except that it allows dropping of a client even
1147  * when not handling a message from that client.
1148  *
1149  * @param client the client to disconnect from
1150  */
1151 void
1152 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1153 {
1154   struct GNUNET_SERVER_Client *prev;
1155   struct GNUNET_SERVER_Client *pos;
1156   struct GNUNET_SERVER_Handle *server;
1157   struct NotifyList *n;
1158   unsigned int rc;
1159
1160   LOG (GNUNET_ERROR_TYPE_DEBUG,
1161        "Client is being disconnected from the server.\n");
1162   if (client->restart_task != GNUNET_SCHEDULER_NO_TASK)
1163   {
1164     GNUNET_SCHEDULER_cancel (client->restart_task);
1165     client->restart_task = GNUNET_SCHEDULER_NO_TASK;
1166   }
1167   if (client->warn_task != GNUNET_SCHEDULER_NO_TASK)
1168   {
1169     GNUNET_SCHEDULER_cancel (client->warn_task);
1170     client->warn_task = GNUNET_SCHEDULER_NO_TASK;
1171   }
1172   if (GNUNET_YES == client->receive_pending)
1173   {
1174     GNUNET_CONNECTION_receive_cancel (client->connection);
1175     client->receive_pending = GNUNET_NO;
1176   }
1177
1178   rc = client->reference_count;
1179   if (client->shutdown_now != GNUNET_YES)
1180   {
1181     server = client->server;
1182     client->shutdown_now = GNUNET_YES;
1183     prev = NULL;
1184     pos = server->clients;
1185     while ((pos != NULL) && (pos != client))
1186     {
1187       prev = pos;
1188       pos = pos->next;
1189     }
1190     GNUNET_assert (pos != NULL);
1191     if (prev == NULL)
1192       server->clients = pos->next;
1193     else
1194       prev->next = pos->next;
1195     if (client->restart_task != GNUNET_SCHEDULER_NO_TASK)
1196     {
1197       GNUNET_SCHEDULER_cancel (client->restart_task);
1198       client->restart_task = GNUNET_SCHEDULER_NO_TASK;
1199     }
1200     if (client->warn_task != GNUNET_SCHEDULER_NO_TASK)
1201     {
1202       GNUNET_SCHEDULER_cancel (client->warn_task);
1203       client->warn_task = GNUNET_SCHEDULER_NO_TASK;
1204     }
1205     n = server->disconnect_notify_list;
1206     while (n != NULL)
1207     {
1208       n->callback (n->callback_cls, client);
1209       n = n->next;
1210     }
1211   }
1212   if (rc > 0)
1213   {
1214     LOG (GNUNET_ERROR_TYPE_DEBUG,
1215          "RC still positive, not destroying everything.\n");
1216     return;
1217   }
1218   if (client->in_process_client_buffer == GNUNET_YES)
1219   {
1220     LOG (GNUNET_ERROR_TYPE_DEBUG,
1221          "Still processing inputs, not destroying everything.\n");
1222     return;
1223   }
1224
1225   if (client->persist == GNUNET_YES)
1226     GNUNET_CONNECTION_persist_ (client->connection);
1227   GNUNET_CONNECTION_destroy (client->connection);
1228
1229   if (client->server->mst_destroy != NULL)
1230     client->server->mst_destroy (client->server->mst_cls, client->mst);
1231   else
1232     GNUNET_SERVER_mst_destroy (client->mst);
1233
1234   GNUNET_free (client);
1235 }
1236
1237
1238 /**
1239  * Disable the "CORK" feature for communication with the given client,
1240  * forcing the OS to immediately flush the buffer on transmission
1241  * instead of potentially buffering multiple messages.
1242  *
1243  * @param client handle to the client
1244  * @return GNUNET_OK on success
1245  */
1246 int
1247 GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
1248 {
1249   return GNUNET_CONNECTION_disable_corking (client->connection);
1250 }
1251
1252
1253 /**
1254  * Wrapper for transmission notification that calls the original
1255  * callback and update the last activity time for our connection.
1256  *
1257  * @param cls the 'struct GNUNET_SERVER_Client'
1258  * @param size number of bytes we can transmit
1259  * @param buf where to copy the message
1260  * @return number of bytes actually transmitted
1261  */
1262 static size_t
1263 transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
1264 {
1265   struct GNUNET_SERVER_Client *client = cls;
1266   GNUNET_CONNECTION_TransmitReadyNotify callback;
1267   size_t ret;
1268
1269   client->th.cth = NULL;
1270   callback = client->th.callback;
1271   client->th.callback = NULL;
1272   ret = callback (client->th.callback_cls, size, buf);
1273   if (ret > 0)
1274     client->last_activity = GNUNET_TIME_absolute_get ();
1275   return ret;
1276 }
1277
1278
1279 /**
1280  * Notify us when the server has enough space to transmit
1281  * a message of the given size to the given client.
1282  *
1283  * @param client client to transmit message to
1284  * @param size requested amount of buffer space
1285  * @param timeout after how long should we give up (and call
1286  *        notify with buf NULL and size 0)?
1287  * @param callback function to call when space is available
1288  * @param callback_cls closure for callback
1289  * @return non-NULL if the notify callback was queued; can be used
1290  *           to cancel the request using
1291  *           GNUNET_SERVER_notify_transmit_ready_cancel.
1292  *         NULL if we are already going to notify someone else (busy)
1293  */
1294 struct GNUNET_SERVER_TransmitHandle *
1295 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1296                                      size_t size,
1297                                      struct GNUNET_TIME_Relative timeout,
1298                                      GNUNET_CONNECTION_TransmitReadyNotify
1299                                      callback, void *callback_cls)
1300 {
1301   if (NULL != client->th.callback)
1302     return NULL;
1303   client->th.callback_cls = callback_cls;
1304   client->th.callback = callback;
1305   client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
1306                                                             timeout,
1307                                                             &transmit_ready_callback_wrapper,
1308                                                             client);
1309   return &client->th;
1310 }
1311
1312
1313 /**
1314  * Abort transmission request.
1315  *
1316  * @param th request to abort
1317  */
1318 void
1319 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
1320 {
1321   GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
1322   th->cth = NULL;
1323   th->callback = NULL;
1324 }
1325
1326
1327 /**
1328  * Set the persistent flag on this client, used to setup client connection
1329  * to only be killed when the service it's connected to is actually dead.
1330  *
1331  * @param client the client to set the persistent flag on
1332  */
1333 void
1334 GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1335 {
1336   client->persist = GNUNET_YES;
1337 }
1338
1339
1340 /**
1341  * Resume receiving from this client, we are done processing the
1342  * current request.  This function must be called from within each
1343  * GNUNET_SERVER_MessageCallback (or its respective continuations).
1344  *
1345  * @param client client we were processing a message of
1346  * @param success GNUNET_OK to keep the connection open and
1347  *                          continue to receive
1348  *                GNUNET_NO to close the connection (normal behavior)
1349  *                GNUNET_SYSERR to close the connection (signal
1350  *                          serious error)
1351  */
1352 void
1353 GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success)
1354 {
1355   if (client == NULL)
1356     return;
1357   GNUNET_assert (client->suspended > 0);
1358   client->suspended--;
1359   if (success != GNUNET_OK)
1360   {
1361     LOG (GNUNET_ERROR_TYPE_DEBUG,
1362          "GNUNET_SERVER_receive_done called with failure indication\n");
1363     GNUNET_SERVER_client_disconnect (client);
1364     return;
1365   }
1366   if (client->suspended > 0)
1367   {
1368     LOG (GNUNET_ERROR_TYPE_DEBUG,
1369          "GNUNET_SERVER_receive_done called, but more clients pending\n");
1370     return;
1371   }
1372   if (GNUNET_SCHEDULER_NO_TASK != client->warn_task)
1373   {
1374     GNUNET_SCHEDULER_cancel (client->warn_task);
1375     client->warn_task = GNUNET_SCHEDULER_NO_TASK;
1376   }
1377   if (client->in_process_client_buffer == GNUNET_YES)
1378   {
1379     LOG (GNUNET_ERROR_TYPE_DEBUG,
1380          "GNUNET_SERVER_receive_done called while still in processing loop\n");
1381     return;
1382   }
1383   if ((client->server == NULL) || (GNUNET_YES == client->shutdown_now))
1384   {
1385     GNUNET_SERVER_client_disconnect (client);
1386     return;
1387   }
1388   LOG (GNUNET_ERROR_TYPE_DEBUG,
1389        "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
1390   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->restart_task);
1391   client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing, client);
1392 }
1393
1394
1395 /**
1396  * Configure this server's connections to continue handling client
1397  * requests as usual even after we get a shutdown signal.  The change
1398  * only applies to clients that connect to the server from the outside
1399  * using TCP after this call.  Clients managed previously or those
1400  * added using GNUNET_SERVER_connect_socket and
1401  * GNUNET_SERVER_connect_callback are not affected by this option.
1402  *
1403  * @param h server handle
1404  * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default
1405  */
1406 void
1407 GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore)
1408 {
1409   h->clients_ignore_shutdown = do_ignore;
1410 }
1411
1412 /* end of server.c */