aboutsummaryrefslogtreecommitdiff
path: root/src/transport/tcp_server_legacy.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-03-16 05:33:01 +0100
committerChristian Grothoff <christian@grothoff.org>2017-03-16 05:33:01 +0100
commitd23a815951413af100c74b38cdd09a01ca1c280a (patch)
tree5fd6a3eae1cd4497dc728917362067a8aded3151 /src/transport/tcp_server_legacy.c
parenta3acd27f0acf30a6c4803ec933c4fe7650bc296c (diff)
downloadgnunet-d23a815951413af100c74b38cdd09a01ca1c280a.tar.gz
gnunet-d23a815951413af100c74b38cdd09a01ca1c280a.zip
removing dead/legacy server/connection logic, except for in tcp/wlan/bt plugins (which will be updated 'later')
Diffstat (limited to 'src/transport/tcp_server_legacy.c')
-rw-r--r--src/transport/tcp_server_legacy.c1748
1 files changed, 1748 insertions, 0 deletions
diff --git a/src/transport/tcp_server_legacy.c b/src/transport/tcp_server_legacy.c
new file mode 100644
index 000000000..c055285b1
--- /dev/null
+++ b/src/transport/tcp_server_legacy.c
@@ -0,0 +1,1748 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file util/server.c
23 * @brief library for building GNUnet network servers
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30
31#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
32
33
34/**
35 * List of arrays of message handlers.
36 */
37struct HandlerList
38{
39 /**
40 * This is a linked list.
41 */
42 struct HandlerList *next;
43
44 /**
45 * NULL-terminated array of handlers.
46 */
47 const struct GNUNET_SERVER_MessageHandler *handlers;
48};
49
50
51/**
52 * List of arrays of message handlers.
53 */
54struct NotifyList
55{
56 /**
57 * This is a doubly linked list.
58 */
59 struct NotifyList *next;
60
61 /**
62 * This is a doubly linked list.
63 */
64 struct NotifyList *prev;
65
66 /**
67 * Function to call.
68 */
69 GNUNET_SERVER_DisconnectCallback callback;
70
71 /**
72 * Closure for callback.
73 */
74 void *callback_cls;
75};
76
77
78/**
79 * @brief handle for a server
80 */
81struct GNUNET_SERVER_Handle
82{
83 /**
84 * List of handlers for incoming messages.
85 */
86 struct HandlerList *handlers;
87
88 /**
89 * Head of list of our current clients.
90 */
91 struct GNUNET_SERVER_Client *clients_head;
92
93 /**
94 * Head of list of our current clients.
95 */
96 struct GNUNET_SERVER_Client *clients_tail;
97
98 /**
99 * Head of linked list of functions to call on disconnects by clients.
100 */
101 struct NotifyList *disconnect_notify_list_head;
102
103 /**
104 * Tail of linked list of functions to call on disconnects by clients.
105 */
106 struct NotifyList *disconnect_notify_list_tail;
107
108 /**
109 * Head of linked list of functions to call on connects by clients.
110 */
111 struct NotifyList *connect_notify_list_head;
112
113 /**
114 * Tail of linked list of functions to call on connects by clients.
115 */
116 struct NotifyList *connect_notify_list_tail;
117
118 /**
119 * Function to call for access control.
120 */
121 GNUNET_CONNECTION_AccessCheck access_cb;
122
123 /**
124 * Closure for @e access_cb.
125 */
126 void *access_cb_cls;
127
128 /**
129 * NULL-terminated array of sockets used to listen for new
130 * connections.
131 */
132 struct GNUNET_NETWORK_Handle **listen_sockets;
133
134 /**
135 * After how long should an idle connection time
136 * out (on write).
137 */
138 struct GNUNET_TIME_Relative idle_timeout;
139
140 /**
141 * Task scheduled to do the listening.
142 */
143 struct GNUNET_SCHEDULER_Task * listen_task;
144
145 /**
146 * Alternative function to create a MST instance.
147 */
148 GNUNET_SERVER_MstCreateCallback mst_create;
149
150 /**
151 * Alternative function to destroy a MST instance.
152 */
153 GNUNET_SERVER_MstDestroyCallback mst_destroy;
154
155 /**
156 * Alternative function to give data to a MST instance.
157 */
158 GNUNET_SERVER_MstReceiveCallback mst_receive;
159
160 /**
161 * Closure for 'mst_'-callbacks.
162 */
163 void *mst_cls;
164
165 /**
166 * Do we ignore messages of types that we do not understand or do we
167 * require that a handler is found (and if not kill the connection)?
168 */
169 int require_found;
170
171 /**
172 * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
173 * all non-monitor clients to disconnect before we call
174 * #GNUNET_SERVER_destroy. See test_monitor_clients(). Set to
175 * #GNUNET_SYSERR once the final destroy task has been scheduled
176 * (we cannot run it in the same task).
177 */
178 int in_soft_shutdown;
179};
180
181
182/**
183 * Handle server returns for aborting transmission to a client.
184 */
185struct GNUNET_SERVER_TransmitHandle
186{
187 /**
188 * Function to call to get the message.
189 */
190 GNUNET_CONNECTION_TransmitReadyNotify callback;
191
192 /**
193 * Closure for @e callback
194 */
195 void *callback_cls;
196
197 /**
198 * Active connection transmission handle.
199 */
200 struct GNUNET_CONNECTION_TransmitHandle *cth;
201
202};
203
204
205/**
206 * @brief handle for a client of the server
207 */
208struct GNUNET_SERVER_Client
209{
210
211 /**
212 * This is a doubly linked list.
213 */
214 struct GNUNET_SERVER_Client *next;
215
216 /**
217 * This is a doubly linked list.
218 */
219 struct GNUNET_SERVER_Client *prev;
220
221 /**
222 * Processing of incoming data.
223 */
224 void *mst;
225
226 /**
227 * Server that this client belongs to.
228 */
229 struct GNUNET_SERVER_Handle *server;
230
231 /**
232 * Client closure for callbacks.
233 */
234 struct GNUNET_CONNECTION_Handle *connection;
235
236 /**
237 * User context value, manipulated using
238 * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
239 */
240 void *user_context;
241
242 /**
243 * ID of task used to restart processing.
244 */
245 struct GNUNET_SCHEDULER_Task * restart_task;
246
247 /**
248 * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
249 */
250 struct GNUNET_SCHEDULER_Task * warn_task;
251
252 /**
253 * Time when the warn task was started.
254 */
255 struct GNUNET_TIME_Absolute warn_start;
256
257 /**
258 * Last activity on this socket (used to time it out
259 * if reference_count == 0).
260 */
261 struct GNUNET_TIME_Absolute last_activity;
262
263 /**
264 * Transmission handle we return for this client from
265 * #GNUNET_SERVER_notify_transmit_ready.
266 */
267 struct GNUNET_SERVER_TransmitHandle th;
268
269 /**
270 * After how long should an idle connection time
271 * out (on write).
272 */
273 struct GNUNET_TIME_Relative idle_timeout;
274
275 /**
276 * Number of external entities with a reference to
277 * this client object.
278 */
279 unsigned int reference_count;
280
281 /**
282 * Was processing if incoming messages suspended while
283 * we were still processing data already received?
284 * This is a counter saying how often processing was
285 * suspended (once per handler invoked).
286 */
287 unsigned int suspended;
288
289 /**
290 * Last size given when user context was initialized; used for
291 * sanity check.
292 */
293 size_t user_context_size;
294
295 /**
296 * Are we currently in the "process_client_buffer" function (and
297 * will hence restart the receive job on exit if suspended == 0 once
298 * we are done?). If this is set, then "receive_done" will
299 * essentially only decrement suspended; if this is not set, then
300 * "receive_done" may need to restart the receive process (either
301 * from the side-buffer or via select/recv).
302 */
303 int in_process_client_buffer;
304
305 /**
306 * We're about to close down this client.
307 */
308 int shutdown_now;
309
310 /**
311 * Are we currently trying to receive? (#GNUNET_YES if we are,
312 * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
313 * available in MST).
314 */
315 int receive_pending;
316
317 /**
318 * Persist the file handle for this client no matter what happens,
319 * force the OS to close once the process actually dies. Should only
320 * be used in special cases!
321 */
322 int persist;
323
324 /**
325 * Is this client a 'monitor' client that should not be counted
326 * when deciding on destroying the server during soft shutdown?
327 * (see also #GNUNET_SERVICE_start)
328 */
329 int is_monitor;
330
331 /**
332 * Type of last message processed (for warn_no_receive_done).
333 */
334 uint16_t warn_type;
335};
336
337
338
339/**
340 * Return user context associated with the given client.
341 * Note: you should probably use the macro (call without the underscore).
342 *
343 * @param client client to query
344 * @param size number of bytes in user context struct (for verification only)
345 * @return pointer to user context
346 */
347void *
348GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
349 size_t size)
350{
351 if ((0 == client->user_context_size) &&
352 (NULL == client->user_context))
353 return NULL; /* never set */
354 GNUNET_assert (size == client->user_context_size);
355 return client->user_context;
356}
357
358
359/**
360 * Set user context to be associated with the given client.
361 * Note: you should probably use the macro (call without the underscore).
362 *
363 * @param client client to query
364 * @param ptr pointer to user context
365 * @param size number of bytes in user context struct (for verification only)
366 */
367void
368GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
369 void *ptr,
370 size_t size)
371{
372 if (NULL == ptr)
373 {
374 client->user_context_size = 0;
375 client->user_context = ptr;
376 return;
377 }
378 client->user_context_size = size;
379 client->user_context = ptr;
380}
381
382
383/**
384 * Scheduler says our listen socket is ready. Process it!
385 *
386 * @param cls handle to our server for which we are processing the listen
387 * socket
388 */
389static void
390process_listen_socket (void *cls)
391{
392 struct GNUNET_SERVER_Handle *server = cls;
393 const struct GNUNET_SCHEDULER_TaskContext *tc;
394 struct GNUNET_CONNECTION_Handle *sock;
395 unsigned int i;
396
397 server->listen_task = NULL;
398 tc = GNUNET_SCHEDULER_get_task_context ();
399 for (i = 0; NULL != server->listen_sockets[i]; i++)
400 {
401 if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
402 server->listen_sockets[i]))
403 {
404 sock =
405 GNUNET_CONNECTION_create_from_accept (server->access_cb,
406 server->access_cb_cls,
407 server->listen_sockets[i]);
408 if (NULL != sock)
409 {
410 LOG (GNUNET_ERROR_TYPE_DEBUG,
411 "Server accepted incoming connection.\n");
412 (void) GNUNET_SERVER_connect_socket (server,
413 sock);
414 }
415 }
416 }
417 /* listen for more! */
418 GNUNET_SERVER_resume (server);
419}
420
421
422/**
423 * Create and initialize a listen socket for the server.
424 *
425 * @param server_addr address to listen on
426 * @param socklen length of @a server_addr
427 * @return NULL on error, otherwise the listen socket
428 */
429static struct GNUNET_NETWORK_Handle *
430open_listen_socket (const struct sockaddr *server_addr,
431 socklen_t socklen)
432{
433 struct GNUNET_NETWORK_Handle *sock;
434 uint16_t port;
435 int eno;
436
437 switch (server_addr->sa_family)
438 {
439 case AF_INET:
440 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
441 break;
442 case AF_INET6:
443 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
444 break;
445 case AF_UNIX:
446 port = 0;
447 break;
448 default:
449 GNUNET_break (0);
450 port = 0;
451 break;
452 }
453 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
454 if (NULL == sock)
455 {
456 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
457 errno = 0;
458 return NULL;
459 }
460 /* bind the socket */
461 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
462 {
463 eno = errno;
464 if (EADDRINUSE != errno)
465 {
466 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
467 * fail if we already took the port on IPv6; if both IPv4 and
468 * IPv6 binds fail, then our caller will log using the
469 * errno preserved in 'eno' */
470 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
471 "bind");
472 if (0 != port)
473 LOG (GNUNET_ERROR_TYPE_ERROR,
474 _("`%s' failed for port %d (%s).\n"),
475 "bind",
476 port,
477 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
478 eno = 0;
479 }
480 else
481 {
482 if (0 != port)
483 LOG (GNUNET_ERROR_TYPE_WARNING,
484 _("`%s' failed for port %d (%s): address already in use\n"),
485 "bind", port,
486 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
487 else if (AF_UNIX == server_addr->sa_family)
488 {
489 LOG (GNUNET_ERROR_TYPE_WARNING,
490 _("`%s' failed for `%s': address already in use\n"),
491 "bind",
492 GNUNET_a2s (server_addr, socklen));
493 }
494 }
495 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
496 errno = eno;
497 return NULL;
498 }
499 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
500 {
501 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
502 "listen");
503 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
504 errno = 0;
505 return NULL;
506 }
507 if (0 != port)
508 LOG (GNUNET_ERROR_TYPE_DEBUG,
509 "Server starts to listen on port %u.\n",
510 port);
511 return sock;
512}
513
514
515/**
516 * Create a new server.
517 *
518 * @param access_cb function for access control
519 * @param access_cb_cls closure for @a access_cb
520 * @param lsocks NULL-terminated array of listen sockets
521 * @param idle_timeout after how long should we timeout idle connections?
522 * @param require_found if #GNUNET_YES, connections sending messages of unknown type
523 * will be closed
524 * @return handle for the new server, NULL on error
525 * (typically, "port" already in use)
526 */
527struct GNUNET_SERVER_Handle *
528GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
529 void *access_cb_cls,
530 struct GNUNET_NETWORK_Handle **lsocks,
531 struct GNUNET_TIME_Relative idle_timeout,
532 int require_found)
533{
534 struct GNUNET_SERVER_Handle *server;
535
536 server = GNUNET_new (struct GNUNET_SERVER_Handle);
537 server->idle_timeout = idle_timeout;
538 server->listen_sockets = lsocks;
539 server->access_cb = access_cb;
540 server->access_cb_cls = access_cb_cls;
541 server->require_found = require_found;
542 if (NULL != lsocks)
543 GNUNET_SERVER_resume (server);
544 return server;
545}
546
547
548/**
549 * Create a new server.
550 *
551 * @param access_cb function for access control
552 * @param access_cb_cls closure for @a access_cb
553 * @param server_addr address to listen on (including port), NULL terminated array
554 * @param socklen length of server_addr
555 * @param idle_timeout after how long should we timeout idle connections?
556 * @param require_found if YES, connections sending messages of unknown type
557 * will be closed
558 * @return handle for the new server, NULL on error
559 * (typically, "port" already in use)
560 */
561struct GNUNET_SERVER_Handle *
562GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
563 void *access_cb_cls,
564 struct sockaddr *const *server_addr,
565 const socklen_t * socklen,
566 struct GNUNET_TIME_Relative idle_timeout,
567 int require_found)
568{
569 struct GNUNET_NETWORK_Handle **lsocks;
570 unsigned int i;
571 unsigned int j;
572 unsigned int k;
573 int seen;
574
575 i = 0;
576 while (NULL != server_addr[i])
577 i++;
578 if (i > 0)
579 {
580 lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
581 i = 0;
582 j = 0;
583 while (NULL != server_addr[i])
584 {
585 seen = 0;
586 for (k=0;k<i;k++)
587 if ( (socklen[k] == socklen[i]) &&
588 (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) )
589 {
590 seen = 1;
591 break;
592 }
593 if (0 != seen)
594 {
595 /* duplicate address, skip */
596 i++;
597 continue;
598 }
599 lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
600 if (NULL != lsocks[j])
601 j++;
602 i++;
603 }
604 if (0 == j)
605 {
606 if (0 != errno)
607 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
608 GNUNET_free (lsocks);
609 lsocks = NULL;
610 }
611 }
612 else
613 {
614 lsocks = NULL;
615 }
616 return GNUNET_SERVER_create_with_sockets (access_cb,
617 access_cb_cls,
618 lsocks,
619 idle_timeout,
620 require_found);
621}
622
623
624/**
625 * Set the 'monitor' flag on this client. Clients which have been
626 * marked as 'monitors' won't prevent the server from shutting down
627 * once '#GNUNET_SERVER_stop_listening()' has been invoked. The idea is
628 * that for "normal" clients we likely want to allow them to process
629 * their requests; however, monitor-clients are likely to 'never'
630 * disconnect during shutdown and thus will not be considered when
631 * determining if the server should continue to exist after
632 * #GNUNET_SERVER_destroy() has been called.
633 *
634 * @param client the client to set the 'monitor' flag on
635 */
636void
637GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
638{
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640 "Marking client as monitor!\n");
641 client->is_monitor = GNUNET_YES;
642}
643
644
645/**
646 * Helper function for #test_monitor_clients() to trigger
647 * #GNUNET_SERVER_destroy() after the stack has unwound.
648 *
649 * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
650 */
651static void
652do_destroy (void *cls)
653{
654 struct GNUNET_SERVER_Handle *server = cls;
655
656 GNUNET_SERVER_destroy (server);
657}
658
659
660/**
661 * Check if only 'monitor' clients are left. If so, destroy the
662 * server completely.
663 *
664 * @param server server to test for full shutdown
665 */
666static void
667test_monitor_clients (struct GNUNET_SERVER_Handle *server)
668{
669 struct GNUNET_SERVER_Client *client;
670
671 if (GNUNET_YES != server->in_soft_shutdown)
672 return;
673 for (client = server->clients_head; NULL != client; client = client->next)
674 if (GNUNET_NO == client->is_monitor)
675 return; /* not done yet */
676 server->in_soft_shutdown = GNUNET_SYSERR;
677 (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
678}
679
680
681/**
682 * Suspend accepting connections from the listen socket temporarily.
683 *
684 * @param server server to stop accepting connections.
685 */
686void
687GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
688{
689 if (NULL != server->listen_task)
690 {
691 GNUNET_SCHEDULER_cancel (server->listen_task);
692 server->listen_task = NULL;
693 }
694}
695
696
697/**
698 * Resume accepting connections from the listen socket.
699 *
700 * @param server server to stop accepting connections.
701 */
702void
703GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
704{
705 struct GNUNET_NETWORK_FDSet *r;
706 unsigned int i;
707
708 if (NULL == server->listen_sockets)
709 return;
710 if (NULL == server->listen_sockets[0])
711 return; /* nothing to do, no listen sockets! */
712 if (NULL == server->listen_sockets[1])
713 {
714 /* simplified method: no fd set needed; this is then much simpler
715 and much more efficient */
716 server->listen_task =
717 GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
718 GNUNET_SCHEDULER_PRIORITY_HIGH,
719 server->listen_sockets[0],
720 &process_listen_socket, server);
721 return;
722 }
723 r = GNUNET_NETWORK_fdset_create ();
724 i = 0;
725 while (NULL != server->listen_sockets[i])
726 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
727 server->listen_task =
728 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
729 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
730 &process_listen_socket, server);
731 GNUNET_NETWORK_fdset_destroy (r);
732}
733
734
735/**
736 * Stop the listen socket and get ready to shutdown the server
737 * once only 'monitor' clients are left.
738 *
739 * @param server server to stop listening on
740 */
741void
742GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
743{
744 unsigned int i;
745
746 LOG (GNUNET_ERROR_TYPE_DEBUG,
747 "Server in soft shutdown\n");
748 if (NULL != server->listen_task)
749 {
750 GNUNET_SCHEDULER_cancel (server->listen_task);
751 server->listen_task = NULL;
752 }
753 if (NULL != server->listen_sockets)
754 {
755 i = 0;
756 while (NULL != server->listen_sockets[i])
757 GNUNET_break (GNUNET_OK ==
758 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
759 GNUNET_free (server->listen_sockets);
760 server->listen_sockets = NULL;
761 }
762 if (GNUNET_NO == server->in_soft_shutdown)
763 server->in_soft_shutdown = GNUNET_YES;
764 test_monitor_clients (server);
765}
766
767
768/**
769 * Free resources held by this server.
770 *
771 * @param server server to destroy
772 */
773void
774GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
775{
776 struct HandlerList *hpos;
777 struct NotifyList *npos;
778 unsigned int i;
779
780 LOG (GNUNET_ERROR_TYPE_DEBUG,
781 "Server shutting down.\n");
782 if (NULL != server->listen_task)
783 {
784 GNUNET_SCHEDULER_cancel (server->listen_task);
785 server->listen_task = NULL;
786 }
787 if (NULL != server->listen_sockets)
788 {
789 i = 0;
790 while (NULL != server->listen_sockets[i])
791 GNUNET_break (GNUNET_OK ==
792 GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
793 GNUNET_free (server->listen_sockets);
794 server->listen_sockets = NULL;
795 }
796 while (NULL != server->clients_head)
797 GNUNET_SERVER_client_disconnect (server->clients_head);
798 while (NULL != (hpos = server->handlers))
799 {
800 server->handlers = hpos->next;
801 GNUNET_free (hpos);
802 }
803 while (NULL != (npos = server->disconnect_notify_list_head))
804 {
805 npos->callback (npos->callback_cls,
806 NULL);
807 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
808 server->disconnect_notify_list_tail,
809 npos);
810 GNUNET_free (npos);
811 }
812 while (NULL != (npos = server->connect_notify_list_head))
813 {
814 npos->callback (npos->callback_cls,
815 NULL);
816 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
817 server->connect_notify_list_tail,
818 npos);
819 GNUNET_free (npos);
820 }
821 GNUNET_free (server);
822}
823
824
825/**
826 * Add additional handlers to an existing server.
827 *
828 * @param server the server to add handlers to
829 * @param handlers array of message handlers for
830 * incoming messages; the last entry must
831 * have "NULL" for the "callback"; multiple
832 * entries for the same type are allowed,
833 * they will be called in order of occurence.
834 * These handlers can be removed later;
835 * the handlers array must exist until removed
836 * (or server is destroyed).
837 */
838void
839GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
840 const struct GNUNET_SERVER_MessageHandler *handlers)
841{
842 struct HandlerList *p;
843
844 p = GNUNET_new (struct HandlerList);
845 p->handlers = handlers;
846 p->next = server->handlers;
847 server->handlers = p;
848}
849
850
851/**
852 * Change functions used by the server to tokenize the message stream.
853 * (very rarely used).
854 *
855 * @param server server to modify
856 * @param create new tokenizer initialization function
857 * @param destroy new tokenizer destruction function
858 * @param receive new tokenizer receive function
859 * @param cls closure for @a create, @a receive, @a destroy
860 */
861void
862GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
863 GNUNET_SERVER_MstCreateCallback create,
864 GNUNET_SERVER_MstDestroyCallback destroy,
865 GNUNET_SERVER_MstReceiveCallback receive,
866 void *cls)
867{
868 server->mst_create = create;
869 server->mst_destroy = destroy;
870 server->mst_receive = receive;
871 server->mst_cls = cls;
872}
873
874
875/**
876 * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
877 *
878 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
879 */
880static void
881warn_no_receive_done (void *cls)
882{
883 struct GNUNET_SERVER_Client *client = cls;
884
885 GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
886 client->warn_task =
887 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
888 &warn_no_receive_done, client);
889 LOG (GNUNET_ERROR_TYPE_WARNING,
890 _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
891 (unsigned int) client->warn_type,
892 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
893 GNUNET_YES));
894}
895
896
897/**
898 * Disable the warning the server issues if a message is not acknowledged
899 * in a timely fashion. Use this call if a client is intentionally delayed
900 * for a while. Only applies to the current message.
901 *
902 * @param client client for which to disable the warning
903 */
904void
905GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
906{
907 if (NULL != client->warn_task)
908 {
909 GNUNET_SCHEDULER_cancel (client->warn_task);
910 client->warn_task = NULL;
911 }
912}
913
914
915/**
916 * Inject a message into the server, pretend it came
917 * from the specified client. Delivery of the message
918 * will happen instantly (if a handler is installed;
919 * otherwise the call does nothing).
920 *
921 * @param server the server receiving the message
922 * @param sender the "pretended" sender of the message
923 * can be NULL!
924 * @param message message to transmit
925 * @return #GNUNET_OK if the message was OK and the
926 * connection can stay open
927 * #GNUNET_SYSERR if the connection to the
928 * client should be shut down
929 */
930int
931GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
932 struct GNUNET_SERVER_Client *sender,
933 const struct GNUNET_MessageHeader *message)
934{
935 struct HandlerList *pos;
936 const struct GNUNET_SERVER_MessageHandler *mh;
937 unsigned int i;
938 uint16_t type;
939 uint16_t size;
940 int found;
941
942 type = ntohs (message->type);
943 size = ntohs (message->size);
944 LOG (GNUNET_ERROR_TYPE_INFO,
945 "Received message of type %u and size %u from client\n",
946 type, size);
947 found = GNUNET_NO;
948 for (pos = server->handlers; NULL != pos; pos = pos->next)
949 {
950 i = 0;
951 while (pos->handlers[i].callback != NULL)
952 {
953 mh = &pos->handlers[i];
954 if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
955 {
956 if ((0 != mh->expected_size) && (mh->expected_size != size))
957 {
958#if GNUNET8_NETWORK_IS_DEAD
959 LOG (GNUNET_ERROR_TYPE_WARNING,
960 "Expected %u bytes for message of type %u, got %u\n",
961 mh->expected_size, mh->type, size);
962 GNUNET_break_op (0);
963#else
964 LOG (GNUNET_ERROR_TYPE_DEBUG,
965 "Expected %u bytes for message of type %u, got %u\n",
966 mh->expected_size, mh->type, size);
967#endif
968 return GNUNET_SYSERR;
969 }
970 if (NULL != sender)
971 {
972 if ( (0 == sender->suspended) &&
973 (NULL == sender->warn_task) )
974 {
975 GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
976 sender->warn_start = GNUNET_TIME_absolute_get ();
977 sender->warn_task =
978 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
979 &warn_no_receive_done,
980 sender);
981 sender->warn_type = type;
982 }
983 sender->suspended++;
984 }
985 mh->callback (mh->callback_cls, sender, message);
986 found = GNUNET_YES;
987 }
988 i++;
989 }
990 }
991 if (GNUNET_NO == found)
992 {
993 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
994 "Received message of unknown type %d\n", type);
995 if (GNUNET_YES == server->require_found)
996 return GNUNET_SYSERR;
997 }
998 return GNUNET_OK;
999}
1000
1001
1002/**
1003 * We are receiving an incoming message. Process it.
1004 *
1005 * @param cls our closure (handle for the client)
1006 * @param buf buffer with data received from network
1007 * @param available number of bytes available in buf
1008 * @param addr address of the sender
1009 * @param addrlen length of @a addr
1010 * @param errCode code indicating errors receiving, 0 for success
1011 */
1012static void
1013process_incoming (void *cls,
1014 const void *buf,
1015 size_t available,
1016 const struct sockaddr *addr,
1017 socklen_t addrlen,
1018 int errCode);
1019
1020
1021/**
1022 * Process messages from the client's message tokenizer until either
1023 * the tokenizer is empty (and then schedule receiving more), or
1024 * until some handler is not immediately done (then wait for restart_processing)
1025 * or shutdown.
1026 *
1027 * @param client the client to process, RC must have already been increased
1028 * using #GNUNET_SERVER_client_keep and will be decreased by one in this
1029 * function
1030 * @param ret #GNUNET_NO to start processing from the buffer,
1031 * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
1032 * #GNUNET_SYSERR if we should instantly abort due to error in a previous step
1033 */
1034static void
1035process_mst (struct GNUNET_SERVER_Client *client,
1036 int ret)
1037{
1038 while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
1039 (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
1040 {
1041 if (GNUNET_OK == ret)
1042 {
1043 LOG (GNUNET_ERROR_TYPE_DEBUG,
1044 "Server re-enters receive loop, timeout: %s.\n",
1045 GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
1046 client->receive_pending = GNUNET_YES;
1047 GNUNET_CONNECTION_receive (client->connection,
1048 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1049 client->idle_timeout,
1050 &process_incoming,
1051 client);
1052 break;
1053 }
1054 LOG (GNUNET_ERROR_TYPE_DEBUG,
1055 "Server processes additional messages instantly.\n");
1056 if (NULL != client->server->mst_receive)
1057 ret =
1058 client->server->mst_receive (client->server->mst_cls, client->mst,
1059 client, NULL, 0, GNUNET_NO, GNUNET_YES);
1060 else
1061 ret =
1062 GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
1063 GNUNET_YES);
1064 }
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
1067 ret, client->server,
1068 client->shutdown_now,
1069 client->suspended);
1070 if (GNUNET_NO == ret)
1071 {
1072 LOG (GNUNET_ERROR_TYPE_DEBUG,
1073 "Server has more data pending but is suspended.\n");
1074 client->receive_pending = GNUNET_SYSERR; /* data pending */
1075 }
1076 if ( (GNUNET_SYSERR == ret) ||
1077 (GNUNET_YES == client->shutdown_now) )
1078 GNUNET_SERVER_client_disconnect (client);
1079}
1080
1081
1082/**
1083 * We are receiving an incoming message. Process it.
1084 *
1085 * @param cls our closure (handle for the client)
1086 * @param buf buffer with data received from network
1087 * @param available number of bytes available in buf
1088 * @param addr address of the sender
1089 * @param addrlen length of @a addr
1090 * @param errCode code indicating errors receiving, 0 for success
1091 */
1092static void
1093process_incoming (void *cls,
1094 const void *buf,
1095 size_t available,
1096 const struct sockaddr *addr,
1097 socklen_t addrlen,
1098 int errCode)
1099{
1100 struct GNUNET_SERVER_Client *client = cls;
1101 struct GNUNET_SERVER_Handle *server = client->server;
1102 struct GNUNET_TIME_Absolute end;
1103 struct GNUNET_TIME_Absolute now;
1104 int ret;
1105
1106 GNUNET_assert (GNUNET_YES == client->receive_pending);
1107 client->receive_pending = GNUNET_NO;
1108 now = GNUNET_TIME_absolute_get ();
1109 end = GNUNET_TIME_absolute_add (client->last_activity,
1110 client->idle_timeout);
1111
1112 if ( (NULL == buf) &&
1113 (0 == available) &&
1114 (NULL == addr) &&
1115 (0 == errCode) &&
1116 (GNUNET_YES != client->shutdown_now) &&
1117 (NULL != server) &&
1118 (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
1119 (end.abs_value_us > now.abs_value_us) )
1120 {
1121 /* wait longer, timeout changed (i.e. due to us sending) */
1122 LOG (GNUNET_ERROR_TYPE_DEBUG,
1123 "Receive time out, but no disconnect due to sending (%p)\n",
1124 client);
1125 client->receive_pending = GNUNET_YES;
1126 GNUNET_CONNECTION_receive (client->connection,
1127 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1128 GNUNET_TIME_absolute_get_remaining (end),
1129 &process_incoming,
1130 client);
1131 return;
1132 }
1133 if ( (NULL == buf) ||
1134 (0 == available) ||
1135 (0 != errCode) ||
1136 (NULL == server) ||
1137 (GNUNET_YES == client->shutdown_now) ||
1138 (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) )
1139 {
1140 /* other side closed connection, error connecting, etc. */
1141 LOG (GNUNET_ERROR_TYPE_DEBUG,
1142 "Failed to connect or other side closed connection (%p)\n",
1143 client);
1144 GNUNET_SERVER_client_disconnect (client);
1145 return;
1146 }
1147 LOG (GNUNET_ERROR_TYPE_DEBUG,
1148 "Server receives %u bytes from `%s'.\n",
1149 (unsigned int) available,
1150 GNUNET_a2s (addr, addrlen));
1151 GNUNET_SERVER_client_keep (client);
1152 client->last_activity = now;
1153
1154 if (NULL != server->mst_receive)
1155 {
1156 ret = client->server->mst_receive (client->server->mst_cls,
1157 client->mst,
1158 client,
1159 buf,
1160 available,
1161 GNUNET_NO,
1162 GNUNET_YES);
1163 }
1164 else if (NULL != client->mst)
1165 {
1166 ret =
1167 GNUNET_SERVER_mst_receive (client->mst,
1168 client,
1169 buf,
1170 available,
1171 GNUNET_NO,
1172 GNUNET_YES);
1173 }
1174 else
1175 {
1176 GNUNET_break (0);
1177 return;
1178 }
1179 process_mst (client,
1180 ret);
1181 GNUNET_SERVER_client_drop (client);
1182}
1183
1184
1185/**
1186 * Task run to start again receiving from the network
1187 * and process requests.
1188 *
1189 * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
1190 */
1191static void
1192restart_processing (void *cls)
1193{
1194 struct GNUNET_SERVER_Client *client = cls;
1195
1196 GNUNET_assert (GNUNET_YES != client->shutdown_now);
1197 client->restart_task = NULL;
1198 if (GNUNET_NO == client->receive_pending)
1199 {
1200 LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
1201 client->receive_pending = GNUNET_YES;
1202 GNUNET_CONNECTION_receive (client->connection,
1203 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1204 client->idle_timeout,
1205 &process_incoming,
1206 client);
1207 return;
1208 }
1209 LOG (GNUNET_ERROR_TYPE_DEBUG,
1210 "Server continues processing messages still in the buffer.\n");
1211 GNUNET_SERVER_client_keep (client);
1212 client->receive_pending = GNUNET_NO;
1213 process_mst (client,
1214 GNUNET_NO);
1215 GNUNET_SERVER_client_drop (client);
1216}
1217
1218
1219/**
1220 * This function is called whenever our inbound message tokenizer has
1221 * received a complete message.
1222 *
1223 * @param cls closure (struct GNUNET_SERVER_Handle)
1224 * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
1225 * @param message the actual message
1226 *
1227 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
1228 */
1229static int
1230client_message_tokenizer_callback (void *cls,
1231 void *client,
1232 const struct GNUNET_MessageHeader *message)
1233{
1234 struct GNUNET_SERVER_Handle *server = cls;
1235 struct GNUNET_SERVER_Client *sender = client;
1236 int ret;
1237
1238 LOG (GNUNET_ERROR_TYPE_DEBUG,
1239 "Tokenizer gives server message of type %u and size %u from client\n",
1240 ntohs (message->type), ntohs (message->size));
1241 sender->in_process_client_buffer = GNUNET_YES;
1242 ret = GNUNET_SERVER_inject (server, sender, message);
1243 sender->in_process_client_buffer = GNUNET_NO;
1244 if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) )
1245 {
1246 GNUNET_SERVER_client_disconnect (sender);
1247 return GNUNET_SYSERR;
1248 }
1249 return GNUNET_OK;
1250}
1251
1252
1253/**
1254 * Add a TCP socket-based connection to the set of handles managed by
1255 * this server. Use this function for outgoing (P2P) connections that
1256 * we initiated (and where this server should process incoming
1257 * messages).
1258 *
1259 * @param server the server to use
1260 * @param connection the connection to manage (client must
1261 * stop using this connection from now on)
1262 * @return the client handle
1263 */
1264struct GNUNET_SERVER_Client *
1265GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
1266 struct GNUNET_CONNECTION_Handle *connection)
1267{
1268 struct GNUNET_SERVER_Client *client;
1269 struct NotifyList *n;
1270
1271 client = GNUNET_new (struct GNUNET_SERVER_Client);
1272 client->connection = connection;
1273 client->server = server;
1274 client->last_activity = GNUNET_TIME_absolute_get ();
1275 client->idle_timeout = server->idle_timeout;
1276 GNUNET_CONTAINER_DLL_insert (server->clients_head,
1277 server->clients_tail,
1278 client);
1279 if (NULL != server->mst_create)
1280 client->mst =
1281 server->mst_create (server->mst_cls, client);
1282 else
1283 client->mst =
1284 GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
1285 server);
1286 GNUNET_assert (NULL != client->mst);
1287 for (n = server->connect_notify_list_head; NULL != n; n = n->next)
1288 n->callback (n->callback_cls, client);
1289 client->receive_pending = GNUNET_YES;
1290 GNUNET_CONNECTION_receive (client->connection,
1291 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
1292 client->idle_timeout,
1293 &process_incoming,
1294 client);
1295 return client;
1296}
1297
1298
1299/**
1300 * Change the timeout for a particular client. Decreasing the timeout
1301 * may not go into effect immediately (only after the previous timeout
1302 * times out or activity happens on the socket).
1303 *
1304 * @param client the client to update
1305 * @param timeout new timeout for activities on the socket
1306 */
1307void
1308GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
1309 struct GNUNET_TIME_Relative timeout)
1310{
1311 client->idle_timeout = timeout;
1312}
1313
1314
1315/**
1316 * Notify the server that the given client handle should
1317 * be kept (keeps the connection up if possible, increments
1318 * the internal reference counter).
1319 *
1320 * @param client the client to keep
1321 */
1322void
1323GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1324{
1325 client->reference_count++;
1326}
1327
1328
1329/**
1330 * Notify the server that the given client handle is no
1331 * longer required. Decrements the reference counter. If
1332 * that counter reaches zero an inactive connection maybe
1333 * closed.
1334 *
1335 * @param client the client to drop
1336 */
1337void
1338GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1339{
1340 GNUNET_assert (client->reference_count > 0);
1341 client->reference_count--;
1342 if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
1343 GNUNET_SERVER_client_disconnect (client);
1344}
1345
1346
1347/**
1348 * Obtain the network address of the other party.
1349 *
1350 * @param client the client to get the address for
1351 * @param addr where to store the address
1352 * @param addrlen where to store the length of the @a addr
1353 * @return #GNUNET_OK on success
1354 */
1355int
1356GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1357 void **addr, size_t * addrlen)
1358{
1359 return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
1360}
1361
1362
1363/**
1364 * Ask the server to notify us whenever a client disconnects.
1365 * This function is called whenever the actual network connection
1366 * is closed; the reference count may be zero or larger than zero
1367 * at this point.
1368 *
1369 * @param server the server manageing the clients
1370 * @param callback function to call on disconnect
1371 * @param callback_cls closure for @a callback
1372 */
1373void
1374GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1375 GNUNET_SERVER_DisconnectCallback callback,
1376 void *callback_cls)
1377{
1378 struct NotifyList *n;
1379
1380 n = GNUNET_new (struct NotifyList);
1381 n->callback = callback;
1382 n->callback_cls = callback_cls;
1383 GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
1384 server->disconnect_notify_list_tail,
1385 n);
1386}
1387
1388
1389/**
1390 * Ask the server to notify us whenever a client connects.
1391 * This function is called whenever the actual network connection
1392 * is opened. If the server is destroyed before this
1393 * notification is explicitly cancelled, the 'callback' will
1394 * once be called with a 'client' argument of NULL to indicate
1395 * that the server itself is now gone (and that the callback
1396 * won't be called anymore and also can no longer be cancelled).
1397 *
1398 * @param server the server manageing the clients
1399 * @param callback function to call on sconnect
1400 * @param callback_cls closure for @a callback
1401 */
1402void
1403GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
1404 GNUNET_SERVER_ConnectCallback callback,
1405 void *callback_cls)
1406{
1407 struct NotifyList *n;
1408 struct GNUNET_SERVER_Client *client;
1409
1410 n = GNUNET_new (struct NotifyList);
1411 n->callback = callback;
1412 n->callback_cls = callback_cls;
1413 GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
1414 server->connect_notify_list_tail,
1415 n);
1416 for (client = server->clients_head; NULL != client; client = client->next)
1417 callback (callback_cls, client);
1418}
1419
1420
1421/**
1422 * Ask the server to stop notifying us whenever a client connects.
1423 *
1424 * @param server the server manageing the clients
1425 * @param callback function to call on connect
1426 * @param callback_cls closure for @a callback
1427 */
1428void
1429GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1430 GNUNET_SERVER_DisconnectCallback callback,
1431 void *callback_cls)
1432{
1433 struct NotifyList *pos;
1434
1435 for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
1436 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1437 break;
1438 if (NULL == pos)
1439 {
1440 GNUNET_break (0);
1441 return;
1442 }
1443 GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
1444 server->disconnect_notify_list_tail,
1445 pos);
1446 GNUNET_free (pos);
1447}
1448
1449
1450/**
1451 * Ask the server to stop notifying us whenever a client disconnects.
1452 *
1453 * @param server the server manageing the clients
1454 * @param callback function to call on disconnect
1455 * @param callback_cls closure for @a callback
1456 */
1457void
1458GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1459 GNUNET_SERVER_ConnectCallback callback,
1460 void *callback_cls)
1461{
1462 struct NotifyList *pos;
1463
1464 for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
1465 if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
1466 break;
1467 if (NULL == pos)
1468 {
1469 GNUNET_break (0);
1470 return;
1471 }
1472 GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
1473 server->connect_notify_list_tail,
1474 pos);
1475 GNUNET_free (pos);
1476}
1477
1478
1479/**
1480 * Destroy the connection that is passed in via @a cls. Used
1481 * as calling #GNUNET_CONNECTION_destroy from within a function
1482 * that was itself called from within process_notify() of
1483 * 'connection.c' is not allowed (see #2329).
1484 *
1485 * @param cls connection to destroy
1486 */
1487static void
1488destroy_connection (void *cls)
1489{
1490 struct GNUNET_CONNECTION_Handle *connection = cls;
1491
1492 GNUNET_CONNECTION_destroy (connection);
1493}
1494
1495
1496/**
1497 * Ask the server to disconnect from the given client.
1498 * This is the same as returning #GNUNET_SYSERR from a message
1499 * handler, except that it allows dropping of a client even
1500 * when not handling a message from that client.
1501 *
1502 * @param client the client to disconnect from
1503 */
1504void
1505GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1506{
1507 struct GNUNET_SERVER_Handle *server = client->server;
1508 struct NotifyList *n;
1509
1510 LOG (GNUNET_ERROR_TYPE_DEBUG,
1511 "Client is being disconnected from the server.\n");
1512 if (NULL != client->restart_task)
1513 {
1514 GNUNET_SCHEDULER_cancel (client->restart_task);
1515 client->restart_task = NULL;
1516 }
1517 if (NULL != client->warn_task)
1518 {
1519 GNUNET_SCHEDULER_cancel (client->warn_task);
1520 client->warn_task = NULL;
1521 }
1522 if (GNUNET_YES == client->receive_pending)
1523 {
1524 GNUNET_CONNECTION_receive_cancel (client->connection);
1525 client->receive_pending = GNUNET_NO;
1526 }
1527 client->shutdown_now = GNUNET_YES;
1528 client->reference_count++; /* make sure nobody else clean up client... */
1529 if ( (NULL != client->mst) &&
1530 (NULL != server) )
1531 {
1532 GNUNET_CONTAINER_DLL_remove (server->clients_head,
1533 server->clients_tail,
1534 client);
1535 if (NULL != server->mst_destroy)
1536 server->mst_destroy (server->mst_cls,
1537 client->mst);
1538 else
1539 GNUNET_SERVER_mst_destroy (client->mst);
1540 client->mst = NULL;
1541 for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
1542 n->callback (n->callback_cls,
1543 client);
1544 }
1545 client->reference_count--;
1546 if (client->reference_count > 0)
1547 {
1548 LOG (GNUNET_ERROR_TYPE_DEBUG,
1549 "RC of %p still positive, not destroying everything.\n",
1550 client);
1551 client->server = NULL;
1552 return;
1553 }
1554 if (GNUNET_YES == client->in_process_client_buffer)
1555 {
1556 LOG (GNUNET_ERROR_TYPE_DEBUG,
1557 "Still processing inputs of %p, not destroying everything.\n",
1558 client);
1559 return;
1560 }
1561 LOG (GNUNET_ERROR_TYPE_DEBUG,
1562 "RC of %p now zero, destroying everything.\n",
1563 client);
1564 if (GNUNET_YES == client->persist)
1565 GNUNET_CONNECTION_persist_ (client->connection);
1566 if (NULL != client->th.cth)
1567 GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
1568 (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
1569 client->connection);
1570 /* need to cancel again, as it might have been re-added
1571 in the meantime (i.e. during callbacks) */
1572 if (NULL != client->warn_task)
1573 {
1574 GNUNET_SCHEDULER_cancel (client->warn_task);
1575 client->warn_task = NULL;
1576 }
1577 if (GNUNET_YES == client->receive_pending)
1578 {
1579 GNUNET_CONNECTION_receive_cancel (client->connection);
1580 client->receive_pending = GNUNET_NO;
1581 }
1582 GNUNET_free (client);
1583 /* we might be in soft-shutdown, test if we're done */
1584 if (NULL != server)
1585 test_monitor_clients (server);
1586}
1587
1588
1589/**
1590 * Disable the "CORK" feature for communication with the given client,
1591 * forcing the OS to immediately flush the buffer on transmission
1592 * instead of potentially buffering multiple messages.
1593 *
1594 * @param client handle to the client
1595 * @return #GNUNET_OK on success
1596 */
1597int
1598GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
1599{
1600 return GNUNET_CONNECTION_disable_corking (client->connection);
1601}
1602
1603
1604/**
1605 * Wrapper for transmission notification that calls the original
1606 * callback and update the last activity time for our connection.
1607 *
1608 * @param cls the `struct GNUNET_SERVER_Client *`
1609 * @param size number of bytes we can transmit
1610 * @param buf where to copy the message
1611 * @return number of bytes actually transmitted
1612 */
1613static size_t
1614transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
1615{
1616 struct GNUNET_SERVER_Client *client = cls;
1617 GNUNET_CONNECTION_TransmitReadyNotify callback;
1618
1619 client->th.cth = NULL;
1620 callback = client->th.callback;
1621 client->th.callback = NULL;
1622 client->last_activity = GNUNET_TIME_absolute_get ();
1623 return callback (client->th.callback_cls, size, buf);
1624}
1625
1626
1627/**
1628 * Notify us when the server has enough space to transmit
1629 * a message of the given size to the given client.
1630 *
1631 * @param client client to transmit message to
1632 * @param size requested amount of buffer space
1633 * @param timeout after how long should we give up (and call
1634 * notify with buf NULL and size 0)?
1635 * @param callback function to call when space is available
1636 * @param callback_cls closure for @a callback
1637 * @return non-NULL if the notify callback was queued; can be used
1638 * to cancel the request using
1639 * #GNUNET_SERVER_notify_transmit_ready_cancel().
1640 * NULL if we are already going to notify someone else (busy)
1641 */
1642struct GNUNET_SERVER_TransmitHandle *
1643GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1644 size_t size,
1645 struct GNUNET_TIME_Relative timeout,
1646 GNUNET_CONNECTION_TransmitReadyNotify callback,
1647 void *callback_cls)
1648{
1649 if (NULL != client->th.callback)
1650 return NULL;
1651 client->th.callback_cls = callback_cls;
1652 client->th.callback = callback;
1653 client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
1654 timeout,
1655 &transmit_ready_callback_wrapper,
1656 client);
1657 return &client->th;
1658}
1659
1660
1661/**
1662 * Abort transmission request.
1663 *
1664 * @param th request to abort
1665 */
1666void
1667GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
1668{
1669 GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
1670 th->cth = NULL;
1671 th->callback = NULL;
1672}
1673
1674
1675/**
1676 * Set the persistent flag on this client, used to setup client connection
1677 * to only be killed when the service it's connected to is actually dead.
1678 *
1679 * @param client the client to set the persistent flag on
1680 */
1681void
1682GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1683{
1684 client->persist = GNUNET_YES;
1685}
1686
1687
1688/**
1689 * Resume receiving from this client, we are done processing the
1690 * current request. This function must be called from within each
1691 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1692 *
1693 * @param client client we were processing a message of
1694 * @param success #GNUNET_OK to keep the connection open and
1695 * continue to receive
1696 * #GNUNET_NO to close the connection (normal behavior)
1697 * #GNUNET_SYSERR to close the connection (signal
1698 * serious error)
1699 */
1700void
1701GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
1702 int success)
1703{
1704 if (NULL == client)
1705 return;
1706 GNUNET_assert (client->suspended > 0);
1707 client->suspended--;
1708 if (GNUNET_OK != success)
1709 {
1710 LOG (GNUNET_ERROR_TYPE_DEBUG,
1711 "GNUNET_SERVER_receive_done called with failure indication\n");
1712 if ( (client->reference_count > 0) || (client->suspended > 0) )
1713 client->shutdown_now = GNUNET_YES;
1714 else
1715 GNUNET_SERVER_client_disconnect (client);
1716 return;
1717 }
1718 if (client->suspended > 0)
1719 {
1720 LOG (GNUNET_ERROR_TYPE_DEBUG,
1721 "GNUNET_SERVER_receive_done called, but more clients pending\n");
1722 return;
1723 }
1724 if (NULL != client->warn_task)
1725 {
1726 GNUNET_SCHEDULER_cancel (client->warn_task);
1727 client->warn_task = NULL;
1728 }
1729 if (GNUNET_YES == client->in_process_client_buffer)
1730 {
1731 LOG (GNUNET_ERROR_TYPE_DEBUG,
1732 "GNUNET_SERVER_receive_done called while still in processing loop\n");
1733 return;
1734 }
1735 if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
1736 {
1737 GNUNET_SERVER_client_disconnect (client);
1738 return;
1739 }
1740 LOG (GNUNET_ERROR_TYPE_DEBUG,
1741 "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
1742 GNUNET_assert (NULL == client->restart_task);
1743 client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
1744 client);
1745}
1746
1747
1748/* end of server.c */