2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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_neighbours.h"
33 #include "gnunet-service-core_sessions.h"
34 #include "gnunet-service-core_typemap.h"
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 @e 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_MultiPeerMap *requests;
80 * Map containing all peers that this client knows we're connected to.
82 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
85 * Options for messages this client cares about,
86 * see GNUNET_CORE_OPTION_ values.
91 * Number of types of incoming messages this client
92 * specifically cares about. Size of the @e types array.
100 * Big "or" of all client options.
102 static uint32_t all_client_options;
105 * Head of linked list of our clients.
107 static struct GSC_Client *client_head;
110 * Tail of linked list of our clients.
112 static struct GSC_Client *client_tail;
115 * Context for notifications we need to send to our clients.
117 static struct GNUNET_SERVER_NotificationContext *notifier;
120 * Tokenizer for messages received from clients.
122 static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
126 * Lookup our client struct given the server's client handle.
128 * @param client server client handle to look up
129 * @return our client handle for the client
131 static struct GSC_Client *
132 find_client (struct GNUNET_SERVER_Client *client)
134 struct GSC_Client *c;
137 while ((c != NULL) && (c->client_handle != client))
144 * Send a message to one of our clients.
146 * @param client target for the message
147 * @param msg message to transmit
148 * @param can_drop could this message be dropped if the
149 * client's queue is getting too large?
152 send_to_client (struct GSC_Client *client,
153 const struct GNUNET_MessageHeader *msg,
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
157 "Preparing to send %u bytes of message of type %u to client.\n",
158 (unsigned int) ntohs (msg->size),
159 (unsigned int) ntohs (msg->type));
160 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
166 * Send a message to one of our clients.
168 * @param client target for the message
169 * @param msg message to transmit
170 * @param can_drop could this message be dropped if the
171 * client's queue is getting too large?
174 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
175 const struct GNUNET_MessageHeader *msg,
178 struct GSC_Client *c;
180 c = find_client (client);
186 send_to_client (c, msg, can_drop);
191 * Test if the client is interested in messages of the given type.
193 * @param type message type
194 * @param c client to test
195 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
198 type_match (uint16_t type, struct GSC_Client *c)
202 if (c->tcnt == 0 && c->options != 0)
203 return GNUNET_YES; /* peer without handlers and inbound/outbond
204 callbacks matches ALL */
205 for (i = 0; i < c->tcnt; i++)
206 if (type == c->types[i])
213 * Send a message to all of our current clients that have the right
216 * @param partner origin (or destination) of the message (used to check that this peer is
217 * known to be connected to the respective client)
218 * @param msg message to multicast
219 * @param can_drop can this message be discarded if the queue is too long
220 * @param options mask to use
221 * @param type type of the embedded message, 0 for none
224 send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
225 const struct GNUNET_MessageHeader *msg,
230 struct GSC_Client *c;
233 for (c = client_head; NULL != c; c = c->next)
235 tm = type_match (type, c);
236 if (! ( (0 != (c->options & options)) ||
237 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
238 (GNUNET_YES == tm) ) ) )
239 continue; /* neither options nor type match permit the message */
240 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
241 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
242 (GNUNET_YES == tm) ) )
244 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
245 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
248 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
251 (unsigned int) type);
252 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
253 (GNUNET_YES != tm) ||
255 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
257 send_to_client (c, msg, can_drop);
263 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
266 * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
267 * @param message the `struct InitMessage` (presumably)
270 handle_client_init (void *cls,
271 struct GNUNET_SERVER_Client *client,
272 const struct GNUNET_MessageHeader *message)
274 const struct InitMessage *im;
275 struct InitReplyMessage irm;
276 struct GSC_Client *c;
278 const uint16_t *types;
282 /* check that we don't have an entry already */
283 c = find_client (client);
287 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
290 msize = ntohs (message->size);
291 if (msize < sizeof (struct InitMessage))
294 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
297 GNUNET_SERVER_notification_context_add (notifier, client);
298 im = (const struct InitMessage *) message;
299 types = (const uint16_t *) &im[1];
300 msize -= sizeof (struct InitMessage);
301 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
302 c->client_handle = client;
303 c->tcnt = msize / sizeof (uint16_t);
304 c->options = ntohl (im->options);
305 all_client_options |= c->options;
306 c->types = (const uint16_t *) &c[1];
307 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
308 GNUNET_assert (GNUNET_YES ==
309 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
312 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
313 wtypes = (uint16_t *) & c[1];
314 for (i = 0; i < c->tcnt; i++)
315 wtypes[i] = ntohs (types[i]);
316 GSC_TYPEMAP_add (wtypes, c->tcnt);
317 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 "Client connecting to core service is interested in %u message types\n",
320 (unsigned int) c->tcnt);
321 /* send init reply message */
322 irm.header.size = htons (sizeof (struct InitReplyMessage));
323 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
324 irm.reserved = htonl (0);
325 irm.my_identity = GSC_my_identity;
326 send_to_client (c, &irm.header, GNUNET_NO);
327 GSC_SESSIONS_notify_client_about_sessions (c);
328 GNUNET_SERVER_receive_done (client, GNUNET_OK);
333 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
336 * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
337 * @param message the `struct SendMessageRequest` (presumably)
340 handle_client_send_request (void *cls,
341 struct GNUNET_SERVER_Client *client,
342 const struct GNUNET_MessageHeader *message)
344 const struct SendMessageRequest *req;
345 struct GSC_Client *c;
346 struct GSC_ClientActiveRequest *car;
349 req = (const struct SendMessageRequest *) message;
350 c = find_client (client);
353 /* client did not send INIT first! */
355 GNUNET_SERVER_receive_done (client,
359 if (NULL == c->requests)
360 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363 "Client asked for transmission to `%s'\n",
364 GNUNET_i2s (&req->peer));
369 sizeof (struct GNUNET_PeerIdentity)));
370 if ((! is_loopback) &&
372 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
375 /* neighbour must have disconnected since request was issued,
376 * ignore (client will realize it once it processes the
377 * disconnect notification) */
378 GNUNET_STATISTICS_update (GSC_stats,
380 ("# send requests dropped (disconnected)"), 1,
382 GNUNET_SERVER_receive_done (client,
387 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
391 /* create new entry */
392 car = GNUNET_new (struct GSC_ClientActiveRequest);
393 GNUNET_assert (GNUNET_OK ==
394 GNUNET_CONTAINER_multipeermap_put (c->requests,
397 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
398 car->client_handle = c;
402 /* dequeue and recycle memory from pending request, there can only
403 be at most one per client and peer */
404 GNUNET_STATISTICS_update (GSC_stats,
406 ("# dequeuing CAR (duplicate request)"), 1,
408 GSC_SESSIONS_dequeue_request (car);
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410 "Transmission request to `%s' was a duplicate!\n",
411 GNUNET_i2s (&req->peer));
413 car->target = req->peer;
414 car->received_time = GNUNET_TIME_absolute_get ();
415 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
416 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
417 car->msize = ntohs (req->size);
418 car->smr_id = req->smr_id;
419 car->was_solicited = GNUNET_NO;
422 /* loopback, satisfy immediately */
423 GSC_CLIENTS_solicit_request (car);
424 GNUNET_SERVER_receive_done (client, GNUNET_OK);
427 GSC_SESSIONS_queue_request (car);
428 GNUNET_SERVER_receive_done (client, GNUNET_OK);
433 * Closure for the #client_tokenizer_callback().
435 struct TokenizerContext
439 * Active request handle for the message.
441 struct GSC_ClientActiveRequest *car;
444 * How important is this message.
446 enum GNUNET_CORE_Priority priority;
449 * Is corking allowed (set only once we have the real message).
457 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
460 * @param client the client issuing the request
461 * @param message the `struct SendMessage`
464 handle_client_send (void *cls,
465 struct GNUNET_SERVER_Client *client,
466 const struct GNUNET_MessageHeader *message)
468 const struct SendMessage *sm;
469 struct GSC_Client *c;
470 struct TokenizerContext tc;
472 struct GNUNET_TIME_Relative delay;
473 struct GNUNET_TIME_Relative overdue;
475 msize = ntohs (message->size);
476 if (msize < sizeof (struct SendMessage))
479 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
482 sm = (const struct SendMessage *) message;
483 msize -= sizeof (struct SendMessage);
484 GNUNET_break (0 == ntohl (sm->reserved));
485 c = find_client (client);
488 /* client did not send INIT first! */
490 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
494 = GNUNET_CONTAINER_multipeermap_get (c->requests,
498 /* Must have been that we first approved the request, then got disconnected
499 * (which triggered removal of the 'car') and now the client gives us a message
500 * just *before* the client learns about the disconnect. Theoretically, we
501 * might also now be *again* connected. So this can happen (but should be
502 * rare). If it does happen, the message is discarded. */
503 GNUNET_STATISTICS_update (GSC_stats,
505 ("# messages discarded (session disconnected)"),
507 GNUNET_SERVER_receive_done (client,
511 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
512 overdue = GNUNET_TIME_absolute_get_duration (tc.car->deadline);
513 tc.cork = ntohl (sm->cork);
514 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
515 if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
516 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
517 "Client waited %s for transmission of %u bytes to `%s'%s\n",
518 GNUNET_STRINGS_relative_time_to_string (delay,
521 GNUNET_i2s (&sm->peer),
522 tc.cork ? "" : " (corked)");
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Client waited %s for transmission of %u bytes to `%s'%s\n",
526 GNUNET_STRINGS_relative_time_to_string (delay,
529 GNUNET_i2s (&sm->peer),
530 tc.cork ? "" : " (corked)");
532 GNUNET_assert (GNUNET_YES ==
533 GNUNET_CONTAINER_multipeermap_remove (c->requests,
536 GNUNET_SERVER_mst_receive (client_mst, &tc,
537 (const char *) &sm[1],
541 GSC_SESSIONS_dequeue_request (tc.car);
542 GNUNET_free (tc.car);
543 GNUNET_SERVER_receive_done (client,
549 * Functions with this signature are called whenever a complete
550 * message is received by the tokenizer. Used by the 'client_mst' for
551 * dispatching messages from clients to either the SESSION subsystem
552 * or other CLIENT (for loopback).
555 * @param client reservation request (`struct GSC_ClientActiveRequest`)
556 * @param message the actual message
559 client_tokenizer_callback (void *cls,
561 const struct GNUNET_MessageHeader *message)
563 struct TokenizerContext *tc = client;
564 struct GSC_ClientActiveRequest *car = tc->car;
567 GNUNET_snprintf (buf, sizeof (buf),
568 gettext_noop ("# bytes of messages of type %u received"),
569 (unsigned int) ntohs (message->type));
570 GNUNET_STATISTICS_update (GSC_stats,
572 ntohs (message->size),
575 memcmp (&car->target,
577 sizeof (struct GNUNET_PeerIdentity)))
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "Delivering message of type %u to myself\n",
581 ntohs (message->type));
582 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
583 ntohs (message->size),
584 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
585 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
586 sizeof (struct GNUNET_MessageHeader),
587 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
588 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
589 ntohs (message->size),
590 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
591 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
592 sizeof (struct GNUNET_MessageHeader),
593 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
598 "Delivering message of type %u and size %u to %s\n",
599 ntohs (message->type), ntohs (message->size),
600 GNUNET_i2s (&car->target));
601 GSC_CLIENTS_deliver_message (&car->target, message,
602 ntohs (message->size),
603 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
604 GSC_CLIENTS_deliver_message (&car->target, message,
605 sizeof (struct GNUNET_MessageHeader),
606 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
607 GSC_SESSIONS_transmit (car,
617 * Free client request records.
620 * @param key identity of peer for which this is an active request
621 * @param value the `struct GSC_ClientActiveRequest` to free
622 * @return #GNUNET_YES (continue iteration)
625 destroy_active_client_request (void *cls,
626 const struct GNUNET_PeerIdentity *key,
629 struct GSC_ClientActiveRequest *car = value;
631 GNUNET_assert (GNUNET_YES ==
632 GNUNET_CONTAINER_multipeermap_remove (car->
633 client_handle->requests,
636 GSC_SESSIONS_dequeue_request (car);
643 * A client disconnected, clean up.
646 * @param client identification of the client
649 handle_client_disconnect (void *cls,
650 struct GNUNET_SERVER_Client *client)
652 struct GSC_Client *c;
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657 "Client %p has disconnected from core service.\n",
659 c = find_client (client);
661 return; /* client never sent INIT */
662 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
663 if (c->requests != NULL)
665 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
666 &destroy_active_client_request,
668 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
670 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
671 c->connectmap = NULL;
672 GSC_TYPEMAP_remove (c->types, c->tcnt);
675 /* recalculate 'all_client_options' */
676 all_client_options = 0;
677 for (c = client_head; NULL != c ; c = c->next)
678 all_client_options |= c->options;
683 * Tell a client that we are ready to receive the message.
685 * @param car request that is now ready; the responsibility
686 * for the handle remains shared between CLIENTS
687 * and SESSIONS after this call.
690 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
692 struct GSC_Client *c;
693 struct SendMessageReady smr;
694 struct GNUNET_TIME_Relative delay;
695 struct GNUNET_TIME_Relative left;
697 c = car->client_handle;
699 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
702 /* connection has gone down since, drop request */
704 memcmp (&car->target,
706 sizeof (struct GNUNET_PeerIdentity)));
707 GSC_SESSIONS_dequeue_request (car);
708 GSC_CLIENTS_reject_request (car,
712 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
713 left = GNUNET_TIME_absolute_get_duration (car->deadline);
714 if (left.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
715 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
716 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
717 GNUNET_STRINGS_relative_time_to_string (delay,
719 GNUNET_i2s (&car->target),
720 (0 == left.rel_value_us)
724 smr.header.size = htons (sizeof (struct SendMessageReady));
725 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
726 smr.size = htons (car->msize);
727 smr.smr_id = car->smr_id;
728 smr.peer = car->target;
729 send_to_client (c, &smr.header, GNUNET_NO);
734 * We will never be ready to transmit the given message in (disconnect
735 * or invalid request). Frees resources associated with @a car. We
736 * don't explicitly tell the client, he'll learn with the disconnect
737 * (or violated the protocol).
739 * @param car request that now permanently failed; the
740 * responsibility for the handle is now returned
741 * to CLIENTS (SESSIONS is done with it).
742 * @param drop_client #GNUNET_YES if the client violated the protocol
743 * and we should thus drop the connection
746 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
749 GNUNET_assert (GNUNET_YES ==
750 GNUNET_CONTAINER_multipeermap_remove (car->
751 client_handle->requests,
754 if (GNUNET_YES == drop_client)
755 GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
761 * Notify a particular client about a change to existing connection to
762 * one of our neighbours (check if the client is interested). Called
763 * from 'GSC_SESSIONS_notify_client_about_sessions'.
765 * @param client client to notify
766 * @param neighbour identity of the neighbour that changed status
767 * @param tmap_old previous type map for the neighbour, NULL for connect
768 * @param tmap_new updated type map for the neighbour, NULL for disconnect
771 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
772 const struct GNUNET_PeerIdentity *neighbour,
773 const struct GSC_TypeMap *tmap_old,
774 const struct GSC_TypeMap *tmap_new)
776 struct ConnectNotifyMessage *cnm;
778 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
779 struct DisconnectNotifyMessage dcm;
783 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
784 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
785 if (old_match == new_match)
787 GNUNET_assert (old_match ==
788 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
790 return; /* no change */
792 if (old_match == GNUNET_NO)
795 GNUNET_assert (GNUNET_NO ==
796 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
798 GNUNET_assert (GNUNET_YES ==
799 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
802 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
803 size = sizeof (struct ConnectNotifyMessage);
804 cnm = (struct ConnectNotifyMessage *) buf;
805 cnm->header.size = htons (size);
806 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
807 cnm->reserved = htonl (0);
808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
809 "Sending `%s' message to client.\n",
811 cnm->peer = *neighbour;
812 send_to_client (client, &cnm->header, GNUNET_NO);
816 /* send disconnect */
817 GNUNET_assert (GNUNET_YES ==
818 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
820 GNUNET_assert (GNUNET_YES ==
821 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
824 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
825 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
826 dcm.reserved = htonl (0);
827 dcm.peer = *neighbour;
828 send_to_client (client, &dcm.header, GNUNET_NO);
834 * Notify all clients about a change to existing session.
835 * Called from SESSIONS whenever there is a change in sessions
836 * or types processed by the respective peer.
838 * @param neighbour identity of the neighbour that changed status
839 * @param tmap_old previous type map for the neighbour, NULL for connect
840 * @param tmap_new updated type map for the neighbour, NULL for disconnect
843 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
844 const struct GSC_TypeMap *tmap_old,
845 const struct GSC_TypeMap *tmap_new)
847 struct GSC_Client *c;
849 for (c = client_head; NULL != c; c = c->next)
850 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
856 * Deliver P2P message to interested clients. Caller must have checked
857 * that the sending peer actually lists the given message type as one
860 * @param sender peer who sent us the message
861 * @param msg the message
862 * @param msize number of bytes to transmit
863 * @param options options for checking which clients should
864 * receive the message
867 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
868 const struct GNUNET_MessageHeader *msg,
872 size_t size = msize + sizeof (struct NotifyTrafficMessage);
873 char buf[size] GNUNET_ALIGN;
874 struct NotifyTrafficMessage *ntm;
876 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
879 /* recovery strategy: throw performance data away... */
880 size = msize + sizeof (struct NotifyTrafficMessage);
882 if (! ( (0 != (all_client_options & options)) ||
883 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
884 return; /* no client cares about this message notification */
885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886 "Core service passes message from `%s' of type %u to client.\n",
888 (unsigned int) ntohs (msg->type));
889 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
890 ntm = (struct NotifyTrafficMessage *) buf;
891 ntm->header.size = htons (size);
892 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
893 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
895 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
900 send_to_all_clients (sender,
909 * Initialize clients subsystem.
911 * @param server handle to server clients connect to
914 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
916 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
917 {&handle_client_init, NULL,
918 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
919 {&GSC_KX_handle_client_monitor_peers, NULL,
920 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
921 sizeof (struct GNUNET_MessageHeader)},
922 {&handle_client_send_request, NULL,
923 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
924 sizeof (struct SendMessageRequest)},
925 {&handle_client_send, NULL,
926 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
930 /* setup notification */
931 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
933 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
934 GNUNET_SERVER_disconnect_notify (server,
935 &handle_client_disconnect, NULL);
936 GNUNET_SERVER_add_handlers (server, handlers);
941 * Shutdown clients subsystem.
946 struct GSC_Client *c;
948 while (NULL != (c = client_head))
949 handle_client_disconnect (NULL, c->client_handle);
950 if (NULL != notifier)
952 GNUNET_SERVER_notification_context_destroy (notifier);
955 if (NULL != client_mst)
957 GNUNET_SERVER_mst_destroy (client_mst);
962 /* end of gnunet-service-core_clients.c */