2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 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.c
23 * @brief high-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet-service-core.h"
30 #include "gnunet-service-core_kx.h"
31 #include "gnunet-service-core_sessions.h"
32 #include "gnunet-service-core_typemap.h"
35 * How many messages do we queue up at most for any client? This can
36 * cause messages to be dropped if clients do not process them fast
37 * enough! Note that this is a soft limit; we try
38 * to keep a few larger messages above the limit.
40 #define SOFT_MAX_QUEUE 128
43 * How many messages do we queue up at most for any client? This can
44 * cause messages to be dropped if clients do not process them fast
45 * enough! Note that this is the hard limit.
47 #define HARD_MAX_QUEUE 256
51 * Data structure for each client connected to the CORE service.
56 * Clients are kept in a linked list.
58 struct GSC_Client *next;
61 * Clients are kept in a linked list.
63 struct GSC_Client *prev;
66 * Handle for the client with the server API.
68 struct GNUNET_SERVICE_Client *client;
71 * Message queue to talk to @e client.
73 struct GNUNET_MQ_Handle *mq;
76 * Array of the types of messages this peer cares
77 * about (with @e tcnt entries). Allocated as part
78 * of this client struct, do not free!
83 * Map of peer identities to active transmission requests of this
84 * client to the peer (of type `struct GSC_ClientActiveRequest`).
86 struct GNUNET_CONTAINER_MultiPeerMap *requests;
89 * Map containing all peers that this client knows we're connected to.
91 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
94 * Options for messages this client cares about,
95 * see GNUNET_CORE_OPTION_ values.
100 * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message
101 * from this client already?
106 * Number of types of incoming messages this client
107 * specifically cares about. Size of the @e types array.
117 struct GNUNET_PeerIdentity GSC_my_identity;
122 const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
125 * For creating statistics.
127 struct GNUNET_STATISTICS_Handle *GSC_stats;
130 * Big "or" of all client options.
132 static uint32_t all_client_options;
135 * Head of linked list of our clients.
137 static struct GSC_Client *client_head;
140 * Tail of linked list of our clients.
142 static struct GSC_Client *client_tail;
146 * Test if the client is interested in messages of the given type.
148 * @param type message type
149 * @param c client to test
150 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
153 type_match (uint16_t type,
154 struct GSC_Client *c)
156 if ( (0 == c->tcnt) &&
158 return GNUNET_YES; /* peer without handlers and inbound/outbond
159 callbacks matches ALL */
160 if (NULL == c->types)
162 for (unsigned int i = 0; i < c->tcnt; i++)
163 if (type == c->types[i])
170 * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
172 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
173 * @param im the `struct InitMessage`
174 * @return #GNUNET_OK if @a im is well-formed
177 check_client_init (void *cls,
178 const struct InitMessage *im)
185 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
187 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
188 * @param im the `struct InitMessage`
191 handle_client_init (void *cls,
192 const struct InitMessage *im)
194 struct GSC_Client *c = cls;
195 struct GNUNET_MQ_Envelope *env;
196 struct InitReplyMessage *irm;
198 const uint16_t *types;
200 /* check that we don't have an entry already */
201 msize = ntohs (im->header.size) - sizeof (struct InitMessage);
202 types = (const uint16_t *) &im[1];
203 c->tcnt = msize / sizeof (uint16_t);
204 c->options = ntohl (im->options);
205 c->got_init = GNUNET_YES;
206 all_client_options |= c->options;
207 c->types = GNUNET_malloc (msize);
208 GNUNET_assert (GNUNET_YES ==
209 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
212 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
213 for (unsigned int i = 0; i < c->tcnt; i++)
214 c->types[i] = ntohs (types[i]);
215 GSC_TYPEMAP_add (c->types,
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218 "Client connecting to core service is interested in %u message types\n",
219 (unsigned int) c->tcnt);
220 /* send init reply message */
221 env = GNUNET_MQ_msg (irm,
222 GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
223 irm->reserved = htonl (0);
224 irm->my_identity = GSC_my_identity;
225 GNUNET_MQ_send (c->mq,
227 GSC_SESSIONS_notify_client_about_sessions (c);
228 GNUNET_SERVICE_client_continue (c->client);
233 * We will never be ready to transmit the given message in (disconnect
234 * or invalid request). Frees resources associated with @a car. We
235 * don't explicitly tell the client, he'll learn with the disconnect
236 * (or violated the protocol).
238 * @param car request that now permanently failed; the
239 * responsibility for the handle is now returned
240 * to CLIENTS (SESSIONS is done with it).
241 * @param drop_client #GNUNET_YES if the client violated the protocol
242 * and we should thus drop the connection
245 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
248 GNUNET_assert (GNUNET_YES ==
249 GNUNET_CONTAINER_multipeermap_remove (car->
250 client_handle->requests,
253 if (GNUNET_YES == drop_client)
254 GNUNET_SERVICE_client_drop (car->client_handle->client);
260 * Tell a client that we are ready to receive the message.
262 * @param car request that is now ready; the responsibility
263 * for the handle remains shared between CLIENTS
264 * and SESSIONS after this call.
267 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
269 struct GSC_Client *c;
270 struct GNUNET_MQ_Envelope *env;
271 struct SendMessageReady *smr;
272 struct GNUNET_TIME_Relative delay;
273 struct GNUNET_TIME_Relative left;
275 c = car->client_handle;
277 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
280 /* connection has gone down since, drop request */
282 memcmp (&car->target,
284 sizeof (struct GNUNET_PeerIdentity)));
285 GSC_SESSIONS_dequeue_request (car);
286 GSC_CLIENTS_reject_request (car,
290 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
291 left = GNUNET_TIME_absolute_get_duration (car->deadline);
292 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
293 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
294 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
295 GNUNET_STRINGS_relative_time_to_string (delay,
297 GNUNET_i2s (&car->target),
298 (0 == left.rel_value_us)
302 env = GNUNET_MQ_msg (smr,
303 GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
304 smr->size = htons (car->msize);
305 smr->smr_id = car->smr_id;
306 smr->peer = car->target;
307 GNUNET_MQ_send (c->mq,
313 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
315 * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
316 * @param req the `struct SendMessageRequest`
319 handle_client_send_request (void *cls,
320 const struct SendMessageRequest *req)
322 struct GSC_Client *c = cls;
323 struct GSC_ClientActiveRequest *car;
326 if (NULL == c->requests)
327 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
330 "Client asked for transmission to `%s'\n",
331 GNUNET_i2s (&req->peer));
336 sizeof (struct GNUNET_PeerIdentity)));
337 if ((! is_loopback) &&
339 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
342 /* neighbour must have disconnected since request was issued,
343 * ignore (client will realize it once it processes the
344 * disconnect notification) */
345 GNUNET_STATISTICS_update (GSC_stats,
347 ("# send requests dropped (disconnected)"), 1,
349 GNUNET_SERVICE_client_continue (c->client);
353 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
357 /* create new entry */
358 car = GNUNET_new (struct GSC_ClientActiveRequest);
359 GNUNET_assert (GNUNET_OK ==
360 GNUNET_CONTAINER_multipeermap_put (c->requests,
363 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
364 car->client_handle = c;
368 /* dequeue and recycle memory from pending request, there can only
369 be at most one per client and peer */
370 GNUNET_STATISTICS_update (GSC_stats,
371 gettext_noop ("# dequeuing CAR (duplicate request)"),
374 GSC_SESSIONS_dequeue_request (car);
375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376 "Transmission request to `%s' was a duplicate!\n",
377 GNUNET_i2s (&req->peer));
379 car->target = req->peer;
380 car->received_time = GNUNET_TIME_absolute_get ();
381 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
382 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
383 car->msize = ntohs (req->size);
384 car->smr_id = req->smr_id;
385 car->was_solicited = GNUNET_NO;
386 GNUNET_SERVICE_client_continue (c->client);
389 /* loopback, satisfy immediately */
390 GSC_CLIENTS_solicit_request (car);
393 GSC_SESSIONS_queue_request (car);
398 * Closure for the #client_tokenizer_callback().
400 struct TokenizerContext
404 * Active request handle for the message.
406 struct GSC_ClientActiveRequest *car;
409 * How important is this message.
411 enum GNUNET_CORE_Priority priority;
414 * Is corking allowed (set only once we have the real message).
422 * Functions with this signature are called whenever a complete
423 * message is received by the tokenizer. Used by
424 * #handle_client_send() for dispatching messages from clients to
425 * either the SESSION subsystem or other CLIENT (for loopback).
427 * @param cls reservation request (`struct TokenizerContext`)
428 * @param message the actual message
431 tokenized_cb (void *cls,
432 const struct GNUNET_MessageHeader *message)
434 struct TokenizerContext *tc = cls;
435 struct GSC_ClientActiveRequest *car = tc->car;
438 GNUNET_snprintf (buf,
440 gettext_noop ("# bytes of messages of type %u received"),
441 (unsigned int) ntohs (message->type));
442 GNUNET_STATISTICS_update (GSC_stats,
444 ntohs (message->size),
447 memcmp (&car->target,
449 sizeof (struct GNUNET_PeerIdentity)))
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 "Delivering message of type %u to myself\n",
453 ntohs (message->type));
454 GSC_CLIENTS_deliver_message (&GSC_my_identity,
456 ntohs (message->size),
457 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
458 GSC_CLIENTS_deliver_message (&GSC_my_identity,
460 sizeof (struct GNUNET_MessageHeader),
461 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
462 GSC_CLIENTS_deliver_message (&GSC_my_identity,
464 ntohs (message->size),
465 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
466 GSC_CLIENTS_deliver_message (&GSC_my_identity,
468 sizeof (struct GNUNET_MessageHeader),
469 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "Delivering message of type %u and size %u to %s\n",
475 ntohs (message->type),
476 ntohs (message->size),
477 GNUNET_i2s (&car->target));
478 GSC_CLIENTS_deliver_message (&car->target,
480 ntohs (message->size),
481 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
482 GSC_CLIENTS_deliver_message (&car->target,
484 sizeof (struct GNUNET_MessageHeader),
485 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
486 GSC_SESSIONS_transmit (car,
496 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
498 * @param cls the `struct GSC_Client`
499 * @param sm the `struct SendMessage`
500 * @return #GNUNET_OK if @a sm is well-formed
503 check_client_send (void *cls,
504 const struct SendMessage *sm)
511 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
513 * @param cls the `struct GSC_Client`
514 * @param sm the `struct SendMessage`
517 handle_client_send (void *cls,
518 const struct SendMessage *sm)
520 struct GSC_Client *c = cls;
521 struct TokenizerContext tc;
523 struct GNUNET_TIME_Relative delay;
524 struct GNUNET_MessageStreamTokenizer *mst;
526 msize = ntohs (sm->header.size) - sizeof (struct SendMessage);
527 GNUNET_break (0 == ntohl (sm->reserved));
528 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
532 /* Must have been that we first approved the request, then got disconnected
533 * (which triggered removal of the 'car') and now the client gives us a message
534 * just *before* the client learns about the disconnect. Theoretically, we
535 * might also now be *again* connected. So this can happen (but should be
536 * rare). If it does happen, the message is discarded. */
537 GNUNET_STATISTICS_update (GSC_stats,
538 gettext_noop ("# messages discarded (session disconnected)"),
541 GNUNET_SERVICE_client_continue (c->client);
544 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
545 tc.cork = ntohl (sm->cork);
546 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
547 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
548 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
549 "Client waited %s for transmission of %u bytes to `%s'%s\n",
550 GNUNET_STRINGS_relative_time_to_string (delay,
553 GNUNET_i2s (&sm->peer),
554 tc.cork ? " (cork)" : " (uncorked)");
556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557 "Client waited %s for transmission of %u bytes to `%s'%s\n",
558 GNUNET_STRINGS_relative_time_to_string (delay,
561 GNUNET_i2s (&sm->peer),
562 tc.cork ? " (cork)" : " (uncorked)");
564 GNUNET_assert (GNUNET_YES ==
565 GNUNET_CONTAINER_multipeermap_remove (c->requests,
568 mst = GNUNET_MST_create (&tokenized_cb,
570 GNUNET_MST_from_buffer (mst,
571 (const char *) &sm[1],
575 GNUNET_MST_destroy (mst);
576 GSC_SESSIONS_dequeue_request (tc.car);
577 GNUNET_free (tc.car);
578 GNUNET_SERVICE_client_continue (c->client);
583 * Free client request records.
586 * @param key identity of peer for which this is an active request
587 * @param value the `struct GSC_ClientActiveRequest` to free
588 * @return #GNUNET_YES (continue iteration)
591 destroy_active_client_request (void *cls,
592 const struct GNUNET_PeerIdentity *key,
595 struct GSC_ClientActiveRequest *car = value;
597 GNUNET_assert (GNUNET_YES ==
598 GNUNET_CONTAINER_multipeermap_remove (car->
599 client_handle->requests,
602 GSC_SESSIONS_dequeue_request (car);
609 * A client connected, set up.
612 * @param client identification of the client
613 * @param mq message queue to talk to @a client
614 * @return our client handle
617 client_connect_cb (void *cls,
618 struct GNUNET_SERVICE_Client *client,
619 struct GNUNET_MQ_Handle *mq)
621 struct GSC_Client *c;
623 c = GNUNET_new (struct GSC_Client);
626 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16,
628 GNUNET_CONTAINER_DLL_insert (client_head,
636 * A client disconnected, clean up.
639 * @param client identification of the client
640 * @param app_ctx our `struct GST_Client` for @a client
643 client_disconnect_cb (void *cls,
644 struct GNUNET_SERVICE_Client *client,
647 struct GSC_Client *c = app_ctx;
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650 "Client %p has disconnected from core service.\n",
652 GNUNET_CONTAINER_DLL_remove (client_head,
655 if (NULL != c->requests)
657 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
658 &destroy_active_client_request,
660 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
662 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
663 c->connectmap = NULL;
664 if (NULL != c->types)
666 GSC_TYPEMAP_remove (c->types,
668 GNUNET_free (c->types);
672 /* recalculate 'all_client_options' */
673 all_client_options = 0;
674 for (c = client_head; NULL != c ; c = c->next)
675 all_client_options |= c->options;
680 * Notify a particular client about a change to existing connection to
681 * one of our neighbours (check if the client is interested). Called
682 * from #GSC_SESSIONS_notify_client_about_sessions().
684 * @param client client to notify
685 * @param neighbour identity of the neighbour that changed status
686 * @param tmap_old previous type map for the neighbour, NULL for connect
687 * @param tmap_new updated type map for the neighbour, NULL for disconnect
690 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
691 const struct GNUNET_PeerIdentity *neighbour,
692 const struct GSC_TypeMap *tmap_old,
693 const struct GSC_TypeMap *tmap_new)
695 struct GNUNET_MQ_Envelope *env;
699 if (GNUNET_YES != client->got_init)
701 old_match = GSC_TYPEMAP_test_match (tmap_old,
704 new_match = GSC_TYPEMAP_test_match (tmap_new,
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708 "Notifying client about neighbour %s (%d/%d)\n",
709 GNUNET_i2s (neighbour),
712 if (old_match == new_match)
714 GNUNET_assert (old_match ==
715 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
717 return; /* no change */
719 if (GNUNET_NO == old_match)
721 struct ConnectNotifyMessage *cnm;
724 GNUNET_assert (GNUNET_NO ==
725 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
727 GNUNET_assert (GNUNET_YES ==
728 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
731 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
732 env = GNUNET_MQ_msg (cnm,
733 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
734 cnm->reserved = htonl (0);
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
737 GNUNET_i2s (neighbour));
738 cnm->peer = *neighbour;
739 GNUNET_MQ_send (client->mq,
744 struct DisconnectNotifyMessage *dcm;
746 /* send disconnect */
747 GNUNET_assert (GNUNET_YES ==
748 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
750 GNUNET_assert (GNUNET_YES ==
751 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
754 env = GNUNET_MQ_msg (dcm,
755 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
756 dcm->reserved = htonl (0);
757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
758 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
759 GNUNET_i2s (neighbour));
760 dcm->peer = *neighbour;
761 GNUNET_MQ_send (client->mq,
768 * Notify all clients about a change to existing session.
769 * Called from SESSIONS whenever there is a change in sessions
770 * or types processed by the respective peer.
772 * @param neighbour identity of the neighbour that changed status
773 * @param tmap_old previous type map for the neighbour, NULL for connect
774 * @param tmap_new updated type map for the neighbour, NULL for disconnect
777 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
778 const struct GSC_TypeMap *tmap_old,
779 const struct GSC_TypeMap *tmap_new)
781 struct GSC_Client *c;
783 for (c = client_head; NULL != c; c = c->next)
784 GSC_CLIENTS_notify_client_about_neighbour (c,
792 * Deliver P2P message to interested clients. Caller must have checked
793 * that the sending peer actually lists the given message type as one
796 * @param sender peer who sent us the message
797 * @param msg the message
798 * @param msize number of bytes to transmit
799 * @param options options for checking which clients should
800 * receive the message
803 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
804 const struct GNUNET_MessageHeader *msg,
808 size_t size = msize + sizeof (struct NotifyTrafficMessage);
810 if (size >= GNUNET_MAX_MESSAGE_SIZE)
815 if (! ( (0 != (all_client_options & options)) ||
816 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
817 return; /* no client cares about this message notification */
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Core service passes message from `%s' of type %u to client.\n",
821 (unsigned int) ntohs (msg->type));
822 GSC_SESSIONS_add_to_typemap (sender,
825 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
827 struct GNUNET_MQ_Envelope *env;
828 struct NotifyTrafficMessage *ntm;
833 tm = type_match (ntohs (msg->type),
835 if (! ( (0 != (c->options & options)) ||
836 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
837 (GNUNET_YES == tm) ) ) )
838 continue; /* neither options nor type match permit the message */
839 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
840 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
841 (GNUNET_YES == tm) ) )
843 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
844 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
848 1) We are above the hard limit, or
849 2) We are above the soft limit, and a coin toss limited
850 to the message size (giving larger messages a
851 proportionally higher chance of being queued) falls
852 below the threshold. The threshold is based on where
853 we are between the soft and the hard limit, scaled
854 to match the range of message sizes we usually encounter
855 (i.e. up to 32k); so a 64k message has a 50% chance of
856 being kept if we are just barely below the hard max,
857 and a 99% chance of being kept if we are at the soft max.
858 The reason is to make it more likely to drop control traffic
859 (ACK, queries) which may be cummulative or highly redundant,
860 and cheap to drop than data traffic. */
861 qlen = GNUNET_MQ_get_length (c->mq);
862 if ( (qlen >= HARD_MAX_QUEUE) ||
863 ( (qlen > SOFT_MAX_QUEUE) &&
864 ( (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
865 ntohs (msg->size)) ) <
866 (qlen - SOFT_MAX_QUEUE) * 0x8000 /
867 (HARD_MAX_QUEUE - SOFT_MAX_QUEUE) ) ) )
871 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
872 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
873 (unsigned int) ntohs (msg->type));
874 GNUNET_snprintf (buf,
876 gettext_noop ("# messages of type %u discarded (client busy)"),
877 (unsigned int) ntohs (msg->type));
878 GNUNET_STATISTICS_update (GSC_stats,
885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
889 (unsigned int) ntohs (msg->type));
891 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
892 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
894 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
895 env = GNUNET_MQ_msg_extra (ntm,
899 GNUNET_memcpy (&ntm[1],
903 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
904 (GNUNET_YES != tm) ||
906 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
908 GNUNET_MQ_send (c->mq,
915 * Last task run during shutdown. Disconnects us from
918 * @param cls NULL, unused
921 shutdown_task (void *cls)
923 struct GSC_Client *c;
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
926 "Core service shutting down.\n");
927 while (NULL != (c = client_head))
928 GNUNET_SERVICE_client_drop (c->client);
929 GSC_SESSIONS_done ();
932 if (NULL != GSC_stats)
934 GNUNET_STATISTICS_destroy (GSC_stats,
943 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
944 * request type, the client does not have to have transmitted an INIT
945 * request. All current peers are returned, regardless of which
946 * message types they accept.
948 * @param cls client sending the iteration request
949 * @param message iteration request message
952 handle_client_monitor_peers (void *cls,
953 const struct GNUNET_MessageHeader *message)
955 struct GSC_Client *c = cls;
957 GNUNET_SERVICE_client_continue (c->client);
958 GSC_KX_handle_client_monitor_peers (c->mq);
963 * Initiate core service.
966 * @param c configuration to use
967 * @param service the initialized service
971 const struct GNUNET_CONFIGURATION_Handle *c,
972 struct GNUNET_SERVICE_Handle *service)
974 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
979 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
985 _("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
986 GNUNET_SCHEDULER_shutdown ();
989 GSC_stats = GNUNET_STATISTICS_create ("core",
991 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
993 GNUNET_SERVICE_suspend (service);
995 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
996 GNUNET_free (keyfile);
997 GNUNET_assert (NULL != pk);
998 if (GNUNET_OK != GSC_KX_init (pk))
1000 GNUNET_SCHEDULER_shutdown ();
1003 GSC_SESSIONS_init ();
1004 GNUNET_SERVICE_resume (service);
1005 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1006 _("Core service of `%s' ready.\n"),
1007 GNUNET_i2s (&GSC_my_identity));
1012 * Define "main" method using service macro.
1016 GNUNET_SERVICE_OPTION_NONE,
1019 &client_disconnect_cb,
1021 GNUNET_MQ_hd_var_size (client_init,
1022 GNUNET_MESSAGE_TYPE_CORE_INIT,
1025 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
1026 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
1027 struct GNUNET_MessageHeader,
1029 GNUNET_MQ_hd_fixed_size (client_send_request,
1030 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
1031 struct SendMessageRequest,
1033 GNUNET_MQ_hd_var_size (client_send,
1034 GNUNET_MESSAGE_TYPE_CORE_SEND,
1037 GNUNET_MQ_handler_end ());
1040 /* end of gnunet-service-core.c */