2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 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 3, 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.
22 * @file core/gnunet-service-core_clients.c
23 * @brief code for managing interactions with clients of core service
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet-service-core.h"
31 #include "gnunet-service-core_clients.h"
32 #include "gnunet-service-core_sessions.h"
33 #include "gnunet-service-core_typemap.h"
36 #define DEBUG_CONNECTS GNUNET_YES
39 * How many messages do we queue up at most for optional
40 * notifications to a client? (this can cause notifications
41 * about outgoing messages to be dropped).
43 #define MAX_NOTIFY_QUEUE 1024
47 * Data structure for each client connected to the core service.
52 * Clients are kept in a linked list.
54 struct GSC_Client *next;
57 * Clients are kept in a linked list.
59 struct GSC_Client *prev;
62 * Handle for the client with the server API.
64 struct GNUNET_SERVER_Client *client_handle;
67 * Array of the types of messages this peer cares
68 * about (with "tcnt" entries). Allocated as part
69 * of this client struct, do not free!
71 const uint16_t *types;
74 * Map of peer identities to active transmission requests of this
75 * client to the peer (of type 'struct GSC_ClientActiveRequest').
77 struct GNUNET_CONTAINER_MultiHashMap *requests;
81 * Map containing all peers that this client knows we're connected to.
83 struct GNUNET_CONTAINER_MultiHashMap *connectmap;
87 * Options for messages this client cares about,
88 * see GNUNET_CORE_OPTION_ values.
93 * Number of types of incoming messages this client
94 * specifically cares about. Size of the "types" array.
102 * Head of linked list of our clients.
104 static struct GSC_Client *client_head;
107 * Tail of linked list of our clients.
109 static struct GSC_Client *client_tail;
112 * Context for notifications we need to send to our clients.
114 static struct GNUNET_SERVER_NotificationContext *notifier;
117 * Tokenizer for messages received from clients.
119 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
123 * Lookup our client struct given the server's client handle.
125 * @param client server client handle to look up
126 * @return our client handle for the client
128 static struct GSC_Client *
129 find_client (struct GNUNET_SERVER_Client *client)
131 struct GSC_Client *c;
134 while ((c != NULL) && (c->client_handle != client))
141 * Send a message to one of our clients.
143 * @param client target for the message
144 * @param msg message to transmit
145 * @param can_drop could this message be dropped if the
146 * client's queue is getting too large?
149 send_to_client (struct GSC_Client *client,
150 const struct GNUNET_MessageHeader *msg, int can_drop)
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Preparing to send %u bytes of message of type %u to client.\n",
155 (unsigned int) ntohs (msg->size),
156 (unsigned int) ntohs (msg->type));
158 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
164 * Send a message to one of our clients.
166 * @param client target for the message
167 * @param msg message to transmit
168 * @param can_drop could this message be dropped if the
169 * client's queue is getting too large?
172 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
173 const struct GNUNET_MessageHeader *msg,
176 struct GSC_Client *c;
178 c = find_client (client);
184 send_to_client (c, msg, can_drop);
189 * Test if the client is interested in messages of the given type.
191 * @param type message type
192 * @param c client to test
193 * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
196 type_match (uint16_t type, struct GSC_Client *c)
201 return GNUNET_YES; /* peer without handlers matches ALL */
202 for (i = 0; i < c->tcnt; i++)
203 if (type == c->types[i])
210 * Send a message to all of our current clients that have the right
213 * @param msg message to multicast
214 * @param can_drop can this message be discarded if the queue is too long
215 * @param options mask to use
216 * @param type type of the embedded message, 0 for none
219 send_to_all_clients (const struct GNUNET_PeerIdentity *sender,
220 const struct GNUNET_MessageHeader *msg, int can_drop,
221 int options, uint16_t type)
223 struct GSC_Client *c;
225 for (c = client_head; c != NULL; c = c->next)
227 if ((0 == (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
228 (GNUNET_YES == type_match (type, c)))
229 continue; /* not the full message, but we'd like the full one! */
230 if ((0 == (c->options & options)) && (GNUNET_YES != type_match (type, c)))
231 continue; /* neither options nor type match permit the message */
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "Sending message to client interested in messages of type %u.\n",
235 (unsigned int) type);
238 GNUNET_assert (GNUNET_YES ==
239 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
240 &sender->hashPubKey));
242 send_to_client (c, msg, can_drop);
248 * Handle CORE_INIT request.
251 * @param client new client that sent INIT
252 * @param message the 'struct InitMessage' (presumably)
255 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
256 const struct GNUNET_MessageHeader *message)
258 const struct InitMessage *im;
259 struct InitReplyMessage irm;
260 struct GSC_Client *c;
262 const uint16_t *types;
266 /* check that we don't have an entry already */
267 c = find_client (client);
271 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
274 msize = ntohs (message->size);
275 if (msize < sizeof (struct InitMessage))
278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
281 GNUNET_SERVER_notification_context_add (notifier, client);
282 im = (const struct InitMessage *) message;
283 types = (const uint16_t *) &im[1];
284 msize -= sizeof (struct InitMessage);
285 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
286 c->client_handle = client;
287 c->tcnt = msize / sizeof (uint16_t);
288 c->options = ntohl (im->options);
289 c->types = (const uint16_t *) &c[1];
291 c->connectmap = GNUNET_CONTAINER_multihashmap_create (16);
292 GNUNET_assert (GNUNET_YES ==
293 GNUNET_CONTAINER_multihashmap_put (c->connectmap,
294 &GSC_my_identity.hashPubKey,
296 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
299 wtypes = (uint16_t *) & c[1];
300 for (i = 0; i < c->tcnt; i++)
301 wtypes[i] = ntohs (types[i]);
302 GSC_TYPEMAP_add (wtypes, c->tcnt);
303 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
306 "Client connecting to core service is interested in %u message types\n",
307 (unsigned int) c->tcnt);
309 /* send init reply message */
310 irm.header.size = htons (sizeof (struct InitReplyMessage));
311 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
312 irm.reserved = htonl (0);
313 irm.my_identity = GSC_my_identity;
314 send_to_client (c, &irm.header, GNUNET_NO);
315 GSC_SESSIONS_notify_client_about_sessions (c);
316 GNUNET_SERVER_receive_done (client, GNUNET_OK);
321 * Handle CORE_SEND_REQUEST message.
324 * @param client new client that sent CORE_SEND_REQUEST
325 * @param message the 'struct SendMessageRequest' (presumably)
328 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
329 const struct GNUNET_MessageHeader *message)
331 const struct SendMessageRequest *req;
332 struct GSC_Client *c;
333 struct GSC_ClientActiveRequest *car;
335 req = (const struct SendMessageRequest *) message;
336 c = find_client (client);
339 /* client did not send INIT first! */
341 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
344 if (c->requests == NULL)
345 c->requests = GNUNET_CONTAINER_multihashmap_create (16);
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
348 "Client asked for transmission to `%s'\n",
349 GNUNET_i2s (&req->peer));
351 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
354 /* create new entry */
355 car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
356 GNUNET_assert (GNUNET_OK ==
357 GNUNET_CONTAINER_multihashmap_put (c->requests,
358 &req->peer.hashPubKey,
360 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
361 car->client_handle = c;
365 GSC_SESSIONS_dequeue_request (car);
367 car->target = req->peer;
368 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
369 car->priority = ntohl (req->priority);
370 car->msize = ntohs (req->size);
371 car->smr_id = req->smr_id;
372 car->was_solicited = GNUNET_NO;
374 memcmp (&req->peer, &GSC_my_identity,
375 sizeof (struct GNUNET_PeerIdentity)))
376 GSC_CLIENTS_solicit_request (car);
378 GSC_SESSIONS_queue_request (car);
379 GNUNET_SERVER_receive_done (client, GNUNET_OK);
384 * Closure for the 'client_tokenizer_callback'.
386 struct TokenizerContext
390 * Active request handle for the message.
392 struct GSC_ClientActiveRequest *car;
395 * Is corking allowed (set only once we have the real message).
403 * Handle CORE_SEND request.
406 * @param client the client issuing the request
407 * @param message the "struct SendMessage"
410 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
411 const struct GNUNET_MessageHeader *message)
413 const struct SendMessage *sm;
414 struct GSC_Client *c;
415 struct TokenizerContext tc;
418 msize = ntohs (message->size);
420 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
423 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
426 sm = (const struct SendMessage *) message;
427 msize -= sizeof (struct SendMessage);
428 GNUNET_break (0 == ntohl (sm->reserved));
429 c = find_client (client);
432 /* client did not send INIT first! */
434 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
438 GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
441 /* Must have been that we first approved the request, then got disconnected
442 * (which triggered removal of the 'car') and now the client gives us a message
443 * just *before* the client learns about the disconnect. Theoretically, we
444 * might also now be *again* connected. So this can happen (but should be
445 * rare). If it does happen, the message is discarded. */
446 GNUNET_STATISTICS_update (GSC_stats,
448 ("# messages discarded (session disconnected)"),
450 GNUNET_SERVER_receive_done (client, GNUNET_OK);
453 GNUNET_assert (GNUNET_YES ==
454 GNUNET_CONTAINER_multihashmap_remove (c->requests,
455 &sm->peer.hashPubKey,
457 tc.cork = ntohl (sm->cork);
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Client asked for transmission of %u bytes to `%s' %s\n", msize,
461 GNUNET_i2s (&sm->peer), tc.cork ? "now" : "");
463 GNUNET_SERVER_mst_receive (client_mst, &tc, (const char *) &sm[1], msize,
464 GNUNET_YES, GNUNET_NO);
466 memcmp (&tc.car->target, &GSC_my_identity,
467 sizeof (struct GNUNET_PeerIdentity)))
468 GSC_SESSIONS_dequeue_request (tc.car);
469 GNUNET_free (tc.car);
470 GNUNET_SERVER_receive_done (client, GNUNET_OK);
475 * Functions with this signature are called whenever a complete
476 * message is received by the tokenizer. Used by the 'client_mst' for
477 * dispatching messages from clients to either the SESSION subsystem
478 * or other CLIENT (for loopback).
481 * @param client reservation request ('struct GSC_ClientActiveRequest')
482 * @param message the actual message
485 client_tokenizer_callback (void *cls, void *client,
486 const struct GNUNET_MessageHeader *message)
488 struct TokenizerContext *tc = client;
489 struct GSC_ClientActiveRequest *car = tc->car;
492 memcmp (&car->target, &GSC_my_identity,
493 sizeof (struct GNUNET_PeerIdentity)))
496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497 "Delivering message of type %u to myself\n",
498 ntohs (message->type));
500 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
501 ntohs (message->size),
502 GNUNET_CORE_OPTION_SEND_FULL_INBOUND |
503 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
504 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
505 sizeof (struct GNUNET_MessageHeader),
506 GNUNET_CORE_OPTION_SEND_HDR_INBOUND |
507 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 "Delivering message of type %u to %s\n", ntohs (message->type),
514 GNUNET_i2s (&car->target));
516 GSC_SESSIONS_transmit (car, message, tc->cork);
522 * Free client request records.
525 * @param key identity of peer for which this is an active request
526 * @param value the 'struct GSC_ClientActiveRequest' to free
527 * @return GNUNET_YES (continue iteration)
530 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
533 struct GSC_ClientActiveRequest *car = value;
535 GNUNET_assert (GNUNET_YES ==
536 GNUNET_CONTAINER_multihashmap_remove (car->
537 client_handle->requests,
538 &car->target.hashPubKey,
540 GSC_SESSIONS_dequeue_request (car);
547 * A client disconnected, clean up.
550 * @param client identification of the client
553 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
555 struct GSC_Client *c;
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561 "Client %p has disconnected from core service.\n", client);
563 c = find_client (client);
565 return; /* client never sent INIT */
566 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
567 if (c->requests != NULL)
569 GNUNET_CONTAINER_multihashmap_iterate (c->requests,
570 &destroy_active_client_request,
572 GNUNET_CONTAINER_multihashmap_destroy (c->requests);
575 GNUNET_CONTAINER_multihashmap_destroy (c->connectmap);
577 GSC_TYPEMAP_remove (c->types, c->tcnt);
583 * Tell a client that we are ready to receive the message.
585 * @param car request that is now ready; the responsibility
586 * for the handle remains shared between CLIENTS
587 * and SESSIONS after this call.
590 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
592 struct GSC_Client *c;
593 struct SendMessageReady smr;
595 c = car->client_handle;
596 smr.header.size = htons (sizeof (struct SendMessageReady));
597 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
598 smr.size = htons (car->msize);
599 smr.smr_id = car->smr_id;
600 smr.peer = car->target;
602 GNUNET_assert (GNUNET_YES ==
603 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
607 send_to_client (c, &smr.header, GNUNET_NO);
612 * Tell a client that we will never be ready to receive the
613 * given message in time (disconnect or timeout).
615 * @param car request that now permanently failed; the
616 * responsibility for the handle is now returned
617 * to CLIENTS (SESSIONS is done with it).
620 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
622 GNUNET_assert (GNUNET_YES ==
623 GNUNET_CONTAINER_multihashmap_remove (car->
624 client_handle->requests,
625 &car->target.hashPubKey,
632 * Notify a particular client about a change to existing connection to
633 * one of our neighbours (check if the client is interested). Called
634 * from 'GSC_SESSIONS_notify_client_about_sessions'.
636 * @param client client to notify
637 * @param neighbour identity of the neighbour that changed status
638 * @param atsi performance information about neighbour
639 * @param atsi_count number of entries in 'ats' array
640 * @param tmap_old previous type map for the neighbour, NULL for disconnect
641 * @param tmap_new updated type map for the neighbour, NULL for disconnect
642 * @param is_new GNUNET_YES if this is a completely new neighbour
645 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
646 const struct GNUNET_PeerIdentity
648 const struct GNUNET_ATS_Information
649 *atsi, unsigned int atsi_count,
650 const struct GSC_TypeMap *tmap_old,
651 const struct GSC_TypeMap *tmap_new)
653 struct ConnectNotifyMessage *cnm;
655 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
656 struct GNUNET_ATS_Information *a;
657 struct DisconnectNotifyMessage dcm;
661 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
662 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
663 if (old_match == new_match)
665 GNUNET_assert (old_match ==
666 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
667 &neighbour->hashPubKey));
668 return; /* no change */
670 if (old_match == GNUNET_NO)
674 GNUNET_assert (GNUNET_NO ==
675 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
676 &neighbour->hashPubKey));
677 GNUNET_assert (GNUNET_YES ==
678 GNUNET_CONTAINER_multihashmap_put (client->connectmap,
679 &neighbour->hashPubKey,
681 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
684 sizeof (struct ConnectNotifyMessage) +
685 (atsi_count) * sizeof (struct GNUNET_ATS_Information);
686 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
689 /* recovery strategy: throw away performance data */
691 size = sizeof (struct ConnectNotifyMessage);
693 cnm = (struct ConnectNotifyMessage *) buf;
694 cnm->header.size = htons (size);
695 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
696 cnm->ats_count = htonl (atsi_count);
697 a = (struct GNUNET_ATS_Information *) &cnm[1];
698 memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
703 cnm->peer = *neighbour;
704 send_to_client (client, &cnm->header, GNUNET_NO);
708 /* send disconnect */
710 GNUNET_assert (GNUNET_YES ==
711 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
712 &neighbour->hashPubKey));
713 GNUNET_assert (GNUNET_YES ==
714 GNUNET_CONTAINER_multihashmap_remove (client->connectmap,
715 &neighbour->hashPubKey,
718 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
719 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
720 dcm.reserved = htonl (0);
721 dcm.peer = *neighbour;
722 send_to_client (client, &dcm.header, GNUNET_NO);
728 * Notify all clients about a change to existing session.
729 * Called from SESSIONS whenever there is a change in sessions
730 * or types processed by the respective peer.
732 * @param neighbour identity of the neighbour that changed status
733 * @param atsi performance information about neighbour
734 * @param atsi_count number of entries in 'ats' array
735 * @param tmap_old previous type map for the neighbour, NULL for disconnect
736 * @param tmap_new updated type map for the neighbour, NULL for disconnect
739 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity
741 const struct GNUNET_ATS_Information
742 *atsi, unsigned int atsi_count,
743 const struct GSC_TypeMap *tmap_old,
744 const struct GSC_TypeMap *tmap_new)
746 struct GSC_Client *c;
748 for (c = client_head; c != NULL; c = c->next)
749 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi, atsi_count,
755 * Deliver P2P message to interested clients. Caller must have checked
756 * that the sending peer actually lists the given message type as one
759 * @param sender peer who sent us the message
760 * @param atsi performance information about neighbour
761 * @param atsi_count number of entries in 'ats' array
762 * @param msg the message
763 * @param msize number of bytes to transmit
764 * @param options options for checking which clients should
765 * receive the message
768 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
769 const struct GNUNET_ATS_Information *atsi,
770 unsigned int atsi_count,
771 const struct GNUNET_MessageHeader *msg,
772 uint16_t msize, int options)
775 msize + sizeof (struct NotifyTrafficMessage) +
776 atsi_count * sizeof (struct GNUNET_ATS_Information);
778 struct NotifyTrafficMessage *ntm;
779 struct GNUNET_ATS_Information *a;
783 GNUNET_snprintf (buf, sizeof (buf),
784 gettext_noop ("# bytes of messages of type %u received"),
785 (unsigned int) ntohs (msg->type));
786 GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO);
788 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
791 /* recovery strategy: throw performance data away... */
793 size = msize + sizeof (struct NotifyTrafficMessage);
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797 "Core service passes message from `%4s' of type %u to client.\n",
798 GNUNET_i2s (sender), (unsigned int) ntohs (msg->type));
800 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
801 ntm = (struct NotifyTrafficMessage *) buf;
802 ntm->header.size = htons (size);
803 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
804 ntm->ats_count = htonl (atsi_count);
807 memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
808 a[atsi_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
809 a[atsi_count].value = htonl (0);
810 memcpy (&a[atsi_count + 1], msg, msize);
811 send_to_all_clients (sender, &ntm->header, GNUNET_YES, options,
817 * Initialize clients subsystem.
819 * @param server handle to server clients connect to
822 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
824 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
825 {&handle_client_init, NULL,
826 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
827 {&GSC_SESSIONS_handle_client_iterate_peers, NULL,
828 GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
829 sizeof (struct GNUNET_MessageHeader)},
830 {&GSC_SESSIONS_handle_client_have_peer, NULL,
831 GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
832 sizeof (struct GNUNET_MessageHeader) +
833 sizeof (struct GNUNET_PeerIdentity)},
834 {&handle_client_send_request, NULL,
835 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
836 sizeof (struct SendMessageRequest)},
837 {&handle_client_send, NULL,
838 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
842 /* setup notification */
843 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
845 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
846 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
847 GNUNET_SERVER_add_handlers (server, handlers);
852 * Shutdown clients subsystem.
857 struct GSC_Client *c;
859 while (NULL != (c = client_head))
860 handle_client_disconnect (NULL, c->client_handle);
861 if (NULL != notifier)
863 GNUNET_SERVER_notification_context_destroy (notifier);
866 GNUNET_SERVER_mst_destroy (client_mst);
870 /* end of gnunet-service-core_clients.c */