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"
38 * How many messages do we queue up at most for optional
39 * notifications to a client? (this can cause notifications
40 * about outgoing messages to be dropped).
42 #define MAX_NOTIFY_QUEUE 1024
46 * Data structure for each client connected to the core service.
51 * Clients are kept in a linked list.
53 struct GSC_Client *next;
56 * Clients are kept in a linked list.
58 struct GSC_Client *prev;
61 * Handle for the client with the server API.
63 struct GNUNET_SERVER_Client *client_handle;
66 * Array of the types of messages this peer cares
67 * about (with "tcnt" entries). Allocated as part
68 * of this client struct, do not free!
70 const uint16_t *types;
73 * Map of peer identities to active transmission requests of this
74 * client to the peer (of type 'struct GSC_ClientActiveRequest').
76 struct GNUNET_CONTAINER_MultiHashMap *requests;
79 * Map containing all peers that this client knows we're connected to.
81 struct GNUNET_CONTAINER_MultiHashMap *connectmap;
84 * Options for messages this client cares about,
85 * see GNUNET_CORE_OPTION_ values.
90 * Number of types of incoming messages this client
91 * specifically cares about. Size of the "types" array.
99 * Head of linked list of our clients.
101 static struct GSC_Client *client_head;
104 * Tail of linked list of our clients.
106 static struct GSC_Client *client_tail;
109 * Context for notifications we need to send to our clients.
111 static struct GNUNET_SERVER_NotificationContext *notifier;
114 * Tokenizer for messages received from clients.
116 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
120 * Lookup our client struct given the server's client handle.
122 * @param client server client handle to look up
123 * @return our client handle for the client
125 static struct GSC_Client *
126 find_client (struct GNUNET_SERVER_Client *client)
128 struct GSC_Client *c;
131 while ((c != NULL) && (c->client_handle != client))
138 * Send a message to one of our clients.
140 * @param client target for the message
141 * @param msg message to transmit
142 * @param can_drop could this message be dropped if the
143 * client's queue is getting too large?
146 send_to_client (struct GSC_Client *client,
147 const struct GNUNET_MessageHeader *msg, int can_drop)
150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
151 "Preparing to send %u bytes of message of type %u to client.\n",
152 (unsigned int) ntohs (msg->size),
153 (unsigned int) ntohs (msg->type));
155 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
161 * Send a message to one of our clients.
163 * @param client target for the message
164 * @param msg message to transmit
165 * @param can_drop could this message be dropped if the
166 * client's queue is getting too large?
169 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
170 const struct GNUNET_MessageHeader *msg,
173 struct GSC_Client *c;
175 c = find_client (client);
181 send_to_client (c, msg, can_drop);
186 * Test if the client is interested in messages of the given type.
188 * @param type message type
189 * @param c client to test
190 * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
193 type_match (uint16_t type, struct GSC_Client *c)
198 return GNUNET_YES; /* peer without handlers matches ALL */
199 for (i = 0; i < c->tcnt; i++)
200 if (type == c->types[i])
207 * Send a message to all of our current clients that have the right
210 * @param msg message to multicast
211 * @param can_drop can this message be discarded if the queue is too long
212 * @param options mask to use
213 * @param type type of the embedded message, 0 for none
216 send_to_all_clients (const struct GNUNET_PeerIdentity *sender,
217 const struct GNUNET_MessageHeader *msg, int can_drop,
218 int options, uint16_t type)
220 struct GSC_Client *c;
222 for (c = client_head; c != NULL; c = c->next)
224 if ((0 == (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
225 (GNUNET_YES == type_match (type, c)))
226 continue; /* not the full message, but we'd like the full one! */
227 if ((0 == (c->options & options)) && (GNUNET_YES != type_match (type, c)))
228 continue; /* neither options nor type match permit the message */
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Sending message to client interested in messages of type %u.\n",
232 (unsigned int) type);
234 GNUNET_assert (GNUNET_YES ==
235 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
236 &sender->hashPubKey));
237 send_to_client (c, msg, can_drop);
243 * Handle CORE_INIT request.
246 * @param client new client that sent INIT
247 * @param message the 'struct InitMessage' (presumably)
250 handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
251 const struct GNUNET_MessageHeader *message)
253 const struct InitMessage *im;
254 struct InitReplyMessage irm;
255 struct GSC_Client *c;
257 const uint16_t *types;
261 /* check that we don't have an entry already */
262 c = find_client (client);
266 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
269 msize = ntohs (message->size);
270 if (msize < sizeof (struct InitMessage))
273 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
276 GNUNET_SERVER_notification_context_add (notifier, client);
277 im = (const struct InitMessage *) message;
278 types = (const uint16_t *) &im[1];
279 msize -= sizeof (struct InitMessage);
280 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
281 c->client_handle = client;
282 c->tcnt = msize / sizeof (uint16_t);
283 c->options = ntohl (im->options);
284 c->types = (const uint16_t *) &c[1];
285 c->connectmap = GNUNET_CONTAINER_multihashmap_create (16);
286 GNUNET_assert (GNUNET_YES ==
287 GNUNET_CONTAINER_multihashmap_put (c->connectmap,
288 &GSC_my_identity.hashPubKey,
290 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
291 wtypes = (uint16_t *) & c[1];
292 for (i = 0; i < c->tcnt; i++)
293 wtypes[i] = ntohs (types[i]);
294 GSC_TYPEMAP_add (wtypes, c->tcnt);
295 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298 "Client connecting to core service is interested in %u message types\n",
299 (unsigned int) c->tcnt);
301 /* send init reply message */
302 irm.header.size = htons (sizeof (struct InitReplyMessage));
303 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
304 irm.reserved = htonl (0);
305 irm.my_identity = GSC_my_identity;
306 send_to_client (c, &irm.header, GNUNET_NO);
307 GSC_SESSIONS_notify_client_about_sessions (c);
308 GNUNET_SERVER_receive_done (client, GNUNET_OK);
313 * Handle CORE_SEND_REQUEST message.
316 * @param client new client that sent CORE_SEND_REQUEST
317 * @param message the 'struct SendMessageRequest' (presumably)
320 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
321 const struct GNUNET_MessageHeader *message)
323 const struct SendMessageRequest *req;
324 struct GSC_Client *c;
325 struct GSC_ClientActiveRequest *car;
328 req = (const struct SendMessageRequest *) message;
329 c = find_client (client);
332 /* client did not send INIT first! */
334 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
337 if (c->requests == NULL)
338 c->requests = GNUNET_CONTAINER_multihashmap_create (16);
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341 "Client asked for transmission to `%s'\n",
342 GNUNET_i2s (&req->peer));
345 memcmp (&req->peer, &GSC_my_identity,
346 sizeof (struct GNUNET_PeerIdentity)));
347 if ( (! is_loopback) &&
349 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
350 &req->peer.hashPubKey)) )
352 /* neighbour must have disconnected since request was issued,
353 * ignore (client will realize it once it processes the
354 * disconnect notification) */
355 GNUNET_STATISTICS_update (GSC_stats,
357 ("# send requests dropped (disconnected)"), 1,
359 GNUNET_SERVER_receive_done (client, GNUNET_OK);
363 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
366 /* create new entry */
367 car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
368 GNUNET_assert (GNUNET_OK ==
369 GNUNET_CONTAINER_multihashmap_put (c->requests,
370 &req->peer.hashPubKey,
372 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
373 car->client_handle = c;
377 GSC_SESSIONS_dequeue_request (car);
379 car->target = req->peer;
380 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
381 car->priority = ntohl (req->priority);
382 car->msize = ntohs (req->size);
383 car->smr_id = req->smr_id;
384 car->was_solicited = GNUNET_NO;
387 /* loopback, satisfy immediately */
388 GSC_CLIENTS_solicit_request (car);
389 GNUNET_SERVER_receive_done (client, GNUNET_OK);
392 GSC_SESSIONS_queue_request (car);
393 GNUNET_SERVER_receive_done (client, GNUNET_OK);
398 * Closure for the 'client_tokenizer_callback'.
400 struct TokenizerContext
404 * Active request handle for the message.
406 struct GSC_ClientActiveRequest *car;
409 * Is corking allowed (set only once we have the real message).
417 * Handle CORE_SEND request.
420 * @param client the client issuing the request
421 * @param message the "struct SendMessage"
424 handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
425 const struct GNUNET_MessageHeader *message)
427 const struct SendMessage *sm;
428 struct GSC_Client *c;
429 struct TokenizerContext tc;
432 msize = ntohs (message->size);
434 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
437 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
440 sm = (const struct SendMessage *) message;
441 msize -= sizeof (struct SendMessage);
442 GNUNET_break (0 == ntohl (sm->reserved));
443 c = find_client (client);
446 /* client did not send INIT first! */
448 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
452 GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
455 /* Must have been that we first approved the request, then got disconnected
456 * (which triggered removal of the 'car') and now the client gives us a message
457 * just *before* the client learns about the disconnect. Theoretically, we
458 * might also now be *again* connected. So this can happen (but should be
459 * rare). If it does happen, the message is discarded. */
460 GNUNET_STATISTICS_update (GSC_stats,
462 ("# messages discarded (session disconnected)"),
464 GNUNET_SERVER_receive_done (client, GNUNET_OK);
467 GNUNET_assert (GNUNET_YES ==
468 GNUNET_CONTAINER_multihashmap_remove (c->requests,
469 &sm->peer.hashPubKey,
471 tc.cork = ntohl (sm->cork);
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "Client asked for transmission of %u bytes to `%s' %s\n", msize,
475 GNUNET_i2s (&sm->peer), tc.cork ? "now" : "");
477 GNUNET_SERVER_mst_receive (client_mst, &tc, (const char *) &sm[1], msize,
478 GNUNET_YES, GNUNET_NO);
480 memcmp (&tc.car->target, &GSC_my_identity,
481 sizeof (struct GNUNET_PeerIdentity)))
482 GSC_SESSIONS_dequeue_request (tc.car);
483 GNUNET_free (tc.car);
484 GNUNET_SERVER_receive_done (client, GNUNET_OK);
489 * Functions with this signature are called whenever a complete
490 * message is received by the tokenizer. Used by the 'client_mst' for
491 * dispatching messages from clients to either the SESSION subsystem
492 * or other CLIENT (for loopback).
495 * @param client reservation request ('struct GSC_ClientActiveRequest')
496 * @param message the actual message
499 client_tokenizer_callback (void *cls, void *client,
500 const struct GNUNET_MessageHeader *message)
502 struct TokenizerContext *tc = client;
503 struct GSC_ClientActiveRequest *car = tc->car;
506 memcmp (&car->target, &GSC_my_identity,
507 sizeof (struct GNUNET_PeerIdentity)))
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511 "Delivering message of type %u to myself\n",
512 ntohs (message->type));
514 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
515 ntohs (message->size),
516 GNUNET_CORE_OPTION_SEND_FULL_INBOUND |
517 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
518 GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message,
519 sizeof (struct GNUNET_MessageHeader),
520 GNUNET_CORE_OPTION_SEND_HDR_INBOUND |
521 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527 "Delivering message of type %u to %s\n", ntohs (message->type),
528 GNUNET_i2s (&car->target));
530 GSC_SESSIONS_transmit (car, message, tc->cork);
536 * Free client request records.
539 * @param key identity of peer for which this is an active request
540 * @param value the 'struct GSC_ClientActiveRequest' to free
541 * @return GNUNET_YES (continue iteration)
544 destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
547 struct GSC_ClientActiveRequest *car = value;
549 GNUNET_assert (GNUNET_YES ==
550 GNUNET_CONTAINER_multihashmap_remove (car->
551 client_handle->requests,
552 &car->target.hashPubKey,
554 GSC_SESSIONS_dequeue_request (car);
561 * A client disconnected, clean up.
564 * @param client identification of the client
567 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
569 struct GSC_Client *c;
574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
575 "Client %p has disconnected from core service.\n", client);
577 c = find_client (client);
579 return; /* client never sent INIT */
580 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
581 if (c->requests != NULL)
583 GNUNET_CONTAINER_multihashmap_iterate (c->requests,
584 &destroy_active_client_request,
586 GNUNET_CONTAINER_multihashmap_destroy (c->requests);
588 GNUNET_CONTAINER_multihashmap_destroy (c->connectmap);
589 c->connectmap = NULL;
590 GSC_TYPEMAP_remove (c->types, c->tcnt);
596 * Tell a client that we are ready to receive the message.
598 * @param car request that is now ready; the responsibility
599 * for the handle remains shared between CLIENTS
600 * and SESSIONS after this call.
603 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
605 struct GSC_Client *c;
606 struct SendMessageReady smr;
608 c = car->client_handle;
610 GNUNET_CONTAINER_multihashmap_contains (c->connectmap,
614 /* connection has gone down since, drop request */
616 memcmp (&car->target, &GSC_my_identity,
617 sizeof (struct GNUNET_PeerIdentity)));
618 GSC_SESSIONS_dequeue_request (car);
619 GSC_CLIENTS_reject_request (car);
622 smr.header.size = htons (sizeof (struct SendMessageReady));
623 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
624 smr.size = htons (car->msize);
625 smr.smr_id = car->smr_id;
626 smr.peer = car->target;
627 send_to_client (c, &smr.header, GNUNET_NO);
632 * Tell a client that we will never be ready to receive the
633 * given message in time (disconnect or timeout).
635 * @param car request that now permanently failed; the
636 * responsibility for the handle is now returned
637 * to CLIENTS (SESSIONS is done with it).
640 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
642 GNUNET_assert (GNUNET_YES ==
643 GNUNET_CONTAINER_multihashmap_remove (car->
644 client_handle->requests,
645 &car->target.hashPubKey,
652 * Notify a particular client about a change to existing connection to
653 * one of our neighbours (check if the client is interested). Called
654 * from 'GSC_SESSIONS_notify_client_about_sessions'.
656 * @param client client to notify
657 * @param neighbour identity of the neighbour that changed status
658 * @param atsi performance information about neighbour
659 * @param atsi_count number of entries in 'ats' array
660 * @param tmap_old previous type map for the neighbour, NULL for disconnect
661 * @param tmap_new updated type map for the neighbour, NULL for disconnect
662 * @param is_new GNUNET_YES if this is a completely new neighbour
665 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
666 const struct GNUNET_PeerIdentity
668 const struct GNUNET_ATS_Information
669 *atsi, unsigned int atsi_count,
670 const struct GSC_TypeMap *tmap_old,
671 const struct GSC_TypeMap *tmap_new)
673 struct ConnectNotifyMessage *cnm;
675 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
676 struct GNUNET_ATS_Information *a;
677 struct DisconnectNotifyMessage dcm;
681 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
682 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
683 if (old_match == new_match)
685 GNUNET_assert (old_match ==
686 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
687 &neighbour->hashPubKey));
688 return; /* no change */
690 if (old_match == GNUNET_NO)
693 GNUNET_assert (GNUNET_NO ==
694 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
695 &neighbour->hashPubKey));
696 GNUNET_assert (GNUNET_YES ==
697 GNUNET_CONTAINER_multihashmap_put (client->connectmap,
698 &neighbour->hashPubKey,
700 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
702 sizeof (struct ConnectNotifyMessage) +
703 (atsi_count) * sizeof (struct GNUNET_ATS_Information);
704 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
707 /* recovery strategy: throw away performance data */
709 size = sizeof (struct ConnectNotifyMessage);
711 cnm = (struct ConnectNotifyMessage *) buf;
712 cnm->header.size = htons (size);
713 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
714 cnm->ats_count = htonl (atsi_count);
715 a = (struct GNUNET_ATS_Information *) &cnm[1];
716 memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
721 cnm->peer = *neighbour;
722 send_to_client (client, &cnm->header, GNUNET_NO);
726 /* send disconnect */
727 GNUNET_assert (GNUNET_YES ==
728 GNUNET_CONTAINER_multihashmap_contains (client->connectmap,
729 &neighbour->hashPubKey));
730 GNUNET_assert (GNUNET_YES ==
731 GNUNET_CONTAINER_multihashmap_remove (client->connectmap,
732 &neighbour->hashPubKey,
734 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
735 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
736 dcm.reserved = htonl (0);
737 dcm.peer = *neighbour;
738 send_to_client (client, &dcm.header, GNUNET_NO);
744 * Notify all clients about a change to existing session.
745 * Called from SESSIONS whenever there is a change in sessions
746 * or types processed by the respective peer.
748 * @param neighbour identity of the neighbour that changed status
749 * @param atsi performance information about neighbour
750 * @param atsi_count number of entries in 'ats' array
751 * @param tmap_old previous type map for the neighbour, NULL for disconnect
752 * @param tmap_new updated type map for the neighbour, NULL for disconnect
755 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity
757 const struct GNUNET_ATS_Information
758 *atsi, unsigned int atsi_count,
759 const struct GSC_TypeMap *tmap_old,
760 const struct GSC_TypeMap *tmap_new)
762 struct GSC_Client *c;
764 for (c = client_head; c != NULL; c = c->next)
765 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi, atsi_count,
771 * Deliver P2P message to interested clients. Caller must have checked
772 * that the sending peer actually lists the given message type as one
775 * @param sender peer who sent us the message
776 * @param atsi performance information about neighbour
777 * @param atsi_count number of entries in 'ats' array
778 * @param msg the message
779 * @param msize number of bytes to transmit
780 * @param options options for checking which clients should
781 * receive the message
784 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
785 const struct GNUNET_ATS_Information *atsi,
786 unsigned int atsi_count,
787 const struct GNUNET_MessageHeader *msg,
788 uint16_t msize, int options)
791 msize + sizeof (struct NotifyTrafficMessage) +
792 atsi_count * sizeof (struct GNUNET_ATS_Information);
794 struct NotifyTrafficMessage *ntm;
795 struct GNUNET_ATS_Information *a;
799 GNUNET_snprintf (buf, sizeof (buf),
800 gettext_noop ("# bytes of messages of type %u received"),
801 (unsigned int) ntohs (msg->type));
802 GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO);
804 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
807 /* recovery strategy: throw performance data away... */
809 size = msize + sizeof (struct NotifyTrafficMessage);
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813 "Core service passes message from `%4s' of type %u to client.\n",
814 GNUNET_i2s (sender), (unsigned int) ntohs (msg->type));
816 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
817 ntm = (struct NotifyTrafficMessage *) buf;
818 ntm->header.size = htons (size);
819 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
820 ntm->ats_count = htonl (atsi_count);
823 memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
824 a[atsi_count].type = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
825 a[atsi_count].value = htonl (0);
826 memcpy (&a[atsi_count + 1], msg, msize);
827 send_to_all_clients (sender, &ntm->header, GNUNET_YES, options,
833 * Initialize clients subsystem.
835 * @param server handle to server clients connect to
838 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
840 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
841 {&handle_client_init, NULL,
842 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
843 {&GSC_SESSIONS_handle_client_iterate_peers, NULL,
844 GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
845 sizeof (struct GNUNET_MessageHeader)},
846 {&GSC_SESSIONS_handle_client_have_peer, NULL,
847 GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
848 sizeof (struct GNUNET_MessageHeader) +
849 sizeof (struct GNUNET_PeerIdentity)},
850 {&handle_client_send_request, NULL,
851 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
852 sizeof (struct SendMessageRequest)},
853 {&handle_client_send, NULL,
854 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
858 /* setup notification */
859 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
861 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
862 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
863 GNUNET_SERVER_add_handlers (server, handlers);
868 * Shutdown clients subsystem.
873 struct GSC_Client *c;
875 while (NULL != (c = client_head))
876 handle_client_disconnect (NULL, c->client_handle);
877 if (NULL != notifier)
879 GNUNET_SERVER_notification_context_destroy (notifier);
882 GNUNET_SERVER_mst_destroy (client_mst);
886 /* end of gnunet-service-core_clients.c */