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 @e 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_MultiPeerMap *requests;
79 * Map containing all peers that this client knows we're connected to.
81 struct GNUNET_CONTAINER_MultiPeerMap *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 @e types array.
99 * Big "or" of all client options.
101 static uint32_t all_client_options;
104 * Head of linked list of our clients.
106 static struct GSC_Client *client_head;
109 * Tail of linked list of our clients.
111 static struct GSC_Client *client_tail;
114 * Context for notifications we need to send to our clients.
116 static struct GNUNET_SERVER_NotificationContext *notifier;
119 * Tokenizer for messages received from clients.
121 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
125 * Lookup our client struct given the server's client handle.
127 * @param client server client handle to look up
128 * @return our client handle for the client
130 static struct GSC_Client *
131 find_client (struct GNUNET_SERVER_Client *client)
133 struct GSC_Client *c;
136 while ((c != NULL) && (c->client_handle != client))
143 * Send a message to one of our clients.
145 * @param client target for the message
146 * @param msg message to transmit
147 * @param can_drop could this message be dropped if the
148 * client's queue is getting too large?
151 send_to_client (struct GSC_Client *client,
152 const struct GNUNET_MessageHeader *msg, int can_drop)
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "Preparing to send %u bytes of message of type %u to client.\n",
156 (unsigned int) ntohs (msg->size),
157 (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 @a 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 partner origin (or destination) of the message (used to check that this peer is
214 * known to be connected to the respective client)
215 * @param msg message to multicast
216 * @param can_drop can this message be discarded if the queue is too long
217 * @param options mask to use
218 * @param type type of the embedded message, 0 for none
221 send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
222 const struct GNUNET_MessageHeader *msg, int can_drop,
223 uint32_t options, uint16_t type)
225 struct GSC_Client *c;
228 for (c = client_head; NULL != c; c = c->next)
230 tm = type_match (type, c);
231 if (! ( (0 != (c->options & options)) ||
232 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
233 (GNUNET_YES == tm) ) ) )
234 continue; /* neither options nor type match permit the message */
235 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
236 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
237 (GNUNET_YES == tm) ) )
239 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
240 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
246 (unsigned int) type);
247 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
248 (GNUNET_YES != tm) ||
250 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
252 send_to_client (c, msg, can_drop);
258 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
261 * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
262 * @param message the `struct InitMessage` (presumably)
265 handle_client_init (void *cls,
266 struct GNUNET_SERVER_Client *client,
267 const struct GNUNET_MessageHeader *message)
269 const struct InitMessage *im;
270 struct InitReplyMessage irm;
271 struct GSC_Client *c;
273 const uint16_t *types;
277 /* check that we don't have an entry already */
278 c = find_client (client);
282 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
285 msize = ntohs (message->size);
286 if (msize < sizeof (struct InitMessage))
289 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
292 GNUNET_SERVER_notification_context_add (notifier, client);
293 im = (const struct InitMessage *) message;
294 types = (const uint16_t *) &im[1];
295 msize -= sizeof (struct InitMessage);
296 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
297 c->client_handle = client;
298 c->tcnt = msize / sizeof (uint16_t);
299 c->options = ntohl (im->options);
300 all_client_options |= c->options;
301 c->types = (const uint16_t *) &c[1];
302 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
303 GNUNET_assert (GNUNET_YES ==
304 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
308 wtypes = (uint16_t *) & c[1];
309 for (i = 0; i < c->tcnt; i++)
310 wtypes[i] = ntohs (types[i]);
311 GSC_TYPEMAP_add (wtypes, c->tcnt);
312 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314 "Client connecting to core service is interested in %u message types\n",
315 (unsigned int) c->tcnt);
316 /* send init reply message */
317 irm.header.size = htons (sizeof (struct InitReplyMessage));
318 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
319 irm.reserved = htonl (0);
320 irm.my_identity = GSC_my_identity;
321 send_to_client (c, &irm.header, GNUNET_NO);
322 GSC_SESSIONS_notify_client_about_sessions (c);
323 GNUNET_SERVER_receive_done (client, GNUNET_OK);
328 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
331 * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
332 * @param message the `struct SendMessageRequest` (presumably)
335 handle_client_send_request (void *cls,
336 struct GNUNET_SERVER_Client *client,
337 const struct GNUNET_MessageHeader *message)
339 const struct SendMessageRequest *req;
340 struct GSC_Client *c;
341 struct GSC_ClientActiveRequest *car;
344 req = (const struct SendMessageRequest *) message;
345 c = find_client (client);
348 /* client did not send INIT first! */
350 GNUNET_SERVER_receive_done (client,
354 if (NULL == c->requests)
355 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
358 "Client asked for transmission to `%s'\n",
359 GNUNET_i2s (&req->peer));
364 sizeof (struct GNUNET_PeerIdentity)));
365 if ((! is_loopback) &&
367 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
370 /* neighbour must have disconnected since request was issued,
371 * ignore (client will realize it once it processes the
372 * disconnect notification) */
373 GNUNET_STATISTICS_update (GSC_stats,
375 ("# send requests dropped (disconnected)"), 1,
377 GNUNET_SERVER_receive_done (client,
382 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
386 /* create new entry */
387 car = GNUNET_new (struct GSC_ClientActiveRequest);
388 GNUNET_assert (GNUNET_OK ==
389 GNUNET_CONTAINER_multipeermap_put (c->requests,
392 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
393 car->client_handle = c;
397 /* dequeue and recycle memory from pending request, there can only
398 be at most one per client and peer */
399 GSC_SESSIONS_dequeue_request (car);
401 car->target = req->peer;
402 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
403 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
404 car->msize = ntohs (req->size);
405 car->smr_id = req->smr_id;
406 car->was_solicited = GNUNET_NO;
409 /* loopback, satisfy immediately */
410 GSC_CLIENTS_solicit_request (car);
411 GNUNET_SERVER_receive_done (client, GNUNET_OK);
414 GSC_SESSIONS_queue_request (car);
415 GNUNET_SERVER_receive_done (client, GNUNET_OK);
420 * Closure for the #client_tokenizer_callback().
422 struct TokenizerContext
426 * Active request handle for the message.
428 struct GSC_ClientActiveRequest *car;
431 * How important is this message.
433 enum GNUNET_CORE_Priority priority;
436 * Is corking allowed (set only once we have the real message).
444 * Handle CORE_SEND request.
447 * @param client the client issuing the request
448 * @param message the `struct SendMessage`
451 handle_client_send (void *cls,
452 struct GNUNET_SERVER_Client *client,
453 const struct GNUNET_MessageHeader *message)
455 const struct SendMessage *sm;
456 struct GSC_Client *c;
457 struct TokenizerContext tc;
460 msize = ntohs (message->size);
462 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
465 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
468 sm = (const struct SendMessage *) message;
469 msize -= sizeof (struct SendMessage);
470 GNUNET_break (0 == ntohl (sm->reserved));
471 c = find_client (client);
474 /* client did not send INIT first! */
476 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
480 GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
483 /* Must have been that we first approved the request, then got disconnected
484 * (which triggered removal of the 'car') and now the client gives us a message
485 * just *before* the client learns about the disconnect. Theoretically, we
486 * might also now be *again* connected. So this can happen (but should be
487 * rare). If it does happen, the message is discarded. */
488 GNUNET_STATISTICS_update (GSC_stats,
490 ("# messages discarded (session disconnected)"),
492 GNUNET_SERVER_receive_done (client, GNUNET_OK);
495 GNUNET_assert (GNUNET_YES ==
496 GNUNET_CONTAINER_multipeermap_remove (c->requests,
499 tc.cork = ntohl (sm->cork);
500 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502 "Client asked for transmission of %u bytes to `%s' %s\n",
504 GNUNET_i2s (&sm->peer), tc.cork ? "now" : "");
505 GNUNET_SERVER_mst_receive (client_mst, &tc,
506 (const char *) &sm[1], msize,
507 GNUNET_YES, GNUNET_NO);
509 memcmp (&tc.car->target, &GSC_my_identity,
510 sizeof (struct GNUNET_PeerIdentity)))
511 GSC_SESSIONS_dequeue_request (tc.car);
512 GNUNET_free (tc.car);
513 GNUNET_SERVER_receive_done (client, GNUNET_OK);
518 * Functions with this signature are called whenever a complete
519 * message is received by the tokenizer. Used by the 'client_mst' for
520 * dispatching messages from clients to either the SESSION subsystem
521 * or other CLIENT (for loopback).
524 * @param client reservation request (`struct GSC_ClientActiveRequest`)
525 * @param message the actual message
528 client_tokenizer_callback (void *cls, void *client,
529 const struct GNUNET_MessageHeader *message)
531 struct TokenizerContext *tc = client;
532 struct GSC_ClientActiveRequest *car = tc->car;
535 GNUNET_snprintf (buf, sizeof (buf),
536 gettext_noop ("# bytes of messages of type %u received"),
537 (unsigned int) ntohs (message->type));
538 GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO);
540 memcmp (&car->target, &GSC_my_identity,
541 sizeof (struct GNUNET_PeerIdentity)))
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Delivering message of type %u to myself\n",
545 ntohs (message->type));
546 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
547 ntohs (message->size),
548 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
549 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
550 sizeof (struct GNUNET_MessageHeader),
551 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
552 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
553 ntohs (message->size),
554 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
555 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
556 sizeof (struct GNUNET_MessageHeader),
557 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562 "Delivering message of type %u and size %u to %s\n",
563 ntohs (message->type), ntohs (message->size),
564 GNUNET_i2s (&car->target));
565 GSC_CLIENTS_deliver_message (&car->target, message,
566 ntohs (message->size),
567 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
568 GSC_CLIENTS_deliver_message (&car->target, message,
569 sizeof (struct GNUNET_MessageHeader),
570 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
571 GSC_SESSIONS_transmit (car,
581 * Free client request records.
584 * @param key identity of peer for which this is an active request
585 * @param value the `struct GSC_ClientActiveRequest` to free
586 * @return #GNUNET_YES (continue iteration)
589 destroy_active_client_request (void *cls,
590 const struct GNUNET_PeerIdentity *key,
593 struct GSC_ClientActiveRequest *car = value;
595 GNUNET_assert (GNUNET_YES ==
596 GNUNET_CONTAINER_multipeermap_remove (car->
597 client_handle->requests,
600 GSC_SESSIONS_dequeue_request (car);
607 * A client disconnected, clean up.
610 * @param client identification of the client
613 handle_client_disconnect (void *cls,
614 struct GNUNET_SERVER_Client *client)
616 struct GSC_Client *c;
620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
621 "Client %p has disconnected from core service.\n", client);
622 c = find_client (client);
624 return; /* client never sent INIT */
625 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
626 if (c->requests != NULL)
628 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
629 &destroy_active_client_request,
631 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
633 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
634 c->connectmap = NULL;
635 GSC_TYPEMAP_remove (c->types, c->tcnt);
638 /* recalculate 'all_client_options' */
639 all_client_options = 0;
640 for (c = client_head; NULL != c ; c = c->next)
641 all_client_options |= c->options;
646 * Tell a client that we are ready to receive the message.
648 * @param car request that is now ready; the responsibility
649 * for the handle remains shared between CLIENTS
650 * and SESSIONS after this call.
653 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
655 struct GSC_Client *c;
656 struct SendMessageReady smr;
658 c = car->client_handle;
660 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
663 /* connection has gone down since, drop request */
665 memcmp (&car->target, &GSC_my_identity,
666 sizeof (struct GNUNET_PeerIdentity)));
667 GSC_SESSIONS_dequeue_request (car);
668 GSC_CLIENTS_reject_request (car);
671 smr.header.size = htons (sizeof (struct SendMessageReady));
672 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
673 smr.size = htons (car->msize);
674 smr.smr_id = car->smr_id;
675 smr.peer = car->target;
676 send_to_client (c, &smr.header, GNUNET_NO);
681 * Tell a client that we will never be ready to receive the
682 * given message in time (disconnect or timeout).
684 * @param car request that now permanently failed; the
685 * responsibility for the handle is now returned
686 * to CLIENTS (SESSIONS is done with it).
689 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
691 GNUNET_assert (GNUNET_YES ==
692 GNUNET_CONTAINER_multipeermap_remove (car->
693 client_handle->requests,
701 * Notify a particular client about a change to existing connection to
702 * one of our neighbours (check if the client is interested). Called
703 * from 'GSC_SESSIONS_notify_client_about_sessions'.
705 * @param client client to notify
706 * @param neighbour identity of the neighbour that changed status
707 * @param tmap_old previous type map for the neighbour, NULL for connect
708 * @param tmap_new updated type map for the neighbour, NULL for disconnect
711 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
712 const struct GNUNET_PeerIdentity *neighbour,
713 const struct GSC_TypeMap *tmap_old,
714 const struct GSC_TypeMap *tmap_new)
716 struct ConnectNotifyMessage *cnm;
718 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
719 struct DisconnectNotifyMessage dcm;
723 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
724 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
725 if (old_match == new_match)
727 GNUNET_assert (old_match ==
728 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
730 return; /* no change */
732 if (old_match == GNUNET_NO)
735 GNUNET_assert (GNUNET_NO ==
736 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
738 GNUNET_assert (GNUNET_YES ==
739 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
742 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
743 size = sizeof (struct ConnectNotifyMessage);
744 cnm = (struct ConnectNotifyMessage *) buf;
745 cnm->header.size = htons (size);
746 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
747 cnm->reserved = htonl (0);
748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
749 "Sending `%s' message to client.\n",
751 cnm->peer = *neighbour;
752 send_to_client (client, &cnm->header, GNUNET_NO);
756 /* send disconnect */
757 GNUNET_assert (GNUNET_YES ==
758 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
760 GNUNET_assert (GNUNET_YES ==
761 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
764 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
765 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
766 dcm.reserved = htonl (0);
767 dcm.peer = *neighbour;
768 send_to_client (client, &dcm.header, GNUNET_NO);
774 * Notify all clients about a change to existing session.
775 * Called from SESSIONS whenever there is a change in sessions
776 * or types processed by the respective peer.
778 * @param neighbour identity of the neighbour that changed status
779 * @param tmap_old previous type map for the neighbour, NULL for connect
780 * @param tmap_new updated type map for the neighbour, NULL for disconnect
783 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
784 const struct GSC_TypeMap *tmap_old,
785 const struct GSC_TypeMap *tmap_new)
787 struct GSC_Client *c;
789 for (c = client_head; NULL != c; c = c->next)
790 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
796 * Deliver P2P message to interested clients. Caller must have checked
797 * that the sending peer actually lists the given message type as one
800 * @param sender peer who sent us the message
801 * @param msg the message
802 * @param msize number of bytes to transmit
803 * @param options options for checking which clients should
804 * receive the message
807 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
808 const struct GNUNET_MessageHeader *msg,
812 size_t size = msize + sizeof (struct NotifyTrafficMessage);
813 char buf[size] GNUNET_ALIGN;
814 struct NotifyTrafficMessage *ntm;
816 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
819 /* recovery strategy: throw performance data away... */
820 size = msize + sizeof (struct NotifyTrafficMessage);
822 if (! ( (0 != (all_client_options & options)) ||
823 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
824 return; /* no client cares about this message notification */
825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
826 "Core service passes message from `%4s' of type %u to client.\n",
828 (unsigned int) ntohs (msg->type));
829 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
830 ntm = (struct NotifyTrafficMessage *) buf;
831 ntm->header.size = htons (size);
832 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
833 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
835 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
840 send_to_all_clients (sender,
849 * Initialize clients subsystem.
851 * @param server handle to server clients connect to
854 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
856 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
857 {&handle_client_init, NULL,
858 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
859 {&GSC_KX_handle_client_monitor_peers, NULL,
860 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
861 sizeof (struct GNUNET_MessageHeader)},
862 {&handle_client_send_request, NULL,
863 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
864 sizeof (struct SendMessageRequest)},
865 {&handle_client_send, NULL,
866 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
870 /* setup notification */
871 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
873 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
874 GNUNET_SERVER_disconnect_notify (server,
875 &handle_client_disconnect, NULL);
876 GNUNET_SERVER_add_handlers (server, handlers);
881 * Shutdown clients subsystem.
886 struct GSC_Client *c;
888 while (NULL != (c = client_head))
889 handle_client_disconnect (NULL, c->client_handle);
890 if (NULL != notifier)
892 GNUNET_SERVER_notification_context_destroy (notifier);
895 if (NULL != client_mst)
897 GNUNET_SERVER_mst_destroy (client_mst);
902 /* end of gnunet-service-core_clients.c */