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_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,
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "Preparing to send %u bytes of message of type %u to client.\n",
157 (unsigned int) ntohs (msg->size),
158 (unsigned int) ntohs (msg->type));
159 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
165 * Send a message to one of our clients.
167 * @param client target for the message
168 * @param msg message to transmit
169 * @param can_drop could this message be dropped if the
170 * client's queue is getting too large?
173 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
174 const struct GNUNET_MessageHeader *msg,
177 struct GSC_Client *c;
179 c = find_client (client);
185 send_to_client (c, msg, can_drop);
190 * Test if the client is interested in messages of the given type.
192 * @param type message type
193 * @param c client to test
194 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
197 type_match (uint16_t type, struct GSC_Client *c)
201 if (c->tcnt == 0 && c->options != 0)
202 return GNUNET_YES; /* peer without handlers and inbound/outbond
203 callbacks matches ALL */
204 for (i = 0; i < c->tcnt; i++)
205 if (type == c->types[i])
212 * Send a message to all of our current clients that have the right
215 * @param partner origin (or destination) of the message (used to check that this peer is
216 * known to be connected to the respective client)
217 * @param msg message to multicast
218 * @param can_drop can this message be discarded if the queue is too long
219 * @param options mask to use
220 * @param type type of the embedded message, 0 for none
223 send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
224 const struct GNUNET_MessageHeader *msg,
229 struct GSC_Client *c;
232 for (c = client_head; NULL != c; c = c->next)
234 tm = type_match (type, c);
235 if (! ( (0 != (c->options & options)) ||
236 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
237 (GNUNET_YES == tm) ) ) )
238 continue; /* neither options nor type match permit the message */
239 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
240 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
241 (GNUNET_YES == tm) ) )
243 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
244 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
247 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
250 (unsigned int) type);
251 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
252 (GNUNET_YES != tm) ||
254 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
256 send_to_client (c, msg, can_drop);
262 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
265 * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
266 * @param message the `struct InitMessage` (presumably)
269 handle_client_init (void *cls,
270 struct GNUNET_SERVER_Client *client,
271 const struct GNUNET_MessageHeader *message)
273 const struct InitMessage *im;
274 struct InitReplyMessage irm;
275 struct GSC_Client *c;
277 const uint16_t *types;
281 /* check that we don't have an entry already */
282 c = find_client (client);
286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
289 msize = ntohs (message->size);
290 if (msize < sizeof (struct InitMessage))
293 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
296 GNUNET_SERVER_notification_context_add (notifier, client);
297 im = (const struct InitMessage *) message;
298 types = (const uint16_t *) &im[1];
299 msize -= sizeof (struct InitMessage);
300 c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
301 c->client_handle = client;
302 c->tcnt = msize / sizeof (uint16_t);
303 c->options = ntohl (im->options);
304 all_client_options |= c->options;
305 c->types = (const uint16_t *) &c[1];
306 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
307 GNUNET_assert (GNUNET_YES ==
308 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
311 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
312 wtypes = (uint16_t *) & c[1];
313 for (i = 0; i < c->tcnt; i++)
314 wtypes[i] = ntohs (types[i]);
315 GSC_TYPEMAP_add (wtypes, c->tcnt);
316 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318 "Client connecting to core service is interested in %u message types\n",
319 (unsigned int) c->tcnt);
320 /* send init reply message */
321 irm.header.size = htons (sizeof (struct InitReplyMessage));
322 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
323 irm.reserved = htonl (0);
324 irm.my_identity = GSC_my_identity;
325 send_to_client (c, &irm.header, GNUNET_NO);
326 GSC_SESSIONS_notify_client_about_sessions (c);
327 GNUNET_SERVER_receive_done (client, GNUNET_OK);
332 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
335 * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
336 * @param message the `struct SendMessageRequest` (presumably)
339 handle_client_send_request (void *cls,
340 struct GNUNET_SERVER_Client *client,
341 const struct GNUNET_MessageHeader *message)
343 const struct SendMessageRequest *req;
344 struct GSC_Client *c;
345 struct GSC_ClientActiveRequest *car;
348 req = (const struct SendMessageRequest *) message;
349 c = find_client (client);
352 /* client did not send INIT first! */
354 GNUNET_SERVER_receive_done (client,
358 if (NULL == c->requests)
359 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362 "Client asked for transmission to `%s'\n",
363 GNUNET_i2s (&req->peer));
368 sizeof (struct GNUNET_PeerIdentity)));
369 if ((! is_loopback) &&
371 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
374 /* neighbour must have disconnected since request was issued,
375 * ignore (client will realize it once it processes the
376 * disconnect notification) */
377 GNUNET_STATISTICS_update (GSC_stats,
379 ("# send requests dropped (disconnected)"), 1,
381 GNUNET_SERVER_receive_done (client,
386 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
390 /* create new entry */
391 car = GNUNET_new (struct GSC_ClientActiveRequest);
392 GNUNET_assert (GNUNET_OK ==
393 GNUNET_CONTAINER_multipeermap_put (c->requests,
396 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
397 car->client_handle = c;
401 /* dequeue and recycle memory from pending request, there can only
402 be at most one per client and peer */
403 GNUNET_STATISTICS_update (GSC_stats,
404 gettext_noop ("# dequeuing CAR (duplicate request)"),
407 GSC_SESSIONS_dequeue_request (car);
408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
409 "Transmission request to `%s' was a duplicate!\n",
410 GNUNET_i2s (&req->peer));
412 car->target = req->peer;
413 car->received_time = GNUNET_TIME_absolute_get ();
414 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
415 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
416 car->msize = ntohs (req->size);
417 car->smr_id = req->smr_id;
418 car->was_solicited = GNUNET_NO;
421 /* loopback, satisfy immediately */
422 GSC_CLIENTS_solicit_request (car);
423 GNUNET_SERVER_receive_done (client, GNUNET_OK);
426 GSC_SESSIONS_queue_request (car);
427 GNUNET_SERVER_receive_done (client, GNUNET_OK);
432 * Closure for the #client_tokenizer_callback().
434 struct TokenizerContext
438 * Active request handle for the message.
440 struct GSC_ClientActiveRequest *car;
443 * How important is this message.
445 enum GNUNET_CORE_Priority priority;
448 * Is corking allowed (set only once we have the real message).
456 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
459 * @param client the client issuing the request
460 * @param message the `struct SendMessage`
463 handle_client_send (void *cls,
464 struct GNUNET_SERVER_Client *client,
465 const struct GNUNET_MessageHeader *message)
467 const struct SendMessage *sm;
468 struct GSC_Client *c;
469 struct TokenizerContext tc;
471 struct GNUNET_TIME_Relative delay;
473 msize = ntohs (message->size);
474 if (msize < sizeof (struct SendMessage))
477 GNUNET_SERVER_receive_done (client,
481 sm = (const struct SendMessage *) message;
482 msize -= sizeof (struct SendMessage);
483 GNUNET_break (0 == ntohl (sm->reserved));
484 c = find_client (client);
487 /* client did not send INIT first! */
489 GNUNET_SERVER_receive_done (client,
493 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
497 /* Must have been that we first approved the request, then got disconnected
498 * (which triggered removal of the 'car') and now the client gives us a message
499 * just *before* the client learns about the disconnect. Theoretically, we
500 * might also now be *again* connected. So this can happen (but should be
501 * rare). If it does happen, the message is discarded. */
502 GNUNET_STATISTICS_update (GSC_stats,
503 gettext_noop ("# messages discarded (session disconnected)"),
506 GNUNET_SERVER_receive_done (client,
510 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
511 tc.cork = ntohl (sm->cork);
512 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
513 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
514 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
515 "Client waited %s for transmission of %u bytes to `%s'%s\n",
516 GNUNET_STRINGS_relative_time_to_string (delay,
519 GNUNET_i2s (&sm->peer),
520 tc.cork ? " (cork)" : " (uncorked)");
522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
523 "Client waited %s for transmission of %u bytes to `%s'%s\n",
524 GNUNET_STRINGS_relative_time_to_string (delay,
527 GNUNET_i2s (&sm->peer),
528 tc.cork ? " (cork)" : " (uncorked)");
530 GNUNET_assert (GNUNET_YES ==
531 GNUNET_CONTAINER_multipeermap_remove (c->requests,
534 GNUNET_SERVER_mst_receive (client_mst, &tc,
535 (const char *) &sm[1],
539 GSC_SESSIONS_dequeue_request (tc.car);
540 GNUNET_free (tc.car);
541 GNUNET_SERVER_receive_done (client,
547 * Functions with this signature are called whenever a complete
548 * message is received by the tokenizer. Used by the 'client_mst' for
549 * dispatching messages from clients to either the SESSION subsystem
550 * or other CLIENT (for loopback).
553 * @param client reservation request (`struct GSC_ClientActiveRequest`)
554 * @param message the actual message
557 client_tokenizer_callback (void *cls,
559 const struct GNUNET_MessageHeader *message)
561 struct TokenizerContext *tc = client;
562 struct GSC_ClientActiveRequest *car = tc->car;
565 GNUNET_snprintf (buf, sizeof (buf),
566 gettext_noop ("# bytes of messages of type %u received"),
567 (unsigned int) ntohs (message->type));
568 GNUNET_STATISTICS_update (GSC_stats,
570 ntohs (message->size),
573 memcmp (&car->target,
575 sizeof (struct GNUNET_PeerIdentity)))
577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
578 "Delivering message of type %u to myself\n",
579 ntohs (message->type));
580 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
581 ntohs (message->size),
582 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
583 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
584 sizeof (struct GNUNET_MessageHeader),
585 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
586 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
587 ntohs (message->size),
588 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
589 GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
590 sizeof (struct GNUNET_MessageHeader),
591 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596 "Delivering message of type %u and size %u to %s\n",
597 ntohs (message->type), ntohs (message->size),
598 GNUNET_i2s (&car->target));
599 GSC_CLIENTS_deliver_message (&car->target, message,
600 ntohs (message->size),
601 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
602 GSC_CLIENTS_deliver_message (&car->target, message,
603 sizeof (struct GNUNET_MessageHeader),
604 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
605 GSC_SESSIONS_transmit (car,
615 * Free client request records.
618 * @param key identity of peer for which this is an active request
619 * @param value the `struct GSC_ClientActiveRequest` to free
620 * @return #GNUNET_YES (continue iteration)
623 destroy_active_client_request (void *cls,
624 const struct GNUNET_PeerIdentity *key,
627 struct GSC_ClientActiveRequest *car = value;
629 GNUNET_assert (GNUNET_YES ==
630 GNUNET_CONTAINER_multipeermap_remove (car->
631 client_handle->requests,
634 GSC_SESSIONS_dequeue_request (car);
641 * A client disconnected, clean up.
644 * @param client identification of the client
647 handle_client_disconnect (void *cls,
648 struct GNUNET_SERVER_Client *client)
650 struct GSC_Client *c;
654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
655 "Client %p has disconnected from core service.\n",
657 c = find_client (client);
659 return; /* client never sent INIT */
660 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
661 if (c->requests != NULL)
663 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
664 &destroy_active_client_request,
666 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
668 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
669 c->connectmap = NULL;
670 GSC_TYPEMAP_remove (c->types, c->tcnt);
673 /* recalculate 'all_client_options' */
674 all_client_options = 0;
675 for (c = client_head; NULL != c ; c = c->next)
676 all_client_options |= c->options;
681 * Tell a client that we are ready to receive the message.
683 * @param car request that is now ready; the responsibility
684 * for the handle remains shared between CLIENTS
685 * and SESSIONS after this call.
688 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
690 struct GSC_Client *c;
691 struct SendMessageReady smr;
692 struct GNUNET_TIME_Relative delay;
693 struct GNUNET_TIME_Relative left;
695 c = car->client_handle;
697 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
700 /* connection has gone down since, drop request */
702 memcmp (&car->target,
704 sizeof (struct GNUNET_PeerIdentity)));
705 GSC_SESSIONS_dequeue_request (car);
706 GSC_CLIENTS_reject_request (car,
710 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
711 left = GNUNET_TIME_absolute_get_duration (car->deadline);
712 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
713 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
714 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
715 GNUNET_STRINGS_relative_time_to_string (delay,
717 GNUNET_i2s (&car->target),
718 (0 == left.rel_value_us)
722 smr.header.size = htons (sizeof (struct SendMessageReady));
723 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
724 smr.size = htons (car->msize);
725 smr.smr_id = car->smr_id;
726 smr.peer = car->target;
727 send_to_client (c, &smr.header, GNUNET_NO);
732 * We will never be ready to transmit the given message in (disconnect
733 * or invalid request). Frees resources associated with @a car. We
734 * don't explicitly tell the client, he'll learn with the disconnect
735 * (or violated the protocol).
737 * @param car request that now permanently failed; the
738 * responsibility for the handle is now returned
739 * to CLIENTS (SESSIONS is done with it).
740 * @param drop_client #GNUNET_YES if the client violated the protocol
741 * and we should thus drop the connection
744 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
747 GNUNET_assert (GNUNET_YES ==
748 GNUNET_CONTAINER_multipeermap_remove (car->
749 client_handle->requests,
752 if (GNUNET_YES == drop_client)
753 GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
759 * Notify a particular client about a change to existing connection to
760 * one of our neighbours (check if the client is interested). Called
761 * from 'GSC_SESSIONS_notify_client_about_sessions'.
763 * @param client client to notify
764 * @param neighbour identity of the neighbour that changed status
765 * @param tmap_old previous type map for the neighbour, NULL for connect
766 * @param tmap_new updated type map for the neighbour, NULL for disconnect
769 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
770 const struct GNUNET_PeerIdentity *neighbour,
771 const struct GSC_TypeMap *tmap_old,
772 const struct GSC_TypeMap *tmap_new)
774 struct ConnectNotifyMessage *cnm;
776 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
777 struct DisconnectNotifyMessage dcm;
781 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
782 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
783 if (old_match == new_match)
785 GNUNET_assert (old_match ==
786 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
788 return; /* no change */
790 if (old_match == GNUNET_NO)
793 GNUNET_assert (GNUNET_NO ==
794 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
796 GNUNET_assert (GNUNET_YES ==
797 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
800 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
801 size = sizeof (struct ConnectNotifyMessage);
802 cnm = (struct ConnectNotifyMessage *) buf;
803 cnm->header.size = htons (size);
804 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
805 cnm->reserved = htonl (0);
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807 "Sending `%s' message to client.\n",
809 cnm->peer = *neighbour;
810 send_to_client (client, &cnm->header, GNUNET_NO);
814 /* send disconnect */
815 GNUNET_assert (GNUNET_YES ==
816 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
818 GNUNET_assert (GNUNET_YES ==
819 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
822 dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
823 dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
824 dcm.reserved = htonl (0);
825 dcm.peer = *neighbour;
826 send_to_client (client, &dcm.header, GNUNET_NO);
832 * Notify all clients about a change to existing session.
833 * Called from SESSIONS whenever there is a change in sessions
834 * or types processed by the respective peer.
836 * @param neighbour identity of the neighbour that changed status
837 * @param tmap_old previous type map for the neighbour, NULL for connect
838 * @param tmap_new updated type map for the neighbour, NULL for disconnect
841 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
842 const struct GSC_TypeMap *tmap_old,
843 const struct GSC_TypeMap *tmap_new)
845 struct GSC_Client *c;
847 for (c = client_head; NULL != c; c = c->next)
848 GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
854 * Deliver P2P message to interested clients. Caller must have checked
855 * that the sending peer actually lists the given message type as one
858 * @param sender peer who sent us the message
859 * @param msg the message
860 * @param msize number of bytes to transmit
861 * @param options options for checking which clients should
862 * receive the message
865 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
866 const struct GNUNET_MessageHeader *msg,
870 size_t size = msize + sizeof (struct NotifyTrafficMessage);
871 char buf[size] GNUNET_ALIGN;
872 struct NotifyTrafficMessage *ntm;
874 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
877 /* recovery strategy: throw performance data away... */
878 size = msize + sizeof (struct NotifyTrafficMessage);
880 if (! ( (0 != (all_client_options & options)) ||
881 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
882 return; /* no client cares about this message notification */
883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884 "Core service passes message from `%s' of type %u to client.\n",
886 (unsigned int) ntohs (msg->type));
887 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
888 ntm = (struct NotifyTrafficMessage *) buf;
889 ntm->header.size = htons (size);
890 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
891 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
893 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
895 GNUNET_memcpy (&ntm[1],
898 send_to_all_clients (sender,
907 * Initialize clients subsystem.
909 * @param server handle to server clients connect to
912 GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
914 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
915 {&handle_client_init, NULL,
916 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
917 {&GSC_KX_handle_client_monitor_peers, NULL,
918 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
919 sizeof (struct GNUNET_MessageHeader)},
920 {&handle_client_send_request, NULL,
921 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
922 sizeof (struct SendMessageRequest)},
923 {&handle_client_send, NULL,
924 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
928 /* setup notification */
929 client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
931 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
932 GNUNET_SERVER_disconnect_notify (server,
933 &handle_client_disconnect, NULL);
934 GNUNET_SERVER_add_handlers (server, handlers);
939 * Shutdown clients subsystem.
944 struct GSC_Client *c;
946 while (NULL != (c = client_head))
947 handle_client_disconnect (NULL, c->client_handle);
948 if (NULL != notifier)
950 GNUNET_SERVER_notification_context_destroy (notifier);
953 if (NULL != client_mst)
955 GNUNET_SERVER_mst_destroy (client_mst);
960 /* end of gnunet-service-core_clients.c */