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_network_lib.h"
33 #include "gnunet_scheduler_lib.h"
34 #include "gnunet_server_lib.h"
35 #include "gnunet_time_lib.h"
37 #define DEBUG_SERVER GNUNET_NO
40 * List of arrays of message handlers.
45 * This is a linked list.
47 struct HandlerList *next;
50 * NULL-terminated array of handlers.
52 const struct GNUNET_SERVER_MessageHandler *handlers;
57 * List of arrays of message handlers.
62 * This is a linked list.
64 struct NotifyList *next;
69 GNUNET_SERVER_DisconnectCallback callback;
72 * Closure for callback.
79 * @brief handle for a server
81 struct GNUNET_SERVER_Handle
86 struct GNUNET_SCHEDULER_Handle *sched;
89 * List of handlers for incoming messages.
91 struct HandlerList *handlers;
94 * List of our current clients.
96 struct GNUNET_SERVER_Client *clients;
99 * Linked list of functions to call on disconnects by clients.
101 struct NotifyList *disconnect_notify_list;
104 * Function to call for access control.
106 GNUNET_NETWORK_AccessCheck access;
109 * Closure for access.
114 * After how long should an idle connection time
117 struct GNUNET_TIME_Relative idle_timeout;
120 * maximum write buffer size for accepted sockets
125 * Pipe used to signal shutdown of the server.
130 * Socket used to listen for new connections. Set to
131 * "-1" by GNUNET_SERVER_destroy to initiate shutdown.
136 * Set to GNUNET_YES if we are shutting down.
141 * Do we ignore messages of types that we do not
142 * understand or do we require that a handler
143 * is found (and if not kill the connection)?
151 * @brief handle for a client of the server
153 struct GNUNET_SERVER_Client
157 * Size of the buffer for incoming data. Should be
158 * first so we get nice alignment.
160 char incoming_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
163 * This is a linked list.
165 struct GNUNET_SERVER_Client *next;
168 * Server that this client belongs to.
170 struct GNUNET_SERVER_Handle *server;
173 * Client closure for callbacks.
175 void *client_closure;
178 * Callback to receive from client.
180 GNUNET_SERVER_ReceiveCallback receive;
183 * Callback to cancel receive from client.
185 GNUNET_SERVER_ReceiveCancelCallback receive_cancel;
188 * Callback to ask about transmit-ready notification.
190 GNUNET_SERVER_TransmitReadyCallback notify_transmit_ready;
193 * Callback to ask about transmit-ready notification.
195 GNUNET_SERVER_TransmitReadyCancelCallback notify_transmit_ready_cancel;
198 * Callback to check if client is still valid.
200 GNUNET_SERVER_CheckCallback check;
203 * Callback to destroy client.
205 GNUNET_SERVER_DestroyCallback destroy;
208 * Side-buffer for incoming data used when processing
214 * Number of bytes in the side buffer.
216 size_t side_buf_size;
219 * Last activity on this socket (used to time it out
220 * if reference_count == 0).
222 struct GNUNET_TIME_Absolute last_activity;
225 * Current task identifier for the receive call
226 * (or GNUNET_SCHEDULER_NO_TASK for none).
228 GNUNET_SCHEDULER_TaskIdentifier my_receive;
231 * How many bytes in the "incoming_buffer" are currently
232 * valid? (starting at offset 0).
237 * Number of external entities with a reference to
238 * this client object.
240 unsigned int reference_count;
243 * Was processing if incoming messages suspended while
244 * we were still processing data already received?
245 * This is a counter saying how often processing was
246 * suspended (once per handler invoked).
248 unsigned int suspended;
251 * Are we currently in the "process_client_buffer" function (and
252 * will hence restart the receive job on exit if suspended == 0 once
253 * we are done?). If this is set, then "receive_done" will
254 * essentially only decrement suspended; if this is not set, then
255 * "receive_done" may need to restart the receive process (either
256 * from the side-buffer or via select/recv).
258 int in_process_client_buffer;
261 * We're about to close down this client due to some serious
270 * Server has been asked to shutdown, free resources.
273 destroy_server (struct GNUNET_SERVER_Handle *server)
275 struct GNUNET_SERVER_Client *pos;
276 struct HandlerList *hpos;
277 struct NotifyList *npos;
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 "Server shutting down.\n");
283 GNUNET_assert (server->listen_socket == -1);
284 GNUNET_break (0 == CLOSE (server->shutpipe[0]));
285 GNUNET_break (0 == CLOSE (server->shutpipe[1]));
286 while (server->clients != NULL)
288 pos = server->clients;
289 server->clients = pos->next;
292 while (NULL != (hpos = server->handlers))
294 server->handlers = hpos->next;
297 while (NULL != (npos = server->disconnect_notify_list))
299 server->disconnect_notify_list = npos->next;
302 GNUNET_free (server);
307 * Scheduler says our listen socket is ready.
311 process_listen_socket (void *cls,
312 const struct GNUNET_SCHEDULER_TaskContext *tc)
314 struct GNUNET_SERVER_Handle *server = cls;
315 struct GNUNET_NETWORK_ConnectionHandle *sock;
316 struct GNUNET_SERVER_Client *client;
319 if ((server->do_shutdown) ||
320 ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0))
322 /* shutdown was initiated */
323 GNUNET_assert (server->listen_socket != -1);
324 GNUNET_break (0 == CLOSE (server->listen_socket));
325 server->listen_socket = -1;
326 if (server->do_shutdown)
327 destroy_server (server);
330 GNUNET_assert (FD_ISSET (server->listen_socket, tc->read_ready));
331 GNUNET_assert (!FD_ISSET (server->shutpipe[0], tc->read_ready));
332 sock = GNUNET_NETWORK_connection_create_from_accept (tc->sched,
335 server->listen_socket,
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341 "Server accepted incoming connection.\n");
343 client = GNUNET_SERVER_connect_socket (server, sock);
344 /* decrement reference count, we don't keep "client" alive */
345 GNUNET_SERVER_client_drop (client);
347 /* listen for more! */
349 FD_SET (server->listen_socket, &r);
350 FD_SET (server->shutpipe[0], &r);
351 GNUNET_SCHEDULER_add_select (server->sched,
353 GNUNET_SCHEDULER_PRIORITY_HIGH,
354 GNUNET_SCHEDULER_NO_TASK,
355 GNUNET_TIME_UNIT_FOREVER_REL,
356 GNUNET_MAX (server->listen_socket,
357 server->shutpipe[0]) + 1, &r, NULL,
358 &process_listen_socket, server);
363 * Create and initialize a listen socket for the server.
365 * @return -1 on error, otherwise the listen socket
368 open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
370 const static int on = 1;
374 switch (serverAddr->sa_family)
377 port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port);
380 port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port);
386 fd = SOCKET (serverAddr->sa_family, SOCK_STREAM, 0);
389 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
394 if (0 != fcntl (fd, F_SETFD, fcntl (fd, F_GETFD) | FD_CLOEXEC))
395 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
398 if (SETSOCKOPT (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
399 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
401 /* bind the socket */
402 if (BIND (fd, serverAddr, socklen) < 0)
404 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
405 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
407 ("`%s' failed for port %d. Is the service already running?\n"),
409 GNUNET_break (0 == CLOSE (fd));
412 if (0 != LISTEN (fd, 5))
414 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
415 GNUNET_break (0 == CLOSE (fd));
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420 "Server starts to listen on port %u.\n",
428 * Create a new server.
430 * @param sched scheduler to use
431 * @param access function for access control
432 * @param access_cls closure for access
433 * @param serverAddr address to listen on (including port), use NULL
434 * for internal server (no listening)
435 * @param socklen length of serverAddr
436 * @param maxbuf maximum write buffer size for accepted sockets
437 * @param idle_timeout after how long should we timeout idle connections?
438 * @param require_found if YES, connections sending messages of unknown type
440 * @return handle for the new server, NULL on error
441 * (typically, "port" already in use)
443 struct GNUNET_SERVER_Handle *
444 GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched,
445 GNUNET_NETWORK_AccessCheck access,
447 const struct sockaddr *serverAddr,
450 struct GNUNET_TIME_Relative
451 idle_timeout, int require_found)
453 struct GNUNET_SERVER_Handle *ret;
458 if (serverAddr != NULL)
460 lsock = open_listen_socket (serverAddr, socklen);
464 ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle));
465 if (0 != PIPE (ret->shutpipe))
467 GNUNET_break (0 == CLOSE (lsock));
472 ret->maxbuf = maxbuf;
473 ret->idle_timeout = idle_timeout;
474 ret->listen_socket = lsock;
475 ret->access = access;
476 ret->access_cls = access_cls;
477 ret->require_found = require_found;
481 FD_SET (ret->listen_socket, &r);
482 FD_SET (ret->shutpipe[0], &r);
483 GNUNET_SCHEDULER_add_select (sched,
485 GNUNET_SCHEDULER_PRIORITY_HIGH,
486 GNUNET_SCHEDULER_NO_TASK,
487 GNUNET_TIME_UNIT_FOREVER_REL,
488 GNUNET_MAX (ret->listen_socket,
489 ret->shutpipe[0]) + 1, &r,
490 NULL, &process_listen_socket, ret);
497 * Free resources held by this server.
500 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s)
504 GNUNET_assert (s->do_shutdown == GNUNET_NO);
505 s->do_shutdown = GNUNET_YES;
506 if (s->listen_socket == -1)
509 GNUNET_break (1 == WRITE (s->shutpipe[1], &c, 1));
514 * Add additional handlers to an existing server.
516 * @param server the server to add handlers to
517 * @param handlers array of message handlers for
518 * incoming messages; the last entry must
519 * have "NULL" for the "callback"; multiple
520 * entries for the same type are allowed,
521 * they will be called in order of occurence.
522 * These handlers can be removed later;
523 * the handlers array must exist until removed
524 * (or server is destroyed).
527 GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
528 const struct GNUNET_SERVER_MessageHandler
531 struct HandlerList *p;
533 p = GNUNET_malloc (sizeof (struct HandlerList));
534 p->handlers = handlers;
535 p->next = server->handlers;
536 server->handlers = p;
541 * Inject a message into the server, pretend it came
542 * from the specified client. Delivery of the message
543 * will happen instantly (if a handler is installed;
544 * otherwise the call does nothing).
546 * @param server the server receiving the message
547 * @param sender the "pretended" sender of the message
549 * @param message message to transmit
550 * @return GNUNET_OK if the message was OK and the
551 * connection can stay open
552 * GNUNET_SYSERR if the connection to the
553 * client should be shut down
556 GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
557 struct GNUNET_SERVER_Client *sender,
558 const struct GNUNET_MessageHeader *message)
560 struct HandlerList *pos;
561 const struct GNUNET_SERVER_MessageHandler *mh;
567 type = ntohs (message->type);
568 size = ntohs (message->size);
570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
571 "Server schedules transmission of %u-byte message of type %u to client.\n",
575 pos = server->handlers;
580 while (pos->handlers[i].callback != NULL)
582 mh = &pos->handlers[i];
583 if (mh->type == type)
585 if ((mh->expected_size != 0) && (mh->expected_size != size))
588 return GNUNET_SYSERR;
592 mh->callback (mh->callback_cls, sender, message);
599 if (found == GNUNET_NO)
601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
602 _("Received message of unknown type %d\n"), type);
603 if (server->require_found == GNUNET_YES)
604 return GNUNET_SYSERR;
611 * We're finished with this client and especially its input
612 * processing. If the RC is zero, free all resources otherwise wait
613 * until RC hits zero to do so.
616 shutdown_incoming_processing (struct GNUNET_SERVER_Client *client)
618 struct GNUNET_SERVER_Client *prev;
619 struct GNUNET_SERVER_Client *pos;
620 struct GNUNET_SERVER_Handle *server;
621 struct NotifyList *n;
624 GNUNET_assert (client->my_receive == GNUNET_SCHEDULER_NO_TASK);
625 rc = client->reference_count;
626 if (client->server != NULL)
628 server = client->server;
629 client->server = NULL;
631 pos = server->clients;
632 while ((pos != NULL) && (pos != client))
637 GNUNET_assert (pos != NULL);
639 server->clients = pos->next;
641 prev->next = pos->next;
642 n = server->disconnect_notify_list;
645 n->callback (n->callback_cls, client);
649 /* wait for RC to hit zero, then free */
652 client->destroy (client->client_closure);
653 GNUNET_free (client);
658 * Go over the contents of the client buffer; as long as full messages
659 * are available, pass them on for processing. Update the buffer
660 * accordingly. Handles fatal errors by shutting down the connection.
662 * @param client identifies which client receive buffer to process
665 process_client_buffer (struct GNUNET_SERVER_Client *client)
667 struct GNUNET_SERVER_Handle *server;
668 const struct GNUNET_MessageHeader *hdr;
671 client->in_process_client_buffer = GNUNET_YES;
672 server = client->server;
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 "Private buffer contains %u bytes; client is %s and we are %s\n",
677 client->suspended ? "suspended" : "up",
678 client->shutdown_now ? "in shutdown" : "running");
680 while ((client->receive_pos >= sizeof (struct GNUNET_MessageHeader)) &&
681 (0 == client->suspended) && (GNUNET_YES != client->shutdown_now))
683 hdr = (const struct GNUNET_MessageHeader *) &client->incoming_buffer;
684 msize = ntohs (hdr->size);
685 if (msize > client->receive_pos)
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Total message size is %u, we only have %u bytes; need more data\n",
691 client->receive_pos);
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697 "Passing %u bytes to callback for processing\n",
700 if ((msize < sizeof (struct GNUNET_MessageHeader)) ||
701 (GNUNET_OK != GNUNET_SERVER_inject (server, client, hdr)))
703 client->in_process_client_buffer = GNUNET_NO;
704 shutdown_incoming_processing (client);
707 /* FIXME: this is highly inefficient; we should
708 try to avoid this if the new base address is
709 already nicely aligned. See old handler code... */
710 memmove (client->incoming_buffer,
711 &client->incoming_buffer[msize], client->receive_pos - msize);
712 client->receive_pos -= msize;
714 client->in_process_client_buffer = GNUNET_NO;
715 if (GNUNET_YES == client->shutdown_now)
716 shutdown_incoming_processing (client);
721 * We are receiving an incoming message. Process it.
723 * @param cls our closure (handle for the client)
724 * @param buf buffer with data received from network
725 * @param available number of bytes available in buf
726 * @param addr address of the sender
727 * @param addrlen length of addr
728 * @param errCode code indicating errors receiving, 0 for success
731 process_incoming (void *cls,
734 const struct sockaddr *addr,
738 struct GNUNET_SERVER_Client *client = cls;
739 struct GNUNET_SERVER_Handle *server = client->server;
740 const char *cbuf = buf;
743 client->my_receive = GNUNET_SCHEDULER_NO_TASK;
748 (client->shutdown_now == GNUNET_YES) ||
749 (GNUNET_YES != client->check (client->client_closure)))
751 /* other side closed connection, error connecting, etc. */
752 shutdown_incoming_processing (client);
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757 "Server receives %u bytes from `%s'.\n",
759 GNUNET_a2s(addr, addrlen));
761 GNUNET_SERVER_client_keep (client);
762 client->last_activity = GNUNET_TIME_absolute_get ();
763 /* process data (if available) */
764 while (available > 0)
767 if (maxcpy > sizeof (client->incoming_buffer) - client->receive_pos)
768 maxcpy = sizeof (client->incoming_buffer) - client->receive_pos;
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 "Can copy %u bytes to private buffer\n",
774 memcpy (&client->incoming_buffer[client->receive_pos], cbuf, maxcpy);
775 client->receive_pos += maxcpy;
778 if (0 < client->suspended)
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784 "Client has suspended processing; copying %u bytes to side buffer to be used later.\n",
787 GNUNET_assert (client->side_buf_size == 0);
788 GNUNET_assert (client->side_buf == NULL);
789 client->side_buf_size = available;
790 client->side_buf = GNUNET_malloc (available);
791 memcpy (client->side_buf, cbuf, available);
794 break; /* do not run next client iteration! */
797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798 "Now processing messages in private buffer\n");
800 process_client_buffer (client);
802 GNUNET_assert (available == 0);
803 if ((client->suspended == 0) &&
804 (GNUNET_YES != client->shutdown_now) && (client->server != NULL))
806 /* Finally, keep receiving! */
807 client->my_receive = client->receive (client->client_closure,
808 GNUNET_SERVER_MAX_MESSAGE_SIZE,
809 server->idle_timeout,
810 &process_incoming, client);
812 if (GNUNET_YES == client->shutdown_now)
813 shutdown_incoming_processing (client);
814 GNUNET_SERVER_client_drop (client);
822 restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
824 struct GNUNET_SERVER_Client *client = cls;
826 process_client_buffer (client);
827 if (0 == client->suspended)
828 client->my_receive = client->receive (client->client_closure,
829 GNUNET_SERVER_MAX_MESSAGE_SIZE,
830 client->server->idle_timeout,
831 &process_incoming, client);
836 * Add a client to the set of our clients and
840 add_client (struct GNUNET_SERVER_Handle *server,
841 struct GNUNET_SERVER_Client *client)
843 client->server = server;
844 client->last_activity = GNUNET_TIME_absolute_get ();
845 client->next = server->clients;
846 server->clients = client;
847 client->my_receive = client->receive (client->client_closure,
848 GNUNET_SERVER_MAX_MESSAGE_SIZE,
849 server->idle_timeout,
850 &process_incoming, client);
855 * Create a request for receiving data from a socket.
857 * @param cls identifies the socket to receive from
858 * @param max how much data to read at most
859 * @param timeout when should this operation time out
860 * @param receiver function to call for processing
861 * @param receiver_cls closure for receiver
862 * @return task identifier that can be used to cancel the operation
864 static GNUNET_SCHEDULER_TaskIdentifier
865 sock_receive (void *cls,
867 struct GNUNET_TIME_Relative timeout,
868 GNUNET_NETWORK_Receiver receiver, void *receiver_cls)
870 return GNUNET_NETWORK_connection_receive (cls, max, timeout, receiver, receiver_cls);
875 * Wrapper to cancel receiving from a socket.
877 * @param cls handle to the GNUNET_NETWORK_ConnectionHandle to cancel
878 * @param tc task ID that was returned by GNUNET_NETWORK_connection_receive
881 sock_receive_cancel (void *cls, GNUNET_SCHEDULER_TaskIdentifier ti)
883 GNUNET_NETWORK_connection_receive_cancel (cls, ti);
891 sock_notify_transmit_ready (void *cls,
893 struct GNUNET_TIME_Relative timeout,
894 GNUNET_NETWORK_TransmitReadyNotify notify,
897 return GNUNET_NETWORK_connection_notify_transmit_ready (cls, size, timeout, notify,
906 sock_notify_transmit_ready_cancel (void *cls, void *h)
908 GNUNET_NETWORK_connection_notify_transmit_ready_cancel (h);
913 * Check if socket is still valid (no fatal errors have happened so far).
915 * @param cls the socket
916 * @return GNUNET_YES if valid, GNUNET_NO otherwise
919 sock_check (void *cls)
921 return GNUNET_NETWORK_connection_check (cls);
926 * Destroy this socket (free resources).
928 * @param cls the socket
931 sock_destroy (void *cls)
933 GNUNET_NETWORK_connection_destroy (cls);
938 * Add a TCP socket-based connection to the set of handles managed by
939 * this server. Use this function for outgoing (P2P) connections that
940 * we initiated (and where this server should process incoming
943 * @param server the server to use
944 * @param connection the connection to manage (client must
945 * stop using this connection from now on)
946 * @return the client handle (client should call
947 * "client_drop" on the return value eventually)
949 struct GNUNET_SERVER_Client *
950 GNUNET_SERVER_connect_socket (struct
953 struct GNUNET_NETWORK_ConnectionHandle *connection)
955 struct GNUNET_SERVER_Client *client;
957 client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
958 client->client_closure = connection;
959 client->receive = &sock_receive;
960 client->receive_cancel = &sock_receive_cancel;
961 client->notify_transmit_ready = &sock_notify_transmit_ready;
962 client->notify_transmit_ready_cancel = &sock_notify_transmit_ready_cancel;
963 client->check = &sock_check;
964 client->destroy = &sock_destroy;
965 client->reference_count = 1;
966 add_client (server, client);
972 * Add an arbitrary connection to the set of handles managed by this
973 * server. This can be used if a sending and receiving does not
974 * really go over the network (internal transmission) or for servers
977 * @param server the server to use
978 * @param chandle opaque handle for the connection
979 * @param creceive receive function for the connection
980 * @param ccancel cancel receive function for the connection
981 * @param cnotify transmit notification function for the connection
982 * @param cnotify_cancel transmit notification cancellation function for the connection
983 * @param ccheck function to test if the connection is still up
984 * @param cdestroy function to close and free the connection
985 * @return the client handle (client should call
986 * "client_drop" on the return value eventually)
988 struct GNUNET_SERVER_Client *
989 GNUNET_SERVER_connect_callback (struct
993 GNUNET_SERVER_ReceiveCallback
995 GNUNET_SERVER_ReceiveCancelCallback
997 GNUNET_SERVER_TransmitReadyCallback
999 GNUNET_SERVER_TransmitReadyCancelCallback
1001 GNUNET_SERVER_CheckCallback
1003 GNUNET_SERVER_DestroyCallback cdestroy)
1005 struct GNUNET_SERVER_Client *client;
1007 client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
1008 client->client_closure = chandle;
1009 client->receive = creceive;
1010 client->receive_cancel = ccancel;
1011 client->notify_transmit_ready = cnotify;
1012 client->notify_transmit_ready_cancel = cnotify_cancel;
1013 client->check = ccheck;
1014 client->destroy = cdestroy;
1015 client->reference_count = 1;
1016 add_client (server, client);
1022 * Notify the server that the given client handle should
1023 * be kept (keeps the connection up if possible, increments
1024 * the internal reference counter).
1026 * @param client the client to keep
1029 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1031 client->reference_count++;
1036 * Notify the server that the given client handle is no
1037 * longer required. Decrements the reference counter. If
1038 * that counter reaches zero an inactive connection maybe
1041 * @param client the client to drop
1044 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1046 GNUNET_assert (client->reference_count > 0);
1047 client->reference_count--;
1048 if ((client->server == NULL) && (client->reference_count == 0))
1049 shutdown_incoming_processing (client);
1054 * Obtain the network address of the other party.
1056 * @param client the client to get the address for
1057 * @param addr where to store the address
1058 * @param addrlen where to store the length of the address
1059 * @return GNUNET_OK on success
1062 GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1063 void **addr, size_t * addrlen)
1065 if (client->receive != &sock_receive)
1066 return GNUNET_SYSERR; /* not a network client */
1067 return GNUNET_NETWORK_connection_get_address (client->client_closure,
1073 * Ask the server to notify us whenever a client disconnects.
1074 * This function is called whenever the actual network connection
1075 * is closed; the reference count may be zero or larger than zero
1078 * @param server the server manageing the clients
1079 * @param callback function to call on disconnect
1080 * @param callback_cls closure for callback
1083 GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1084 GNUNET_SERVER_DisconnectCallback callback,
1087 struct NotifyList *n;
1089 n = GNUNET_malloc (sizeof (struct NotifyList));
1090 n->callback = callback;
1091 n->callback_cls = callback_cls;
1092 n->next = server->disconnect_notify_list;
1093 server->disconnect_notify_list = n;
1098 * Ask the server to disconnect from the given client.
1099 * This is the same as returning GNUNET_SYSERR from a message
1100 * handler, except that it allows dropping of a client even
1101 * when not handling a message from that client.
1103 * @param client the client to disconnect from
1106 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1108 if (client->server == NULL)
1109 return; /* already disconnected */
1110 GNUNET_assert (client->my_receive != GNUNET_SCHEDULER_NO_TASK);
1111 client->receive_cancel (client->client_closure, client->my_receive);
1112 client->my_receive = GNUNET_SCHEDULER_NO_TASK;
1113 shutdown_incoming_processing (client);
1118 * Notify us when the server has enough space to transmit
1119 * a message of the given size to the given client.
1121 * @param server the server to use
1122 * @param client client to transmit message to
1123 * @param size requested amount of buffer space
1124 * @param timeout after how long should we give up (and call
1125 * notify with buf NULL and size 0)?
1126 * @param callback function to call when space is available
1127 * @param callback_cls closure for callback
1128 * @return non-NULL if the notify callback was queued; can be used
1129 * to cancel the request using
1130 * GNUNET_NETWORK_connection_notify_transmit_ready_cancel.
1131 * NULL if we are already going to notify someone else (busy)
1133 struct GNUNET_NETWORK_TransmitHandle *
1134 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1136 struct GNUNET_TIME_Relative timeout,
1137 GNUNET_NETWORK_TransmitReadyNotify
1138 callback, void *callback_cls)
1140 return client->notify_transmit_ready (client->client_closure,
1142 timeout, callback, callback_cls);
1147 * Resume receiving from this client, we are done processing the
1148 * current request. This function must be called from within each
1149 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1151 * @param client client we were processing a message of
1152 * @param success GNUNET_OK to keep the connection open and
1153 * continue to receive
1154 * GNUNET_SYSERR to close the connection (signal
1158 GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success)
1164 GNUNET_assert (client->suspended > 0);
1165 client->suspended--;
1166 if (success != GNUNET_OK)
1167 client->shutdown_now = GNUNET_YES;
1168 if (client->suspended > 0)
1170 if (client->in_process_client_buffer == GNUNET_YES)
1172 if (client->side_buf_size > 0)
1174 /* resume processing from side-buf */
1175 sb = client->side_buf;
1176 client->side_buf = NULL;
1177 /* this will also resume the receive job */
1178 if (GNUNET_YES != client->shutdown_now)
1179 process_incoming (client, sb, client->side_buf_size, NULL, 0, 0);
1181 shutdown_incoming_processing (client);
1182 /* finally, free the side-buf */
1186 /* resume receive job */
1187 if (GNUNET_YES != client->shutdown_now)
1189 GNUNET_SCHEDULER_add_continuation (client->server->sched,
1191 &restart_processing,
1193 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1196 shutdown_incoming_processing (client);
1200 /* end of server.c */