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"
37 #include "gnunet_protocols.h"
39 #define DEBUG_SERVER GNUNET_NO
42 * List of arrays of message handlers.
47 * This is a linked list.
49 struct HandlerList *next;
52 * NULL-terminated array of handlers.
54 const struct GNUNET_SERVER_MessageHandler *handlers;
59 * List of arrays of message handlers.
64 * This is a linked list.
66 struct NotifyList *next;
71 GNUNET_SERVER_DisconnectCallback callback;
74 * Closure for callback.
81 * @brief handle for a server
83 struct GNUNET_SERVER_Handle
88 struct GNUNET_SCHEDULER_Handle *sched;
91 * List of handlers for incoming messages.
93 struct HandlerList *handlers;
96 * List of our current clients.
98 struct GNUNET_SERVER_Client *clients;
101 * Linked list of functions to call on disconnects by clients.
103 struct NotifyList *disconnect_notify_list;
106 * Function to call for access control.
108 GNUNET_CONNECTION_AccessCheck access;
111 * Closure for access.
116 * NULL-terminated array of sockets used to listen for new
119 struct GNUNET_NETWORK_Handle **listen_sockets;
122 * After how long should an idle connection time
125 struct GNUNET_TIME_Relative idle_timeout;
128 * maximum write buffer size for accepted sockets
133 * Task scheduled to do the listening.
135 GNUNET_SCHEDULER_TaskIdentifier listen_task;
138 * Do we ignore messages of types that we do not understand or do we
139 * require that a handler is found (and if not kill the connection)?
144 * Should all of the clients of this server continue to process
145 * connections as usual even if we get a shutdown request? (the
146 * listen socket always ignores shutdown).
148 int clients_ignore_shutdown;
154 * @brief handle for a client of the server
156 struct GNUNET_SERVER_Client
160 * Size of the buffer for incoming data. Should be
161 * first so we get nice alignment.
163 char incoming_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
166 * This is a linked list.
168 struct GNUNET_SERVER_Client *next;
171 * Server that this client belongs to.
173 struct GNUNET_SERVER_Handle *server;
176 * Client closure for callbacks.
178 void *client_closure;
181 * Callback to receive from client.
183 GNUNET_SERVER_ReceiveCallback receive;
186 * Callback to cancel receive from client.
188 GNUNET_SERVER_ReceiveCancelCallback receive_cancel;
191 * Callback to ask about transmit-ready notification.
193 GNUNET_SERVER_TransmitReadyCallback notify_transmit_ready;
196 * Callback to ask about transmit-ready notification.
198 GNUNET_SERVER_TransmitReadyCancelCallback notify_transmit_ready_cancel;
201 * Callback to check if client is still valid.
203 GNUNET_SERVER_CheckCallback check;
206 * Callback to destroy client.
208 GNUNET_SERVER_DestroyCallback destroy;
211 * Side-buffer for incoming data used when processing
217 * ID of task used to restart processing.
219 GNUNET_SCHEDULER_TaskIdentifier restart_task;
222 * Number of bytes in the side buffer.
224 size_t side_buf_size;
227 * Last activity on this socket (used to time it out
228 * if reference_count == 0).
230 struct GNUNET_TIME_Absolute last_activity;
233 * How many bytes in the "incoming_buffer" are currently
234 * valid? (starting at offset 0).
239 * Number of external entities with a reference to
240 * this client object.
242 unsigned int reference_count;
245 * Was processing if incoming messages suspended while
246 * we were still processing data already received?
247 * This is a counter saying how often processing was
248 * suspended (once per handler invoked).
250 unsigned int suspended;
253 * Are we currently in the "process_client_buffer" function (and
254 * will hence restart the receive job on exit if suspended == 0 once
255 * we are done?). If this is set, then "receive_done" will
256 * essentially only decrement suspended; if this is not set, then
257 * "receive_done" may need to restart the receive process (either
258 * from the side-buffer or via select/recv).
260 int in_process_client_buffer;
263 * We're about to close down this client due to some serious
269 * Are we currently trying to receive?
274 * Persist the file handle for this client no matter what happens,
275 * force the OS to close once the process actually dies. Should only
276 * be used in special cases!
283 * Scheduler says our listen socket is ready. Process it!
285 * @param cls handle to our server for which we are processing the listen
287 * @param tc reason why we are running right now
290 process_listen_socket (void *cls,
291 const struct GNUNET_SCHEDULER_TaskContext *tc)
293 struct GNUNET_SERVER_Handle *server = cls;
294 struct GNUNET_CONNECTION_Handle *sock;
295 struct GNUNET_SERVER_Client *client;
296 struct GNUNET_NETWORK_FDSet *r;
299 server->listen_task = GNUNET_SCHEDULER_NO_TASK;
300 r = GNUNET_NETWORK_fdset_create ();
302 while (NULL != server->listen_sockets[i])
303 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
304 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
306 /* ignore shutdown, someone else will take care of it! */
307 server->listen_task = GNUNET_SCHEDULER_add_select (server->sched,
308 GNUNET_SCHEDULER_PRIORITY_HIGH,
309 GNUNET_SCHEDULER_NO_TASK,
310 GNUNET_TIME_UNIT_FOREVER_REL,
312 &process_listen_socket,
314 GNUNET_NETWORK_fdset_destroy (r);
318 while (NULL != server->listen_sockets[i])
320 if (GNUNET_NETWORK_fdset_isset
321 (tc->read_ready, server->listen_sockets[i]))
324 GNUNET_CONNECTION_create_from_accept (tc->sched, server->access,
326 server->listen_sockets[i],
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Server accepted incoming connection.\n");
334 client = GNUNET_SERVER_connect_socket (server, sock);
335 GNUNET_CONNECTION_ignore_shutdown (sock,
336 server->clients_ignore_shutdown);
337 /* decrement reference count, we don't keep "client" alive */
338 GNUNET_SERVER_client_drop (client);
343 /* listen for more! */
344 server->listen_task = GNUNET_SCHEDULER_add_select (server->sched,
345 GNUNET_SCHEDULER_PRIORITY_HIGH,
346 GNUNET_SCHEDULER_NO_TASK,
347 GNUNET_TIME_UNIT_FOREVER_REL,
349 &process_listen_socket,
351 GNUNET_NETWORK_fdset_destroy (r);
356 * Create and initialize a listen socket for the server.
358 * @param serverAddr address to listen on
359 * @param socklen length of address
360 * @return NULL on error, otherwise the listen socket
362 static struct GNUNET_NETWORK_Handle *
363 open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
365 const static int on = 1;
366 struct GNUNET_NETWORK_Handle *sock;
370 switch (serverAddr->sa_family)
373 port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port);
376 port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port);
382 sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0);
385 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
391 if (GNUNET_NETWORK_socket_setsockopt
392 (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
393 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
396 if ( (serverAddr->sa_family == AF_INET6) &&
397 (GNUNET_NETWORK_socket_setsockopt
398 (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK) )
399 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
403 /* bind the socket */
404 if (GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen) != GNUNET_OK)
407 if (errno != EADDRINUSE)
409 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
410 fail if we already took the port on IPv6; if both IPv4 and
411 IPv6 binds fail, then our caller will log using the
412 errno preserved in 'eno' */
413 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 ("`%s' failed for port %d (%s).\n"),
419 (serverAddr->sa_family == AF_INET) ? "IPv4" : "IPv6");
422 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
426 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
428 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
429 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "Server starts to listen on port %u.\n", port);
443 * Create a new server.
445 * @param sched scheduler to use
446 * @param access function for access control
447 * @param access_cls closure for access
448 * @param serverAddr address to listen on (including port), NULL terminated array
449 * @param socklen length of serverAddr
450 * @param maxbuf maximum write buffer size for accepted sockets
451 * @param idle_timeout after how long should we timeout idle connections?
452 * @param require_found if YES, connections sending messages of unknown type
454 * @return handle for the new server, NULL on error
455 * (typically, "port" already in use)
457 struct GNUNET_SERVER_Handle *
458 GNUNET_SERVER_create (struct GNUNET_SCHEDULER_Handle *sched,
459 GNUNET_CONNECTION_AccessCheck access,
461 struct sockaddr *const *serverAddr,
462 const socklen_t * socklen,
464 struct GNUNET_TIME_Relative
465 idle_timeout, int require_found)
467 struct GNUNET_SERVER_Handle *ret;
468 struct GNUNET_NETWORK_Handle **lsocks;
469 struct GNUNET_NETWORK_FDSet *r;
474 while (serverAddr[i] != NULL)
479 GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
482 while (serverAddr[i] != NULL)
484 lsocks[j] = open_listen_socket (serverAddr[i], socklen[i]);
485 if (lsocks[j] != NULL)
492 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
493 GNUNET_free (lsocks);
501 ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle));
503 ret->maxbuf = maxbuf;
504 ret->idle_timeout = idle_timeout;
505 ret->listen_sockets = lsocks;
506 ret->access = access;
507 ret->access_cls = access_cls;
508 ret->require_found = require_found;
511 r = GNUNET_NETWORK_fdset_create ();
513 while (NULL != ret->listen_sockets[i])
514 GNUNET_NETWORK_fdset_set (r, ret->listen_sockets[i++]);
515 ret->listen_task = GNUNET_SCHEDULER_add_select (sched,
516 GNUNET_SCHEDULER_PRIORITY_HIGH,
517 GNUNET_SCHEDULER_NO_TASK,
518 GNUNET_TIME_UNIT_FOREVER_REL,
520 &process_listen_socket,
522 GNUNET_NETWORK_fdset_destroy (r);
529 * Free resources held by this server.
531 * @param s server to destroy
534 GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s)
536 struct HandlerList *hpos;
537 struct NotifyList *npos;
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n");
543 if (GNUNET_SCHEDULER_NO_TASK != s->listen_task)
545 GNUNET_SCHEDULER_cancel (s->sched, s->listen_task);
546 s->listen_task = GNUNET_SCHEDULER_NO_TASK;
548 if (s->listen_sockets != NULL)
551 while (s->listen_sockets[i] != NULL)
552 GNUNET_break (GNUNET_OK ==
553 GNUNET_NETWORK_socket_close (s->listen_sockets[i++]));
554 GNUNET_free (s->listen_sockets);
555 s->listen_sockets = NULL;
557 while (s->clients != NULL)
558 GNUNET_SERVER_client_disconnect (s->clients);
559 while (NULL != (hpos = s->handlers))
561 s->handlers = hpos->next;
564 while (NULL != (npos = s->disconnect_notify_list))
566 npos->callback (npos->callback_cls, NULL);
567 s->disconnect_notify_list = npos->next;
575 * Add additional handlers to an existing server.
577 * @param server the server to add handlers to
578 * @param handlers array of message handlers for
579 * incoming messages; the last entry must
580 * have "NULL" for the "callback"; multiple
581 * entries for the same type are allowed,
582 * they will be called in order of occurence.
583 * These handlers can be removed later;
584 * the handlers array must exist until removed
585 * (or server is destroyed).
588 GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
589 const struct GNUNET_SERVER_MessageHandler
592 struct HandlerList *p;
594 p = GNUNET_malloc (sizeof (struct HandlerList));
595 p->handlers = handlers;
596 p->next = server->handlers;
597 server->handlers = p;
602 * Inject a message into the server, pretend it came
603 * from the specified client. Delivery of the message
604 * will happen instantly (if a handler is installed;
605 * otherwise the call does nothing).
607 * @param server the server receiving the message
608 * @param sender the "pretended" sender of the message
610 * @param message message to transmit
611 * @return GNUNET_OK if the message was OK and the
612 * connection can stay open
613 * GNUNET_SYSERR if the connection to the
614 * client should be shut down
617 GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
618 struct GNUNET_SERVER_Client *sender,
619 const struct GNUNET_MessageHeader *message)
621 struct HandlerList *pos;
622 const struct GNUNET_SERVER_MessageHandler *mh;
628 type = ntohs (message->type);
629 size = ntohs (message->size);
631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632 "Server schedules transmission of %u-byte message of type %u to client.\n",
635 pos = server->handlers;
640 while (pos->handlers[i].callback != NULL)
642 mh = &pos->handlers[i];
643 if ( (mh->type == type) ||
644 (mh->type == GNUNET_MESSAGE_TYPE_ALL) )
646 if ((mh->expected_size != 0) && (mh->expected_size != size))
649 return GNUNET_SYSERR;
653 mh->callback (mh->callback_cls, sender, message);
660 if (found == GNUNET_NO)
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
663 _("Received message of unknown type %d\n"), type);
664 if (server->require_found == GNUNET_YES)
665 return GNUNET_SYSERR;
672 * Go over the contents of the client buffer; as long as full messages
673 * are available, pass them on for processing. Update the buffer
674 * accordingly. Handles fatal errors by shutting down the connection.
676 * @param client identifies which client receive buffer to process
679 process_client_buffer (struct GNUNET_SERVER_Client *client)
681 struct GNUNET_SERVER_Handle *server;
682 const struct GNUNET_MessageHeader *hdr;
685 client->in_process_client_buffer = GNUNET_YES;
686 server = client->server;
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Private buffer contains %u bytes; client is %s and we are %s\n",
691 client->suspended ? "suspended" : "up",
692 client->shutdown_now ? "in shutdown" : "running");
694 while ( (client->receive_pos >= sizeof (struct GNUNET_MessageHeader)) &&
695 (0 == client->suspended) &&
696 (GNUNET_YES != client->shutdown_now) )
698 hdr = (const struct GNUNET_MessageHeader *) &client->incoming_buffer;
699 msize = ntohs (hdr->size);
700 if (msize > client->receive_pos)
703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
704 "Total message size is %u, we only have %u bytes; need more data\n",
705 msize, client->receive_pos);
710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
711 "Passing %u bytes to callback for processing\n", msize);
713 if ( (msize < sizeof (struct GNUNET_MessageHeader)) ||
714 (GNUNET_OK != GNUNET_SERVER_inject (server, client, hdr)) )
716 client->in_process_client_buffer = GNUNET_NO;
717 GNUNET_SERVER_client_disconnect (client);
720 /* FIXME: this is highly inefficient; we should
721 try to avoid this if the new base address is
722 already nicely aligned. See old handler code... */
723 memmove (client->incoming_buffer,
724 &client->incoming_buffer[msize], client->receive_pos - msize);
725 client->receive_pos -= msize;
727 client->in_process_client_buffer = GNUNET_NO;
728 if (GNUNET_YES == client->shutdown_now)
729 GNUNET_SERVER_client_disconnect (client);
734 * We are receiving an incoming message. Process it.
736 * @param cls our closure (handle for the client)
737 * @param buf buffer with data received from network
738 * @param available number of bytes available in buf
739 * @param addr address of the sender
740 * @param addrlen length of addr
741 * @param errCode code indicating errors receiving, 0 for success
744 process_incoming (void *cls,
747 const struct sockaddr *addr, socklen_t addrlen, int errCode)
749 struct GNUNET_SERVER_Client *client = cls;
750 struct GNUNET_SERVER_Handle *server = client->server;
751 const char *cbuf = buf;
754 client->receive_pending = GNUNET_NO;
759 (client->shutdown_now == GNUNET_YES) ||
760 (GNUNET_YES != client->check (client->client_closure)))
762 /* other side closed connection, error connecting, etc. */
763 GNUNET_SERVER_client_disconnect (client);
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Server receives %u bytes from `%s'.\n",
769 available, GNUNET_a2s (addr, addrlen));
771 GNUNET_SERVER_client_keep (client);
772 client->last_activity = GNUNET_TIME_absolute_get ();
773 /* process data (if available) */
774 while (available > 0)
777 if (maxcpy > sizeof (client->incoming_buffer) - client->receive_pos)
778 maxcpy = sizeof (client->incoming_buffer) - client->receive_pos;
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Can copy %u bytes to private buffer\n", maxcpy);
783 memcpy (&client->incoming_buffer[client->receive_pos], cbuf, maxcpy);
784 client->receive_pos += maxcpy;
787 if (0 < client->suspended)
792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793 "Client has suspended processing; copying %u bytes to side buffer to be used later.\n",
796 GNUNET_assert (client->side_buf_size == 0);
797 GNUNET_assert (client->side_buf == NULL);
798 client->side_buf_size = available;
799 client->side_buf = GNUNET_malloc (available);
800 memcpy (client->side_buf, cbuf, available);
803 break; /* do not run next client iteration! */
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807 "Now processing messages in private buffer\n");
809 process_client_buffer (client);
811 GNUNET_assert (available == 0);
812 if ((client->suspended == 0) &&
813 (GNUNET_YES != client->shutdown_now) && (client->server != NULL))
815 /* Finally, keep receiving! */
816 client->receive_pending = GNUNET_YES;
817 client->receive (client->client_closure,
818 GNUNET_SERVER_MAX_MESSAGE_SIZE,
819 server->idle_timeout, &process_incoming, client);
821 if (GNUNET_YES == client->shutdown_now)
822 GNUNET_SERVER_client_disconnect (client);
823 GNUNET_SERVER_client_drop (client);
828 * Task run to start again receiving from the network
829 * and process requests.
831 * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from
832 * @param tc scheduler context (unused)
835 restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
837 struct GNUNET_SERVER_Client *client = cls;
838 struct GNUNET_SERVER_Handle *server = client->server;
840 client->restart_task = GNUNET_SCHEDULER_NO_TASK;
841 if ( (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) &&
842 (GNUNET_NO == server->clients_ignore_shutdown) )
844 GNUNET_SERVER_client_disconnect (client);
847 GNUNET_SERVER_client_keep (client);
848 process_client_buffer (client);
849 if (0 == client->suspended)
851 client->receive_pending = GNUNET_YES;
852 client->receive (client->client_closure,
853 GNUNET_SERVER_MAX_MESSAGE_SIZE,
854 client->server->idle_timeout, &process_incoming, client);
856 GNUNET_SERVER_client_drop (client);
861 * Add a client to the set of our clients and
865 add_client (struct GNUNET_SERVER_Handle *server,
866 struct GNUNET_SERVER_Client *client)
868 client->server = server;
869 client->last_activity = GNUNET_TIME_absolute_get ();
870 client->next = server->clients;
871 server->clients = client;
872 client->receive_pending = GNUNET_YES;
873 client->receive (client->client_closure,
874 GNUNET_SERVER_MAX_MESSAGE_SIZE,
875 server->idle_timeout, &process_incoming, client);
880 * Create a request for receiving data from a socket.
882 * @param cls identifies the socket to receive from
883 * @param max how much data to read at most
884 * @param timeout when should this operation time out
885 * @param receiver function to call for processing
886 * @param receiver_cls closure for receiver
889 sock_receive (void *cls,
891 struct GNUNET_TIME_Relative timeout,
892 GNUNET_CONNECTION_Receiver receiver, void *receiver_cls)
894 GNUNET_CONNECTION_receive (cls, max, timeout, receiver, receiver_cls);
899 * Wrapper to cancel receiving from a socket.
901 * @param cls handle to the GNUNET_CONNECTION_Handle to cancel
904 sock_receive_cancel (void *cls)
906 GNUNET_CONNECTION_receive_cancel (cls);
914 sock_notify_transmit_ready (void *cls,
916 struct GNUNET_TIME_Relative timeout,
917 GNUNET_CONNECTION_TransmitReadyNotify notify,
920 return GNUNET_CONNECTION_notify_transmit_ready (cls, size, timeout, notify,
929 sock_notify_transmit_ready_cancel (void *cls, void *h)
931 GNUNET_CONNECTION_notify_transmit_ready_cancel (h);
936 * Check if socket is still valid (no fatal errors have happened so far).
938 * @param cls the socket
939 * @return GNUNET_YES if valid, GNUNET_NO otherwise
942 sock_check (void *cls)
944 return GNUNET_CONNECTION_check (cls);
949 * Destroy this socket (free resources).
951 * @param cls the socket
952 * @param persist set the socket to be persisted
955 sock_destroy (void *cls, int persist)
957 struct GNUNET_CONNECTION_Handle *sock = cls;
958 if (persist == GNUNET_YES)
959 GNUNET_CONNECTION_persist_ (sock);
961 GNUNET_CONNECTION_destroy (sock, GNUNET_NO);
966 * Add a TCP socket-based connection to the set of handles managed by
967 * this server. Use this function for outgoing (P2P) connections that
968 * we initiated (and where this server should process incoming
971 * @param server the server to use
972 * @param connection the connection to manage (client must
973 * stop using this connection from now on)
974 * @return the client handle (client should call
975 * "client_drop" on the return value eventually)
977 struct GNUNET_SERVER_Client *
978 GNUNET_SERVER_connect_socket (struct
981 struct GNUNET_CONNECTION_Handle *connection)
983 struct GNUNET_SERVER_Client *client;
985 client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
986 client->client_closure = connection;
987 client->receive = &sock_receive;
988 client->receive_cancel = &sock_receive_cancel;
989 client->notify_transmit_ready = &sock_notify_transmit_ready;
990 client->notify_transmit_ready_cancel = &sock_notify_transmit_ready_cancel;
991 client->check = &sock_check;
992 client->destroy = &sock_destroy;
993 client->reference_count = 1;
994 add_client (server, client);
1000 * Add an arbitrary connection to the set of handles managed by this
1001 * server. This can be used if a sending and receiving does not
1002 * really go over the network (internal transmission) or for servers
1005 * @param server the server to use
1006 * @param chandle opaque handle for the connection
1007 * @param creceive receive function for the connection
1008 * @param ccancel cancel receive function for the connection
1009 * @param cnotify transmit notification function for the connection
1010 * @param cnotify_cancel transmit notification cancellation function for the connection
1011 * @param ccheck function to test if the connection is still up
1012 * @param cdestroy function to close and free the connection
1013 * @return the client handle (client should call
1014 * "client_drop" on the return value eventually)
1016 struct GNUNET_SERVER_Client *
1017 GNUNET_SERVER_connect_callback (struct
1018 GNUNET_SERVER_Handle
1021 GNUNET_SERVER_ReceiveCallback
1023 GNUNET_SERVER_ReceiveCancelCallback
1025 GNUNET_SERVER_TransmitReadyCallback
1027 GNUNET_SERVER_TransmitReadyCancelCallback
1029 GNUNET_SERVER_CheckCallback
1031 GNUNET_SERVER_DestroyCallback cdestroy)
1033 struct GNUNET_SERVER_Client *client;
1035 client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
1036 client->client_closure = chandle;
1037 client->receive = creceive;
1038 client->receive_cancel = ccancel;
1039 client->notify_transmit_ready = cnotify;
1040 client->notify_transmit_ready_cancel = cnotify_cancel;
1041 client->check = ccheck;
1042 client->destroy = cdestroy;
1043 client->reference_count = 1;
1044 add_client (server, client);
1050 * Notify the server that the given client handle should
1051 * be kept (keeps the connection up if possible, increments
1052 * the internal reference counter).
1054 * @param client the client to keep
1057 GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
1059 client->reference_count++;
1064 * Notify the server that the given client handle is no
1065 * longer required. Decrements the reference counter. If
1066 * that counter reaches zero an inactive connection maybe
1069 * @param client the client to drop
1072 GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
1074 GNUNET_assert (client->reference_count > 0);
1075 client->reference_count--;
1076 if ( (client->shutdown_now == GNUNET_YES) &&
1077 (client->reference_count == 0) )
1078 GNUNET_SERVER_client_disconnect (client);
1083 * Obtain the network address of the other party.
1085 * @param client the client to get the address for
1086 * @param addr where to store the address
1087 * @param addrlen where to store the length of the address
1088 * @return GNUNET_OK on success
1091 GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
1092 void **addr, size_t * addrlen)
1094 if (client->receive != &sock_receive)
1095 return GNUNET_SYSERR; /* not a network client */
1096 return GNUNET_CONNECTION_get_address (client->client_closure,
1102 * Ask the server to notify us whenever a client disconnects.
1103 * This function is called whenever the actual network connection
1104 * is closed; the reference count may be zero or larger than zero
1107 * @param server the server manageing the clients
1108 * @param callback function to call on disconnect
1109 * @param callback_cls closure for callback
1112 GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
1113 GNUNET_SERVER_DisconnectCallback callback,
1116 struct NotifyList *n;
1118 n = GNUNET_malloc (sizeof (struct NotifyList));
1119 n->callback = callback;
1120 n->callback_cls = callback_cls;
1121 n->next = server->disconnect_notify_list;
1122 server->disconnect_notify_list = n;
1127 * Ask the server to stop notifying us whenever a client disconnects.
1129 * @param server the server manageing the clients
1130 * @param callback function to call on disconnect
1131 * @param callback_cls closure for callback
1134 GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
1135 GNUNET_SERVER_DisconnectCallback callback,
1138 struct NotifyList *pos;
1139 struct NotifyList *prev;
1142 pos = server->disconnect_notify_list;
1145 if ( (pos->callback == callback) &&
1146 (pos->callback_cls == callback_cls ) )
1157 server->disconnect_notify_list = pos->next;
1159 prev->next = pos->next;
1165 * Ask the server to disconnect from the given client.
1166 * This is the same as returning GNUNET_SYSERR from a message
1167 * handler, except that it allows dropping of a client even
1168 * when not handling a message from that client.
1170 * @param client the client to disconnect from
1173 GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
1175 struct GNUNET_SERVER_Client *prev;
1176 struct GNUNET_SERVER_Client *pos;
1177 struct GNUNET_SERVER_Handle *server;
1178 struct NotifyList *n;
1181 if (client->restart_task != GNUNET_SCHEDULER_NO_TASK)
1183 GNUNET_SCHEDULER_cancel (client->server->sched,
1184 client->restart_task);
1185 client->restart_task = GNUNET_SCHEDULER_NO_TASK;
1187 if (GNUNET_YES == client->receive_pending)
1189 client->receive_cancel (client->client_closure);
1190 client->receive_pending = GNUNET_NO;
1193 rc = client->reference_count;
1194 if (client->server != NULL)
1196 server = client->server;
1197 client->server = NULL;
1198 client->shutdown_now = GNUNET_YES;
1200 pos = server->clients;
1201 while ((pos != NULL) && (pos != client))
1206 GNUNET_assert (pos != NULL);
1208 server->clients = pos->next;
1210 prev->next = pos->next;
1211 if (client->restart_task != GNUNET_SCHEDULER_NO_TASK)
1212 GNUNET_SCHEDULER_cancel (server->sched,
1213 client->restart_task);
1214 n = server->disconnect_notify_list;
1217 n->callback (n->callback_cls, client);
1223 if (client->in_process_client_buffer == GNUNET_YES)
1225 client->destroy (client->client_closure, client->persist);
1226 GNUNET_free (client);
1231 * Notify us when the server has enough space to transmit
1232 * a message of the given size to the given client.
1234 * @param client client to transmit message to
1235 * @param size requested amount of buffer space
1236 * @param timeout after how long should we give up (and call
1237 * notify with buf NULL and size 0)?
1238 * @param callback function to call when space is available
1239 * @param callback_cls closure for callback
1240 * @return non-NULL if the notify callback was queued; can be used
1241 * to cancel the request using
1242 * GNUNET_CONNECTION_notify_transmit_ready_cancel.
1243 * NULL if we are already going to notify someone else (busy)
1245 struct GNUNET_CONNECTION_TransmitHandle *
1246 GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
1248 struct GNUNET_TIME_Relative timeout,
1249 GNUNET_CONNECTION_TransmitReadyNotify
1250 callback, void *callback_cls)
1252 return client->notify_transmit_ready (client->client_closure,
1254 timeout, callback, callback_cls);
1258 * Set the persistent flag on this client, used to setup client connection
1259 * to only be killed when the service it's connected to is actually dead.
1261 * @param client the client to set the persistent flag on
1264 GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
1266 client->persist = GNUNET_YES;
1270 * Resume receiving from this client, we are done processing the
1271 * current request. This function must be called from within each
1272 * GNUNET_SERVER_MessageCallback (or its respective continuations).
1274 * @param client client we were processing a message of
1275 * @param success GNUNET_OK to keep the connection open and
1276 * continue to receive
1277 * GNUNET_NO to close the connection (normal behavior)
1278 * GNUNET_SYSERR to close the connection (signal
1282 GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success)
1288 GNUNET_assert (client->suspended > 0);
1289 client->suspended--;
1290 if (success != GNUNET_OK)
1292 GNUNET_SERVER_client_disconnect (client);
1295 if (client->suspended > 0)
1297 if (client->in_process_client_buffer == GNUNET_YES)
1299 if (client->side_buf_size > 0)
1301 /* resume processing from side-buf */
1302 sb = client->side_buf;
1303 client->side_buf = NULL;
1304 /* this will also resume the receive job */
1305 process_incoming (client, sb, client->side_buf_size, NULL, 0, 0);
1306 /* finally, free the side-buf */
1310 if (client->server == NULL)
1312 GNUNET_SERVER_client_disconnect (client);
1315 client->restart_task = GNUNET_SCHEDULER_add_now (client->server->sched,
1316 &restart_processing,
1322 * Configure this server's connections to continue handling client
1323 * requests as usual even after we get a shutdown signal. The change
1324 * only applies to clients that connect to the server from the outside
1325 * using TCP after this call. Clients managed previously or those
1326 * added using GNUNET_SERVER_connect_socket and
1327 * GNUNET_SERVER_connect_callback are not affected by this option.
1329 * @param h server handle
1330 * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default
1333 GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore)
1335 h->clients_ignore_shutdown = do_ignore;
1338 /* end of server.c */