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