5a2eee28d517e0e1ff7c8c1074621eadc22d93e4
[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_TIME_UNIT_FOREVER_REL, r, NULL,
328                                      &process_listen_socket, server);
329     GNUNET_NETWORK_fdset_destroy (r);
330     return;
331   }
332   i = 0;
333   while (NULL != server->listen_sockets[i])
334   {
335     if (GNUNET_NETWORK_fdset_isset (tc->read_ready, server->listen_sockets[i]))
336     {
337       sock =
338           GNUNET_CONNECTION_create_from_accept (server->access,
339                                                 server->access_cls,
340                                                 server->listen_sockets[i]);
341       if (sock != NULL)
342       {
343         LOG (GNUNET_ERROR_TYPE_DEBUG, "Server accepted incoming connection.\n");
344         client = GNUNET_SERVER_connect_socket (server, sock);
345         GNUNET_CONNECTION_ignore_shutdown (sock,
346                                            server->clients_ignore_shutdown);
347         /* decrement reference count, we don't keep "client" alive */
348         GNUNET_SERVER_client_drop (client);
349       }
350     }
351     i++;
352   }
353   /* listen for more! */
354   server->listen_task =
355       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
356                                    GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
357                                    &process_listen_socket, server);
358   GNUNET_NETWORK_fdset_destroy (r);
359 }
360
361
362 /**
363  * Create and initialize a listen socket for the server.
364  *
365  * @param serverAddr address to listen on
366  * @param socklen length of address
367  * @return NULL on error, otherwise the listen socket
368  */
369 static struct GNUNET_NETWORK_Handle *
370 open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
371 {
372   const static int on = 1;
373   struct GNUNET_NETWORK_Handle *sock;
374   uint16_t port;
375   int eno;
376
377   switch (serverAddr->sa_family)
378   {
379   case AF_INET:
380     port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port);
381     break;
382   case AF_INET6:
383     port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port);
384     break;
385   case AF_UNIX:
386     port = 0;
387     break;
388   default:
389     GNUNET_break (0);
390     port = 0;
391     break;
392   }
393   sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0);
394   if (NULL == sock)
395   {
396     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
397     errno = 0;
398     return NULL;
399   }
400   if (port != 0)
401   {
402     if (GNUNET_NETWORK_socket_setsockopt
403         (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
404       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
405                     "setsockopt");
406 #ifdef IPV6_V6ONLY
407     if ((serverAddr->sa_family == AF_INET6) &&
408         (GNUNET_NETWORK_socket_setsockopt
409          (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
410       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
411                     "setsockopt");
412 #endif
413   }
414   /* bind the socket */
415   if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK)
416   {
417     eno = errno;
418     if (errno != EADDRINUSE)
419     {
420       /* we don't log 'EADDRINUSE' here since an IPv4 bind may
421        * fail if we already took the port on IPv6; if both IPv4 and
422        * IPv6 binds fail, then our caller will log using the
423        * errno preserved in 'eno' */
424       LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
425       if (port != 0)
426         LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed for port %d (%s).\n"),
427              "bind", port,
428              (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6");
429       eno = 0;
430     }
431     else
432     {
433       if (port != 0)
434         LOG (GNUNET_ERROR_TYPE_WARNING,
435              _("`%s' failed for port %d (%s): address already in use\n"),
436              "bind", port,
437              (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6");
438       else if (serverAddr->sa_family == AF_UNIX)
439         LOG (GNUNET_ERROR_TYPE_WARNING,
440              _("`%s' failed for `%s': address already in use\n"), "bind",
441              ((const struct sockaddr_un *) serverAddr)->sun_path);
442
443     }
444     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
445     errno = eno;
446     return NULL;
447   }
448   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
449   {
450     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen");
451     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
452     errno = 0;
453     return NULL;
454   }
455   if (port != 0)
456     LOG (GNUNET_ERROR_TYPE_DEBUG, "Server starts to listen on port %u.\n",
457          port);
458   return sock;
459 }
460
461
462 /**
463  * Create a new server.
464  *
465  * @param access function for access control
466  * @param access_cls closure for access
467  * @param lsocks NULL-terminated array of listen sockets
468  * @param idle_timeout after how long should we timeout idle connections?
469  * @param require_found if YES, connections sending messages of unknown type
470  *        will be closed
471  * @return handle for the new server, NULL on error
472  *         (typically, "port" already in use)
473  */
474 struct GNUNET_SERVER_Handle *
475 GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access,
476                                    void *access_cls,
477                                    struct GNUNET_NETWORK_Handle **lsocks,
478                                    struct GNUNET_TIME_Relative idle_timeout,
479                                    int require_found)
480 {
481   struct GNUNET_SERVER_Handle *ret;
482   struct GNUNET_NETWORK_FDSet *r;
483   int i;
484
485   ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle));
486   ret->idle_timeout = idle_timeout;
487   ret->listen_sockets = lsocks;
488   ret->access = access;
489   ret->access_cls = access_cls;
490   ret->require_found = require_found;
491   if (lsocks != NULL)
492   {
493     r = GNUNET_NETWORK_fdset_create ();
494     i = 0;
495     while (NULL != ret->listen_sockets[i])
496       GNUNET_NETWORK_fdset_set (r, ret->listen_sockets[i++]);
497     ret->listen_task =
498         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
499                                      GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
500                                      &process_listen_socket, ret);
501     GNUNET_NETWORK_fdset_destroy (r);
502   }
503   return ret;
504 }
505
506
507 /**
508  * Create a new server.
509  *
510  * @param access function for access control
511  * @param access_cls closure for access
512  * @param serverAddr address to listen on (including port), NULL terminated array
513  * @param socklen length of serverAddr
514  * @param idle_timeout after how long should we timeout idle connections?
515  * @param require_found if YES, connections sending messages of unknown type
516  *        will be closed
517  * @return handle for the new server, NULL on error
518  *         (typically, "port" already in use)
519  */
520 struct GNUNET_SERVER_Handle *
521 GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls,
522                       struct sockaddr *const *serverAddr,
523                       const socklen_t * socklen,
524                       struct GNUNET_TIME_Relative idle_timeout,
525                       int require_found)
526 {
527   struct GNUNET_NETWORK_Handle **lsocks;
528   unsigned int i;
529   unsigned int j;
530
531   i = 0;
532   while (serverAddr[i] != NULL)
533     i++;
534   if (i > 0)
535   {
536     lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
537     i = 0;
538     j = 0;
539     while (serverAddr[i] != NULL)
540     {
541       lsocks[j] = open_listen_socket (serverAddr[i], socklen[i]);
542       if (lsocks[j] != NULL)
543         j++;
544       i++;
545     }
546     if (j == 0)
547     {
548       if (errno != 0)
549         LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
550       GNUNET_free (lsocks);
551       lsocks = NULL;
552     }
553   }
554   else
555   {
556     lsocks = NULL;
557   }
558   return GNUNET_SERVER_create_with_sockets (access, access_cls, lsocks,
559                                             idle_timeout, require_found);
560 }
561
562
563 /**
564  * Free resources held by this server.
565  *
566  * @param s server to destroy
567  */
568 void
569 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s)
570 {
571   struct HandlerList *hpos;
572   struct NotifyList *npos;
573   unsigned int i;
574
575   LOG (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n");
576   if (GNUNET_SCHEDULER_NO_TASK != s->listen_task)
577   {
578     GNUNET_SCHEDULER_cancel (s->listen_task);
579     s->listen_task = GNUNET_SCHEDULER_NO_TASK;
580   }
581   if (s->listen_sockets != NULL)
582   {
583     i = 0;
584     while (s->listen_sockets[i] != NULL)
585       GNUNET_break (GNUNET_OK ==
586                     GNUNET_NETWORK_socket_close (s->listen_sockets[i++]));
587     GNUNET_free (s->listen_sockets);
588     s->listen_sockets = NULL;
589   }
590   while (s->clients != NULL)
591     GNUNET_SERVER_client_disconnect (s->clients);
592   while (NULL != (hpos = s->handlers))
593   {
594     s->handlers = hpos->next;
595     GNUNET_free (hpos);
596   }
597   while (NULL != (npos = s->disconnect_notify_list))
598   {
599     npos->callback (npos->callback_cls, NULL);
600     s->disconnect_notify_list = npos->next;
601     GNUNET_free (npos);
602   }
603   GNUNET_free (s);
604 }
605
606
607 /**
608  * Add additional handlers to an existing server.
609  *
610  * @param server the server to add handlers to
611  * @param handlers array of message handlers for
612  *        incoming messages; the last entry must
613  *        have "NULL" for the "callback"; multiple
614  *        entries for the same type are allowed,
615  *        they will be called in order of occurence.
616  *        These handlers can be removed later;
617  *        the handlers array must exist until removed
618  *        (or server is destroyed).
619  */
620 void
621 GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
622                             const struct GNUNET_SERVER_MessageHandler *handlers)
623 {
624   struct HandlerList *p;
625
626   p = GNUNET_malloc (sizeof (struct HandlerList));
627   p->handlers = handlers;
628   p->next = server->handlers;
629   server->handlers = p;
630 }
631
632
633 void
634 GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
635                              GNUNET_SERVER_MstCreateCallback create,
636                              GNUNET_SERVER_MstDestroyCallback destroy,
637                              GNUNET_SERVER_MstReceiveCallback receive,
638                              void *cls)
639 {
640   server->mst_create = create;
641   server->mst_destroy = destroy;
642   server->mst_receive = receive;
643   server->mst_cls = cls;
644 }
645
646
647 /**
648  * Task run to warn about missing calls to 'GNUNET_SERVER_receive_done'.
649  *
650  * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from
651  * @param tc scheduler context (unused)
652  */
653 static void
654 warn_no_receive_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
655 {
656   struct GNUNET_SERVER_Client *client = cls;
657
658   client->warn_task =
659       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
660                                     &warn_no_receive_done, client);
661   if (0 == (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
662     LOG (GNUNET_ERROR_TYPE_WARNING,
663          _
664          ("Processing code for message of type %u did not call GNUNET_SERVER_receive_done after %llums\n"),
665          (unsigned int) client->warn_type,
666          (unsigned long long)
667          GNUNET_TIME_absolute_get_duration (client->warn_start).rel_value);
668 }
669
670
671 /**
672  * Disable the warning the server issues if a message is not acknowledged
673  * in a timely fashion.  Use this call if a client is intentionally delayed
674  * for a while.  Only applies to the current message.
675  *
676  * @param client client for which to disable the warning
677  */
678 void
679 GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
680 {
681   if (GNUNET_SCHEDULER_NO_TASK != client->warn_task)
682   {
683     GNUNET_SCHEDULER_cancel (client->warn_task);
684     client->warn_task = GNUNET_SCHEDULER_NO_TASK;
685   }
686 }
687
688
689 /**
690  * Inject a message into the server, pretend it came
691  * from the specified client.  Delivery of the message
692  * will happen instantly (if a handler is installed;
693  * otherwise the call does nothing).
694  *
695  * @param server the server receiving the message
696  * @param sender the "pretended" sender of the message
697  *        can be NULL!
698  * @param message message to transmit
699  * @return GNUNET_OK if the message was OK and the
700  *                   connection can stay open
701  *         GNUNET_SYSERR if the connection to the
702  *         client should be shut down
703  */
704 int
705 GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
706                       struct GNUNET_SERVER_Client *sender,
707                       const struct GNUNET_MessageHeader *message)
708 {
709   struct HandlerList *pos;
710   const struct GNUNET_SERVER_MessageHandler *mh;
711   unsigned int i;
712   uint16_t type;
713   uint16_t size;
714   int found;
715
716   type = ntohs (message->type);
717   size = ntohs (message->size);
718   LOG (GNUNET_ERROR_TYPE_DEBUG,
719        "Server schedules transmission of %u-byte message of type %u to client.\n",
720        size, type);
721   pos = server->handlers;
722   found = GNUNET_NO;
723   while (pos != NULL)
724   {
725     i = 0;
726     while (pos->handlers[i].callback != NULL)
727     {
728       mh = &pos->handlers[i];
729       if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
730       {
731         if ((mh->expected_size != 0) && (mh->expected_size != size))
732         {
733 #if GNUNET8_NETWORK_IS_DEAD
734           LOG (GNUNET_ERROR_TYPE_WARNING,
735                "Expected %u bytes for message of type %u, got %u\n",
736                mh->expected_size, mh->type, size);
737           GNUNET_break_op (0);
738 #endif
739           return GNUNET_SYSERR;
740         }
741         if (sender != NULL)
742         {
743           if (0 == sender->suspended)
744           {
745             sender->warn_start = GNUNET_TIME_absolute_get ();
746             sender->warn_task =
747                 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
748                                               &warn_no_receive_done, sender);
749             sender->warn_type = type;
750           }
751           sender->suspended++;
752         }
753         mh->callback (mh->callback_cls, sender, message);
754         found = GNUNET_YES;
755       }
756       i++;
757     }
758     pos = pos->next;
759   }
760   if (found == GNUNET_NO)
761   {
762     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
763          "Received message of unknown type %d\n", type);
764     if (server->require_found == GNUNET_YES)
765       return GNUNET_SYSERR;
766   }
767   return GNUNET_OK;
768 }
769
770
771 /**
772  * We are receiving an incoming message.  Process it.
773  *
774  * @param cls our closure (handle for the client)
775  * @param buf buffer with data received from network
776  * @param available number of bytes available in buf
777  * @param addr address of the sender
778  * @param addrlen length of addr
779  * @param errCode code indicating errors receiving, 0 for success
780  */
781 static void
782 process_incoming (void *cls, const void *buf, size_t available,
783                   const struct sockaddr *addr, socklen_t addrlen, int errCode);
784
785
786 /**
787  * Process messages from the client's message tokenizer until either
788  * the tokenizer is empty (and then schedule receiving more), or
789  * until some handler is not immediately done (then wait for restart_processing)
790  * or shutdown.
791  *
792  * @param client the client to process, RC must have already been increased
793  *        using GNUNET_SERVER_client_keep and will be decreased by one in this
794  *        function
795  * @param ret GNUNET_NO to start processing from the buffer,
796  *            GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
797  *            GNUNET_SYSERR if we should instantly abort due to error in a previous step
798  */
799 static void
800 process_mst (struct GNUNET_SERVER_Client *client, int ret)
801 {
802   while ((ret != GNUNET_SYSERR) && (client->server != NULL) &&
803          (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
804   {
805     if (ret == GNUNET_OK)
806     {
807       LOG (GNUNET_ERROR_TYPE_DEBUG,
808            "Server re-enters receive loop, timeout: %llu.\n",
809            client->idle_timeout.rel_value);
810       client->receive_pending = GNUNET_YES;
811       GNUNET_CONNECTION_receive (client->connection,
812                                  GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
813                                  client->idle_timeout, &process_incoming,
814                                  client);
815       break;
816     }
817     LOG (GNUNET_ERROR_TYPE_DEBUG,
818          "Server processes additional messages instantly.\n");
819     if (client->server->mst_receive != NULL)
820       ret =
821           client->server->mst_receive (client->server->mst_cls, client->mst,
822                                        client, NULL, 0, GNUNET_NO, GNUNET_YES);
823     else
824       ret =
825           GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
826                                      GNUNET_YES);
827   }
828   LOG (GNUNET_ERROR_TYPE_DEBUG,
829        "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
830        ret, client->server, client->shutdown_now, client->suspended);
831   if (ret == GNUNET_NO)
832   {
833     LOG (GNUNET_ERROR_TYPE_DEBUG,
834          "Server has more data pending but is suspended.\n");
835     client->receive_pending = GNUNET_SYSERR;    /* data pending */
836   }
837   if ((ret == GNUNET_SYSERR) || (GNUNET_YES == client->shutdown_now))
838     GNUNET_SERVER_client_disconnect (client);
839   GNUNET_SERVER_client_drop (client);
840 }
841
842
843 /**
844  * We are receiving an incoming message.  Process it.
845  *
846  * @param cls our closure (handle for the client)
847  * @param buf buffer with data received from network
848  * @param available number of bytes available in buf
849  * @param addr address of the sender
850  * @param addrlen length of addr
851  * @param errCode code indicating errors receiving, 0 for success
852  */
853 static void
854 process_incoming (void *cls, const void *buf, size_t available,
855                   const struct sockaddr *addr, socklen_t addrlen, int errCode)
856 {
857   struct GNUNET_SERVER_Client *client = cls;
858   struct GNUNET_SERVER_Handle *server = client->server;
859   struct GNUNET_TIME_Absolute end;
860   struct GNUNET_TIME_Absolute now;
861   int ret;
862
863   GNUNET_assert (client->receive_pending == GNUNET_YES);
864   client->receive_pending = GNUNET_NO;
865   now = GNUNET_TIME_absolute_get ();
866   end = GNUNET_TIME_absolute_add (client->last_activity, client->idle_timeout);
867
868   if ((buf == NULL) && (available == 0) && (addr == NULL) && (errCode == 0) &&
869       (client->shutdown_now != GNUNET_YES) && (server != NULL) &&
870       (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
871       (end.abs_value > now.abs_value))
872   {
873     /* wait longer, timeout changed (i.e. due to us sending) */
874     LOG (GNUNET_ERROR_TYPE_DEBUG,
875          "Receive time out, but no disconnect due to sending (%p)\n",
876          GNUNET_a2s (addr, addrlen));
877     client->receive_pending = GNUNET_YES;
878     GNUNET_CONNECTION_receive (client->connection,
879                                GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
880                                GNUNET_TIME_absolute_get_remaining (end),
881                                &process_incoming, client);
882     return;
883   }
884   if ((buf == NULL) || (available == 0) || (errCode != 0) || (server == NULL) ||
885       (client->shutdown_now == GNUNET_YES) ||
886       (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)))
887   {
888     /* other side closed connection, error connecting, etc. */
889     GNUNET_SERVER_client_disconnect (client);
890     return;
891   }
892   LOG (GNUNET_ERROR_TYPE_DEBUG, "Server receives %u bytes from `%s'.\n",
893        (unsigned int) available, GNUNET_a2s (addr, addrlen));
894   GNUNET_SERVER_client_keep (client);
895   client->last_activity = now;
896
897   if (server->mst_receive != NULL)
898     ret =
899         client->server->mst_receive (client->server->mst_cls, client->mst,
900                                      client, buf, available, GNUNET_NO, GNUNET_YES);
901   else
902     ret =
903         GNUNET_SERVER_mst_receive (client->mst, client, buf, available, GNUNET_NO,
904                                    GNUNET_YES);
905
906   process_mst (client, ret);
907 }
908
909
910 /**
911  * Task run to start again receiving from the network
912  * and process requests.
913  *
914  * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from
915  * @param tc scheduler context (unused)
916  */
917 static void
918 restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
919 {
920   struct GNUNET_SERVER_Client *client = cls;
921   struct GNUNET_SERVER_Handle *server = client->server;
922
923   client->restart_task = GNUNET_SCHEDULER_NO_TASK;
924   if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
925       (GNUNET_NO == server->clients_ignore_shutdown))
926   {
927     GNUNET_SERVER_client_disconnect (client);
928     return;
929   }
930   if (client->receive_pending == GNUNET_NO)
931   {
932     LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
933     client->receive_pending = GNUNET_YES;
934     GNUNET_CONNECTION_receive (client->connection,
935                                GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
936                                client->idle_timeout, &process_incoming, client);
937     return;
938   }
939   LOG (GNUNET_ERROR_TYPE_DEBUG,
940        "Server continues processing messages still in the buffer.\n");
941   GNUNET_SERVER_client_keep (client);
942   client->receive_pending = GNUNET_NO;
943   process_mst (client, GNUNET_NO);
944 }
945
946
947 /**
948  * This function is called whenever our inbound message tokenizer has
949  * received a complete message.
950  *
951  * @param cls closure (struct GNUNET_SERVER_Handle)
952  * @param client identification of the client (struct GNUNET_SERVER_Client*)
953  * @param message the actual message
954  */
955 static void
956 client_message_tokenizer_callback (void *cls, void *client,
957                                    const struct GNUNET_MessageHeader *message)
958 {
959   struct GNUNET_SERVER_Handle *server = cls;
960   struct GNUNET_SERVER_Client *sender = client;
961   int ret;
962
963   LOG (GNUNET_ERROR_TYPE_DEBUG,
964        "Tokenizer gives server message of type %u from client\n",
965        ntohs (message->type));
966   sender->in_process_client_buffer = GNUNET_YES;
967   ret = GNUNET_SERVER_inject (server, sender, message);
968   sender->in_process_client_buffer = GNUNET_NO;
969   if (GNUNET_OK != ret)
970     GNUNET_SERVER_client_disconnect (sender);
971 }
972
973
974 /**
975  * Add a TCP socket-based connection to the set of handles managed by
976  * this server.  Use this function for outgoing (P2P) connections that
977  * we initiated (and where this server should process incoming
978  * messages).
979  *
980  * @param server the server to use
981  * @param connection the connection to manage (client must
982  *        stop using this connection from now on)
983  * @return the client handle (client should call
984  *         "client_drop" on the return value eventually)
985  */
986 struct GNUNET_SERVER_Client *
987 GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
988                               struct GNUNET_CONNECTION_Handle *connection)
989 {
990   struct GNUNET_SERVER_Client *client;
991
992   client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
993   client->connection = connection;
994   client->reference_count = 1;
995   client->server = server;
996   client->last_activity = GNUNET_TIME_absolute_get ();
997   client->next = server->clients;
998   client->idle_timeout = server->idle_timeout;
999   server->clients = client;
1000   if (NULL != server->mst_create)
1001     client->mst =
1002         server->mst_create (server->mst_cls, client);
1003   else
1004     client->mst =
1005         GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server);
1006   client->receive_pending = GNUNET_YES;
1007   GNUNET_CONNECTION_receive (client->connection,
1008                              GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1009                              client->idle_timeout, &process_incoming, client);
1010   return client;
1011 }
1012
1013
1014 /**
1015  * Change the timeout for a particular client.  Decreasing the timeout
1016  * may not go into effect immediately (only after the previous timeout
1017  * times out or activity happens on the socket).
1018  *
1019  * @param client the client to update
1020  * @param timeout new timeout for activities on the socket
1021  */
1022 void
1023 GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
1024                                   struct GNUNET_TIME_Relative timeout)
1025 {
1026   client->idle_timeout = timeout;
1027 }
1028
1029
1030 /**
1031  * Notify the server that the given client handle should
1032  * be kept (keeps the connection up if possible, increments
1033  * the internal reference counter).
1034  *
1035  * @param client the client to keep
1036  */
1037 void
1038 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1039 {
1040   client->reference_count++;
1041 }
1042
1043
1044 /**
1045  * Notify the server that the given client handle is no
1046  * longer required.  Decrements the reference counter.  If
1047  * that counter reaches zero an inactive connection maybe
1048  * closed.
1049  *
1050  * @param client the client to drop
1051  */
1052 void
1053 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1054 {
1055   GNUNET_assert (client->reference_count > 0);
1056   client->reference_count--;
1057   if ((client->shutdown_now == GNUNET_YES) && (client->reference_count == 0))
1058     GNUNET_SERVER_client_disconnect (client);
1059 }
1060
1061
1062 /**
1063  * Obtain the network address of the other party.
1064  *
1065  * @param client the client to get the address for
1066  * @param addr where to store the address
1067  * @param addrlen where to store the length of the address
1068  * @return GNUNET_OK on success
1069  */
1070 int
1071 GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1072                                   void **addr, size_t * addrlen)
1073 {
1074   return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
1075 }
1076
1077
1078 /**
1079  * Ask the server to notify us whenever a client disconnects.
1080  * This function is called whenever the actual network connection
1081  * is closed; the reference count may be zero or larger than zero
1082  * at this point.
1083  *
1084  * @param server the server manageing the clients
1085  * @param callback function to call on disconnect
1086  * @param callback_cls closure for callback
1087  */
1088 void
1089 GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1090                                  GNUNET_SERVER_DisconnectCallback callback,
1091                                  void *callback_cls)
1092 {
1093   struct NotifyList *n;
1094
1095   n = GNUNET_malloc (sizeof (struct NotifyList));
1096   n->callback = callback;
1097   n->callback_cls = callback_cls;
1098   n->next = server->disconnect_notify_list;
1099   server->disconnect_notify_list = n;
1100 }
1101
1102
1103 /**
1104  * Ask the server to stop notifying us whenever a client disconnects.
1105  *
1106  * @param server the server manageing the clients
1107  * @param callback function to call on disconnect
1108  * @param callback_cls closure for callback
1109  */
1110 void
1111 GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1112                                         GNUNET_SERVER_DisconnectCallback
1113                                         callback, void *callback_cls)
1114 {
1115   struct NotifyList *pos;
1116   struct NotifyList *prev;
1117
1118   prev = NULL;
1119   pos = server->disconnect_notify_list;
1120   while (pos != NULL)
1121   {
1122     if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1123       break;
1124     prev = pos;
1125     pos = pos->next;
1126   }
1127   if (pos == NULL)
1128   {
1129     GNUNET_break (0);
1130     return;
1131   }
1132   if (prev == NULL)
1133     server->disconnect_notify_list = pos->next;
1134   else
1135     prev->next = pos->next;
1136   GNUNET_free (pos);
1137 }
1138
1139
1140 /**
1141  * Ask the server to disconnect from the given client.
1142  * This is the same as returning GNUNET_SYSERR from a message
1143  * handler, except that it allows dropping of a client even
1144  * when not handling a message from that client.
1145  *
1146  * @param client the client to disconnect from
1147  */
1148 void
1149 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1150 {
1151   struct GNUNET_SERVER_Client *prev;
1152   struct GNUNET_SERVER_Client *pos;
1153   struct GNUNET_SERVER_Handle *server;
1154   struct NotifyList *n;
1155   unsigned int rc;
1156
1157   LOG (GNUNET_ERROR_TYPE_DEBUG,
1158        "Client is being disconnected from the server.\n");
1159   if (client->restart_task != GNUNET_SCHEDULER_NO_TASK)
1160   {
1161     GNUNET_SCHEDULER_cancel (client->restart_task);
1162     client->restart_task = GNUNET_SCHEDULER_NO_TASK;
1163   }
1164   if (client->warn_task != GNUNET_SCHEDULER_NO_TASK)
1165   {
1166     GNUNET_SCHEDULER_cancel (client->warn_task);
1167     client->warn_task = GNUNET_SCHEDULER_NO_TASK;
1168   }
1169   if (GNUNET_YES == client->receive_pending)
1170   {
1171     GNUNET_CONNECTION_receive_cancel (client->connection);
1172     client->receive_pending = GNUNET_NO;
1173   }
1174
1175   rc = client->reference_count;
1176   if (client->shutdown_now != GNUNET_YES)
1177   {
1178     server = client->server;
1179     client->shutdown_now = GNUNET_YES;
1180     prev = NULL;
1181     pos = server->clients;
1182     while ((pos != NULL) && (pos != client))
1183     {
1184       prev = pos;
1185       pos = pos->next;
1186     }
1187     GNUNET_assert (pos != NULL);
1188     if (prev == NULL)
1189       server->clients = pos->next;
1190     else
1191       prev->next = pos->next;
1192     if (client->restart_task != GNUNET_SCHEDULER_NO_TASK)
1193     {
1194       GNUNET_SCHEDULER_cancel (client->restart_task);
1195       client->restart_task = GNUNET_SCHEDULER_NO_TASK;
1196     }
1197     if (client->warn_task != GNUNET_SCHEDULER_NO_TASK)
1198     {
1199       GNUNET_SCHEDULER_cancel (client->warn_task);
1200       client->warn_task = GNUNET_SCHEDULER_NO_TASK;
1201     }
1202     n = server->disconnect_notify_list;
1203     while (n != NULL)
1204     {
1205       n->callback (n->callback_cls, client);
1206       n = n->next;
1207     }
1208   }
1209   if (rc > 0)
1210   {
1211     LOG (GNUNET_ERROR_TYPE_DEBUG,
1212          "RC still positive, not destroying everything.\n");
1213     return;
1214   }
1215   if (client->in_process_client_buffer == GNUNET_YES)
1216   {
1217     LOG (GNUNET_ERROR_TYPE_DEBUG,
1218          "Still processing inputs, not destroying everything.\n");
1219     return;
1220   }
1221
1222   if (client->persist == GNUNET_YES)
1223     GNUNET_CONNECTION_persist_ (client->connection);
1224   if (NULL != client->th.cth)
1225     GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
1226   GNUNET_CONNECTION_destroy (client->connection);
1227
1228   if (client->server->mst_destroy != NULL)
1229     client->server->mst_destroy (client->server->mst_cls, client->mst);
1230   else
1231     GNUNET_SERVER_mst_destroy (client->mst);
1232
1233   GNUNET_free (client);
1234 }
1235
1236
1237 /**
1238  * Disable the "CORK" feature for communication with the given client,
1239  * forcing the OS to immediately flush the buffer on transmission
1240  * instead of potentially buffering multiple messages.
1241  *
1242  * @param client handle to the client
1243  * @return GNUNET_OK on success
1244  */
1245 int
1246 GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
1247 {
1248   return GNUNET_CONNECTION_disable_corking (client->connection);
1249 }
1250
1251
1252 /**
1253  * Wrapper for transmission notification that calls the original
1254  * callback and update the last activity time for our connection.
1255  *
1256  * @param cls the 'struct GNUNET_SERVER_Client'
1257  * @param size number of bytes we can transmit
1258  * @param buf where to copy the message
1259  * @return number of bytes actually transmitted
1260  */
1261 static size_t
1262 transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
1263 {
1264   struct GNUNET_SERVER_Client *client = cls;
1265   GNUNET_CONNECTION_TransmitReadyNotify callback;
1266   size_t ret;
1267
1268   client->th.cth = NULL;
1269   callback = client->th.callback;
1270   client->th.callback = NULL;
1271   ret = callback (client->th.callback_cls, size, buf);
1272   if (ret > 0)
1273     client->last_activity = GNUNET_TIME_absolute_get ();
1274   return ret;
1275 }
1276
1277
1278 /**
1279  * Notify us when the server has enough space to transmit
1280  * a message of the given size to the given client.
1281  *
1282  * @param client client to transmit message to
1283  * @param size requested amount of buffer space
1284  * @param timeout after how long should we give up (and call
1285  *        notify with buf NULL and size 0)?
1286  * @param callback function to call when space is available
1287  * @param callback_cls closure for callback
1288  * @return non-NULL if the notify callback was queued; can be used
1289  *           to cancel the request using
1290  *           GNUNET_SERVER_notify_transmit_ready_cancel.
1291  *         NULL if we are already going to notify someone else (busy)
1292  */
1293 struct GNUNET_SERVER_TransmitHandle *
1294 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1295                                      size_t size,
1296                                      struct GNUNET_TIME_Relative timeout,
1297                                      GNUNET_CONNECTION_TransmitReadyNotify
1298                                      callback, void *callback_cls)
1299 {
1300   if (NULL != client->th.callback)
1301     return NULL;
1302   client->th.callback_cls = callback_cls;
1303   client->th.callback = callback;
1304   client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
1305                                                             timeout,
1306                                                             &transmit_ready_callback_wrapper,
1307                                                             client);
1308   return &client->th;
1309 }
1310
1311
1312 /**
1313  * Abort transmission request.
1314  *
1315  * @param th request to abort
1316  */
1317 void
1318 GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
1319 {
1320   GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
1321   th->cth = NULL;
1322   th->callback = NULL;
1323 }
1324
1325
1326 /**
1327  * Set the persistent flag on this client, used to setup client connection
1328  * to only be killed when the service it's connected to is actually dead.
1329  *
1330  * @param client the client to set the persistent flag on
1331  */
1332 void
1333 GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1334 {
1335   client->persist = GNUNET_YES;
1336 }
1337
1338
1339 /**
1340  * Resume receiving from this client, we are done processing the
1341  * current request.  This function must be called from within each
1342  * GNUNET_SERVER_MessageCallback (or its respective continuations).
1343  *
1344  * @param client client we were processing a message of
1345  * @param success GNUNET_OK to keep the connection open and
1346  *                          continue to receive
1347  *                GNUNET_NO to close the connection (normal behavior)
1348  *                GNUNET_SYSERR to close the connection (signal
1349  *                          serious error)
1350  */
1351 void
1352 GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success)
1353 {
1354   if (client == NULL)
1355     return;
1356   GNUNET_assert (client->suspended > 0);
1357   client->suspended--;
1358   if (success != GNUNET_OK)
1359   {
1360     LOG (GNUNET_ERROR_TYPE_DEBUG,
1361          "GNUNET_SERVER_receive_done called with failure indication\n");
1362     GNUNET_SERVER_client_disconnect (client);
1363     return;
1364   }
1365   if (client->suspended > 0)
1366   {
1367     LOG (GNUNET_ERROR_TYPE_DEBUG,
1368          "GNUNET_SERVER_receive_done called, but more clients pending\n");
1369     return;
1370   }
1371   if (GNUNET_SCHEDULER_NO_TASK != client->warn_task)
1372   {
1373     GNUNET_SCHEDULER_cancel (client->warn_task);
1374     client->warn_task = GNUNET_SCHEDULER_NO_TASK;
1375   }
1376   if (client->in_process_client_buffer == GNUNET_YES)
1377   {
1378     LOG (GNUNET_ERROR_TYPE_DEBUG,
1379          "GNUNET_SERVER_receive_done called while still in processing loop\n");
1380     return;
1381   }
1382   if ((client->server == NULL) || (GNUNET_YES == client->shutdown_now))
1383   {
1384     GNUNET_SERVER_client_disconnect (client);
1385     return;
1386   }
1387   LOG (GNUNET_ERROR_TYPE_DEBUG,
1388        "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
1389   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->restart_task);
1390   client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing, client);
1391 }
1392
1393
1394 /**
1395  * Configure this server's connections to continue handling client
1396  * requests as usual even after we get a shutdown signal.  The change
1397  * only applies to clients that connect to the server from the outside
1398  * using TCP after this call.  Clients managed previously or those
1399  * added using GNUNET_SERVER_connect_socket and
1400  * GNUNET_SERVER_connect_callback are not affected by this option.
1401  *
1402  * @param h server handle
1403  * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default
1404  */
1405 void
1406 GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore)
1407 {
1408   h->clients_ignore_shutdown = do_ignore;
1409 }
1410
1411 /* end of server.c */