2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
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.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @brief library for building GNUnet network servers
24 * @author Christian Grothoff
27 * - fix inefficient memmove in message processing
31 #include "gnunet_common.h"
32 #include "gnunet_connection_lib.h"
33 #include "gnunet_scheduler_lib.h"
34 #include "gnunet_server_lib.h"
35 #include "gnunet_time_lib.h"
36 #include "gnunet_disk_lib.h"
38 #define DEBUG_SERVER GNUNET_NO
41 * List of arrays of message handlers.
46 * This is a linked list.
48 struct HandlerList *next;
51 * NULL-terminated array of handlers.
53 const struct GNUNET_SERVER_MessageHandler *handlers;
58 * List of arrays of message handlers.
63 * This is a linked list.
65 struct NotifyList *next;
70 GNUNET_SERVER_DisconnectCallback callback;
73 * Closure for callback.
80 * @brief handle for a server
82 struct GNUNET_SERVER_Handle
87 struct GNUNET_SCHEDULER_Handle *sched;
90 * List of handlers for incoming messages.
92 struct HandlerList *handlers;
95 * List of our current clients.
97 struct GNUNET_SERVER_Client *clients;
100 * Linked list of functions to call on disconnects by clients.
102 struct NotifyList *disconnect_notify_list;
105 * Function to call for access control.
107 GNUNET_CONNECTION_AccessCheck access;
110 * Closure for access.
115 * After how long should an idle connection time
118 struct GNUNET_TIME_Relative idle_timeout;
121 * maximum write buffer size for accepted sockets
126 * Socket used to listen for new connections. Set to
127 * "-1" by GNUNET_SERVER_destroy to initiate shutdown.
129 struct GNUNET_NETWORK_Handle *listen_socket;
132 * Task scheduled to do the listening.
134 GNUNET_SCHEDULER_TaskIdentifier listen_task;
137 * Do we ignore messages of types that we do not
138 * understand or do we require that a handler
139 * is found (and if not kill the connection)?
147 * @brief handle for a client of the server
149 struct GNUNET_SERVER_Client
153 * Size of the buffer for incoming data. Should be
154 * first so we get nice alignment.
156 char incoming_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
159 * This is a linked list.
161 struct GNUNET_SERVER_Client *next;
164 * Server that this client belongs to.
166 struct GNUNET_SERVER_Handle *server;
169 * Client closure for callbacks.
171 void *client_closure;
174 * Callback to receive from client.
176 GNUNET_SERVER_ReceiveCallback receive;
179 * Callback to cancel receive from client.
181 GNUNET_SERVER_ReceiveCancelCallback receive_cancel;
184 * Callback to ask about transmit-ready notification.
186 GNUNET_SERVER_TransmitReadyCallback notify_transmit_ready;
189 * Callback to ask about transmit-ready notification.
191 GNUNET_SERVER_TransmitReadyCancelCallback notify_transmit_ready_cancel;
194 * Callback to check if client is still valid.
196 GNUNET_SERVER_CheckCallback check;
199 * Callback to destroy client.
201 GNUNET_SERVER_DestroyCallback destroy;
204 * Side-buffer for incoming data used when processing
210 * Number of bytes in the side buffer.
212 size_t side_buf_size;
215 * Last activity on this socket (used to time it out
216 * if reference_count == 0).
218 struct GNUNET_TIME_Absolute last_activity;
221 * How many bytes in the "incoming_buffer" are currently
222 * valid? (starting at offset 0).
227 * Number of external entities with a reference to
228 * this client object.
230 unsigned int reference_count;
233 * Was processing if incoming messages suspended while
234 * we were still processing data already received?
235 * This is a counter saying how often processing was
236 * suspended (once per handler invoked).
238 unsigned int suspended;
241 * Are we currently in the "process_client_buffer" function (and
242 * will hence restart the receive job on exit if suspended == 0 once
243 * we are done?). If this is set, then "receive_done" will
244 * essentially only decrement suspended; if this is not set, then
245 * "receive_done" may need to restart the receive process (either
246 * from the side-buffer or via select/recv).
248 int in_process_client_buffer;
251 * We're about to close down this client due to some serious
260 * Scheduler says our listen socket is ready.
264 process_listen_socket (void *cls,
265 const struct GNUNET_SCHEDULER_TaskContext *tc)
267 struct GNUNET_SERVER_Handle *server = cls;
268 struct GNUNET_CONNECTION_Handle *sock;
269 struct GNUNET_SERVER_Client *client;
270 struct GNUNET_NETWORK_FDSet *r;
272 server->listen_task = GNUNET_SCHEDULER_NO_TASK;
273 r = GNUNET_NETWORK_fdset_create ();
274 GNUNET_NETWORK_fdset_set (r, server->listen_socket);
275 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
277 server->listen_task = GNUNET_SCHEDULER_add_select (server->sched,
278 GNUNET_SCHEDULER_PRIORITY_HIGH,
279 GNUNET_SCHEDULER_NO_TASK,
280 GNUNET_TIME_UNIT_FOREVER_REL,
282 &process_listen_socket,
284 GNUNET_NETWORK_fdset_destroy (r);
285 return; /* ignore shutdown, someone else will take care of it! */
287 GNUNET_assert (GNUNET_NETWORK_fdset_isset
288 (tc->read_ready, server->listen_socket));
290 GNUNET_CONNECTION_create_from_accept (tc->sched, server->access,
292 server->listen_socket,
297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298 "Server accepted incoming connection.\n");
300 client = GNUNET_SERVER_connect_socket (server, sock);
301 /* decrement reference count, we don't keep "client" alive */
302 GNUNET_SERVER_client_drop (client);
304 /* listen for more! */
305 server->listen_task = GNUNET_SCHEDULER_add_select (server->sched,
306 GNUNET_SCHEDULER_PRIORITY_HIGH,
307 GNUNET_SCHEDULER_NO_TASK,
308 GNUNET_TIME_UNIT_FOREVER_REL,
310 &process_listen_socket,
312 GNUNET_NETWORK_fdset_destroy (r);
317 * Create and initialize a listen socket for the server.
319 * @return NULL on error, otherwise the listen socket
321 static struct GNUNET_NETWORK_Handle *
322 open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
324 const static int on = 1;
325 struct GNUNET_NETWORK_Handle *sock;
328 switch (serverAddr->sa_family)
331 port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port);
334 port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port);
340 sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0);
343 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
346 if (GNUNET_NETWORK_socket_setsockopt
347 (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
348 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
350 /* bind the socket */
351 if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK)
353 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
354 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
356 ("`%s' failed for port %d. Is the service already running?\n"),
358 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
361 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
363 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
364 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369 "Server starts to listen on port %u.\n", port);
376 * Create a new server.
378 * @param sched scheduler to use
379 * @param access function for access control
380 * @param access_cls closure for access
381 * @param serverAddr address to listen on (including port), use NULL
382 * for internal server (no listening)
383 * @param socklen length of serverAddr
384 * @param maxbuf maximum write buffer size for accepted sockets
385 * @param idle_timeout after how long should we timeout idle connections?
386 * @param require_found if YES, connections sending messages of unknown type
388 * @return handle for the new server, NULL on error
389 * (typically, "port" already in use)
391 struct GNUNET_SERVER_Handle *
392 GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched,
393 GNUNET_CONNECTION_AccessCheck access,
395 const struct sockaddr *serverAddr,
398 struct GNUNET_TIME_Relative
399 idle_timeout, int require_found)
401 struct GNUNET_SERVER_Handle *ret;
402 struct GNUNET_NETWORK_Handle *lsock;
403 struct GNUNET_NETWORK_FDSet *r;
406 if (serverAddr != NULL)
408 lsock = open_listen_socket (serverAddr, socklen);
412 ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle));
414 ret->maxbuf = maxbuf;
415 ret->idle_timeout = idle_timeout;
416 ret->listen_socket = lsock;
417 ret->access = access;
418 ret->access_cls = access_cls;
419 ret->require_found = require_found;
422 r = GNUNET_NETWORK_fdset_create ();
423 GNUNET_NETWORK_fdset_set (r, ret->listen_socket);
424 ret->listen_task = GNUNET_SCHEDULER_add_select (sched,
425 GNUNET_SCHEDULER_PRIORITY_HIGH,
426 GNUNET_SCHEDULER_NO_TASK,
427 GNUNET_TIME_UNIT_FOREVER_REL,
429 &process_listen_socket,
431 GNUNET_NETWORK_fdset_destroy (r);
438 * Free resources held by this server.
441 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s)
443 struct GNUNET_SERVER_Client *pos;
444 struct HandlerList *hpos;
445 struct NotifyList *npos;
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n");
450 if (GNUNET_SCHEDULER_NO_TASK != s->listen_task)
452 GNUNET_SCHEDULER_cancel (s->sched, s->listen_task);
453 s->listen_task = GNUNET_SCHEDULER_NO_TASK;
455 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s->listen_socket));
456 s->listen_socket = NULL;
457 while (s->clients != NULL)
460 s->clients = pos->next;
463 while (NULL != (hpos = s->handlers))
465 s->handlers = hpos->next;
468 while (NULL != (npos = s->disconnect_notify_list))
470 s->disconnect_notify_list = npos->next;
478 * Add additional handlers to an existing server.
480 * @param server the server to add handlers to
481 * @param handlers array of message handlers for
482 * incoming messages; the last entry must
483 * have "NULL" for the "callback"; multiple
484 * entries for the same type are allowed,
485 * they will be called in order of occurence.
486 * These handlers can be removed later;
487 * the handlers array must exist until removed
488 * (or server is destroyed).
491 GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
492 const struct GNUNET_SERVER_MessageHandler
495 struct HandlerList *p;
497 p = GNUNET_malloc (sizeof (struct HandlerList));
498 p->handlers = handlers;
499 p->next = server->handlers;
500 server->handlers = p;
505 * Inject a message into the server, pretend it came
506 * from the specified client. Delivery of the message
507 * will happen instantly (if a handler is installed;
508 * otherwise the call does nothing).
510 * @param server the server receiving the message
511 * @param sender the "pretended" sender of the message
513 * @param message message to transmit
514 * @return GNUNET_OK if the message was OK and the
515 * connection can stay open
516 * GNUNET_SYSERR if the connection to the
517 * client should be shut down
520 GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
521 struct GNUNET_SERVER_Client *sender,
522 const struct GNUNET_MessageHeader *message)
524 struct HandlerList *pos;
525 const struct GNUNET_SERVER_MessageHandler *mh;
531 type = ntohs (message->type);
532 size = ntohs (message->size);
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535 "Server schedules transmission of %u-byte message of type %u to client.\n",
538 pos = server->handlers;
543 while (pos->handlers[i].callback != NULL)
545 mh = &pos->handlers[i];
546 if (mh->type == type)
548 if ((mh->expected_size != 0) && (mh->expected_size != size))
551 return GNUNET_SYSERR;
555 mh->callback (mh->callback_cls, sender, message);
562 if (found == GNUNET_NO)
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
565 _("Received message of unknown type %d\n"), type);
566 if (server->require_found == GNUNET_YES)
567 return GNUNET_SYSERR;
574 * We're finished with this client and especially its input
575 * processing. If the RC is zero, free all resources otherwise wait
576 * until RC hits zero to do so.
579 shutdown_incoming_processing (struct GNUNET_SERVER_Client *client)
581 struct GNUNET_SERVER_Client *prev;
582 struct GNUNET_SERVER_Client *pos;
583 struct GNUNET_SERVER_Handle *server;
584 struct NotifyList *n;
587 rc = client->reference_count;
588 if (client->server != NULL)
590 server = client->server;
591 client->server = NULL;
593 pos = server->clients;
594 while ((pos != NULL) && (pos != client))
599 GNUNET_assert (pos != NULL);
601 server->clients = pos->next;
603 prev->next = pos->next;
604 n = server->disconnect_notify_list;
607 n->callback (n->callback_cls, client);
611 /* wait for RC to hit zero, then free */
614 client->destroy (client->client_closure);
615 GNUNET_free (client);
620 * Go over the contents of the client buffer; as long as full messages
621 * are available, pass them on for processing. Update the buffer
622 * accordingly. Handles fatal errors by shutting down the connection.
624 * @param client identifies which client receive buffer to process
627 process_client_buffer (struct GNUNET_SERVER_Client *client)
629 struct GNUNET_SERVER_Handle *server;
630 const struct GNUNET_MessageHeader *hdr;
633 client->in_process_client_buffer = GNUNET_YES;
634 server = client->server;
636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
637 "Private buffer contains %u bytes; client is %s and we are %s\n",
639 client->suspended ? "suspended" : "up",
640 client->shutdown_now ? "in shutdown" : "running");
642 while ((client->receive_pos >= sizeof (struct GNUNET_MessageHeader)) &&
643 (0 == client->suspended) && (GNUNET_YES != client->shutdown_now))
645 hdr = (const struct GNUNET_MessageHeader *) &client->incoming_buffer;
646 msize = ntohs (hdr->size);
647 if (msize > client->receive_pos)
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651 "Total message size is %u, we only have %u bytes; need more data\n",
652 msize, client->receive_pos);
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Passing %u bytes to callback for processing\n", msize);
660 if ((msize < sizeof (struct GNUNET_MessageHeader)) ||
661 (GNUNET_OK != GNUNET_SERVER_inject (server, client, hdr)))
663 client->in_process_client_buffer = GNUNET_NO;
664 shutdown_incoming_processing (client);
667 /* FIXME: this is highly inefficient; we should
668 try to avoid this if the new base address is
669 already nicely aligned. See old handler code... */
670 memmove (client->incoming_buffer,
671 &client->incoming_buffer[msize], client->receive_pos - msize);
672 client->receive_pos -= msize;
674 client->in_process_client_buffer = GNUNET_NO;
675 if (GNUNET_YES == client->shutdown_now)
676 shutdown_incoming_processing (client);
681 * We are receiving an incoming message. Process it.
683 * @param cls our closure (handle for the client)
684 * @param buf buffer with data received from network
685 * @param available number of bytes available in buf
686 * @param addr address of the sender
687 * @param addrlen length of addr
688 * @param errCode code indicating errors receiving, 0 for success
691 process_incoming (void *cls,
694 const struct sockaddr *addr, socklen_t addrlen, int errCode)
696 struct GNUNET_SERVER_Client *client = cls;
697 struct GNUNET_SERVER_Handle *server = client->server;
698 const char *cbuf = buf;
705 (client->shutdown_now == GNUNET_YES) ||
706 (GNUNET_YES != client->check (client->client_closure)))
708 /* other side closed connection, error connecting, etc. */
709 shutdown_incoming_processing (client);
713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
714 "Server receives %u bytes from `%s'.\n",
715 available, GNUNET_a2s (addr, addrlen));
717 GNUNET_SERVER_client_keep (client);
718 client->last_activity = GNUNET_TIME_absolute_get ();
719 /* process data (if available) */
720 while (available > 0)
723 if (maxcpy > sizeof (client->incoming_buffer) - client->receive_pos)
724 maxcpy = sizeof (client->incoming_buffer) - client->receive_pos;
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Can copy %u bytes to private buffer\n", maxcpy);
729 memcpy (&client->incoming_buffer[client->receive_pos], cbuf, maxcpy);
730 client->receive_pos += maxcpy;
733 if (0 < client->suspended)
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
739 "Client has suspended processing; copying %u bytes to side buffer to be used later.\n",
742 GNUNET_assert (client->side_buf_size == 0);
743 GNUNET_assert (client->side_buf == NULL);
744 client->side_buf_size = available;
745 client->side_buf = GNUNET_malloc (available);
746 memcpy (client->side_buf, cbuf, available);
749 break; /* do not run next client iteration! */
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753 "Now processing messages in private buffer\n");
755 process_client_buffer (client);
757 GNUNET_assert (available == 0);
758 if ((client->suspended == 0) &&
759 (GNUNET_YES != client->shutdown_now) && (client->server != NULL))
761 /* Finally, keep receiving! */
762 client->receive (client->client_closure,
763 GNUNET_SERVER_MAX_MESSAGE_SIZE,
764 server->idle_timeout, &process_incoming, client);
766 if (GNUNET_YES == client->shutdown_now)
767 shutdown_incoming_processing (client);
768 GNUNET_SERVER_client_drop (client);
776 restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
778 struct GNUNET_SERVER_Client *client = cls;
780 GNUNET_SERVER_client_keep (client);
781 process_client_buffer (client);
782 if (0 == client->suspended)
783 client->receive (client->client_closure,
784 GNUNET_SERVER_MAX_MESSAGE_SIZE,
785 client->server->idle_timeout, &process_incoming, client);
786 GNUNET_SERVER_client_drop (client);
791 * Add a client to the set of our clients and
795 add_client (struct GNUNET_SERVER_Handle *server,
796 struct GNUNET_SERVER_Client *client)
798 client->server = server;
799 client->last_activity = GNUNET_TIME_absolute_get ();
800 client->next = server->clients;
801 server->clients = client;
802 client->receive (client->client_closure,
803 GNUNET_SERVER_MAX_MESSAGE_SIZE,
804 server->idle_timeout, &process_incoming, client);
809 * Create a request for receiving data from a socket.
811 * @param cls identifies the socket to receive from
812 * @param max how much data to read at most
813 * @param timeout when should this operation time out
814 * @param receiver function to call for processing
815 * @param receiver_cls closure for receiver
818 sock_receive (void *cls,
820 struct GNUNET_TIME_Relative timeout,
821 GNUNET_CONNECTION_Receiver receiver, void *receiver_cls)
823 GNUNET_CONNECTION_receive (cls, max, timeout, receiver, receiver_cls);
828 * Wrapper to cancel receiving from a socket.
830 * @param cls handle to the GNUNET_CONNECTION_Handle to cancel
833 sock_receive_cancel (void *cls)
835 GNUNET_CONNECTION_receive_cancel (cls);
843 sock_notify_transmit_ready (void *cls,
845 struct GNUNET_TIME_Relative timeout,
846 GNUNET_CONNECTION_TransmitReadyNotify notify,
849 return GNUNET_CONNECTION_notify_transmit_ready (cls, size, timeout, notify,
858 sock_notify_transmit_ready_cancel (void *cls, void *h)
860 GNUNET_CONNECTION_notify_transmit_ready_cancel (h);
865 * Check if socket is still valid (no fatal errors have happened so far).
867 * @param cls the socket
868 * @return GNUNET_YES if valid, GNUNET_NO otherwise
871 sock_check (void *cls)
873 return GNUNET_CONNECTION_check (cls);
878 * Destroy this socket (free resources).
880 * @param cls the socket
883 sock_destroy (void *cls)
885 GNUNET_CONNECTION_destroy (cls);
890 * Add a TCP socket-based connection to the set of handles managed by
891 * this server. Use this function for outgoing (P2P) connections that
892 * we initiated (and where this server should process incoming
895 * @param server the server to use
896 * @param connection the connection to manage (client must
897 * stop using this connection from now on)
898 * @return the client handle (client should call
899 * "client_drop" on the return value eventually)
901 struct GNUNET_SERVER_Client *
902 GNUNET_SERVER_connect_socket (struct
905 struct GNUNET_CONNECTION_Handle *connection)
907 struct GNUNET_SERVER_Client *client;
909 client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
910 client->client_closure = connection;
911 client->receive = &sock_receive;
912 client->receive_cancel = &sock_receive_cancel;
913 client->notify_transmit_ready = &sock_notify_transmit_ready;
914 client->notify_transmit_ready_cancel = &sock_notify_transmit_ready_cancel;
915 client->check = &sock_check;
916 client->destroy = &sock_destroy;
917 client->reference_count = 1;
918 add_client (server, client);
924 * Add an arbitrary connection to the set of handles managed by this
925 * server. This can be used if a sending and receiving does not
926 * really go over the network (internal transmission) or for servers
929 * @param server the server to use
930 * @param chandle opaque handle for the connection
931 * @param creceive receive function for the connection
932 * @param ccancel cancel receive function for the connection
933 * @param cnotify transmit notification function for the connection
934 * @param cnotify_cancel transmit notification cancellation function for the connection
935 * @param ccheck function to test if the connection is still up
936 * @param cdestroy function to close and free the connection
937 * @return the client handle (client should call
938 * "client_drop" on the return value eventually)
940 struct GNUNET_SERVER_Client *
941 GNUNET_SERVER_connect_callback (struct
945 GNUNET_SERVER_ReceiveCallback
947 GNUNET_SERVER_ReceiveCancelCallback
949 GNUNET_SERVER_TransmitReadyCallback
951 GNUNET_SERVER_TransmitReadyCancelCallback
953 GNUNET_SERVER_CheckCallback
955 GNUNET_SERVER_DestroyCallback cdestroy)
957 struct GNUNET_SERVER_Client *client;
959 client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
960 client->client_closure = chandle;
961 client->receive = creceive;
962 client->receive_cancel = ccancel;
963 client->notify_transmit_ready = cnotify;
964 client->notify_transmit_ready_cancel = cnotify_cancel;
965 client->check = ccheck;
966 client->destroy = cdestroy;
967 client->reference_count = 1;
968 add_client (server, client);
974 * Notify the server that the given client handle should
975 * be kept (keeps the connection up if possible, increments
976 * the internal reference counter).
978 * @param client the client to keep
981 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
983 client->reference_count++;
988 * Notify the server that the given client handle is no
989 * longer required. Decrements the reference counter. If
990 * that counter reaches zero an inactive connection maybe
993 * @param client the client to drop
996 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
998 GNUNET_assert (client->reference_count > 0);
999 client->reference_count--;
1000 if ((client->server == NULL) && (client->reference_count == 0))
1001 shutdown_incoming_processing (client);
1006 * Obtain the network address of the other party.
1008 * @param client the client to get the address for
1009 * @param addr where to store the address
1010 * @param addrlen where to store the length of the address
1011 * @return GNUNET_OK on success
1014 GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1015 void **addr, size_t * addrlen)
1017 if (client->receive != &sock_receive)
1018 return GNUNET_SYSERR; /* not a network client */
1019 return GNUNET_CONNECTION_get_address (client->client_closure,
1025 * Ask the server to notify us whenever a client disconnects.
1026 * This function is called whenever the actual network connection
1027 * is closed; the reference count may be zero or larger than zero
1030 * @param server the server manageing the clients
1031 * @param callback function to call on disconnect
1032 * @param callback_cls closure for callback
1035 GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1036 GNUNET_SERVER_DisconnectCallback callback,
1039 struct NotifyList *n;
1041 n = GNUNET_malloc (sizeof (struct NotifyList));
1042 n->callback = callback;
1043 n->callback_cls = callback_cls;
1044 n->next = server->disconnect_notify_list;
1045 server->disconnect_notify_list = n;
1050 * Ask the server to disconnect from the given client.
1051 * This is the same as returning GNUNET_SYSERR from a message
1052 * handler, except that it allows dropping of a client even
1053 * when not handling a message from that client.
1055 * @param client the client to disconnect from
1058 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1060 if (client->server == NULL)
1061 return; /* already disconnected */
1062 client->receive_cancel (client->client_closure);
1063 shutdown_incoming_processing (client);
1068 * Notify us when the server has enough space to transmit
1069 * a message of the given size to the given client.
1071 * @param client client to transmit message to
1072 * @param size requested amount of buffer space
1073 * @param timeout after how long should we give up (and call
1074 * notify with buf NULL and size 0)?
1075 * @param callback function to call when space is available
1076 * @param callback_cls closure for callback
1077 * @return non-NULL if the notify callback was queued; can be used
1078 * to cancel the request using
1079 * GNUNET_CONNECTION_notify_transmit_ready_cancel.
1080 * NULL if we are already going to notify someone else (busy)
1082 struct GNUNET_CONNECTION_TransmitHandle *
1083 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1085 struct GNUNET_TIME_Relative timeout,
1086 GNUNET_CONNECTION_TransmitReadyNotify
1087 callback, void *callback_cls)
1089 return client->notify_transmit_ready (client->client_closure,
1091 timeout, callback, callback_cls);
1096 * Resume receiving from this client, we are done processing the
1097 * current request. This function must be called from within each
1098 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1100 * @param client client we were processing a message of
1101 * @param success GNUNET_OK to keep the connection open and
1102 * continue to receive
1103 * GNUNET_SYSERR to close the connection (signal
1107 GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success)
1113 GNUNET_assert (client->suspended > 0);
1114 client->suspended--;
1115 if (success != GNUNET_OK)
1116 client->shutdown_now = GNUNET_YES;
1117 if (client->suspended > 0)
1119 if (client->in_process_client_buffer == GNUNET_YES)
1121 if (client->side_buf_size > 0)
1123 /* resume processing from side-buf */
1124 sb = client->side_buf;
1125 client->side_buf = NULL;
1126 /* this will also resume the receive job */
1127 if (GNUNET_YES != client->shutdown_now)
1128 process_incoming (client, sb, client->side_buf_size, NULL, 0, 0);
1130 shutdown_incoming_processing (client);
1131 /* finally, free the side-buf */
1135 /* resume receive job */
1136 if (GNUNET_YES != client->shutdown_now)
1138 GNUNET_SCHEDULER_add_continuation (client->server->sched,
1139 &restart_processing,
1141 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1144 shutdown_incoming_processing (client);
1148 /* end of server.c */