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 it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
17 * @file core/gnunet-service-core.c
18 * @brief high-level P2P messaging
19 * @author Christian Grothoff
23 #include "gnunet_util_lib.h"
24 #include "gnunet-service-core.h"
25 #include "gnunet-service-core_kx.h"
26 #include "gnunet-service-core_sessions.h"
27 #include "gnunet-service-core_typemap.h"
30 * How many messages do we queue up at most for any client? This can
31 * cause messages to be dropped if clients do not process them fast
32 * enough! Note that this is a soft limit; we try
33 * to keep a few larger messages above the limit.
35 #define SOFT_MAX_QUEUE 128
38 * How many messages do we queue up at most for any client? This can
39 * cause messages to be dropped if clients do not process them fast
40 * enough! Note that this is the hard limit.
42 #define HARD_MAX_QUEUE 256
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_SERVICE_Client *client;
66 * Message queue to talk to @e client.
68 struct GNUNET_MQ_Handle *mq;
71 * Array of the types of messages this peer cares
72 * about (with @e tcnt entries). Allocated as part
73 * of this client struct, do not free!
78 * Map of peer identities to active transmission requests of this
79 * client to the peer (of type `struct GSC_ClientActiveRequest`).
81 struct GNUNET_CONTAINER_MultiPeerMap *requests;
84 * Map containing all peers that this client knows we're connected to.
86 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
89 * Options for messages this client cares about,
90 * see GNUNET_CORE_OPTION_ values.
95 * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message
96 * from this client already?
101 * Number of types of incoming messages this client
102 * specifically cares about. Size of the @e types array.
112 struct GNUNET_PeerIdentity GSC_my_identity;
117 const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
120 * For creating statistics.
122 struct GNUNET_STATISTICS_Handle *GSC_stats;
125 * Big "or" of all client options.
127 static uint32_t all_client_options;
130 * Head of linked list of our clients.
132 static struct GSC_Client *client_head;
135 * Tail of linked list of our clients.
137 static struct GSC_Client *client_tail;
141 * Test if the client is interested in messages of the given type.
143 * @param type message type
144 * @param c client to test
145 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
148 type_match (uint16_t type,
149 struct GSC_Client *c)
151 if ( (0 == c->tcnt) &&
153 return GNUNET_YES; /* peer without handlers and inbound/outbond
154 callbacks matches ALL */
155 if (NULL == c->types)
157 for (unsigned int i = 0; i < c->tcnt; i++)
158 if (type == c->types[i])
165 * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
167 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
168 * @param im the `struct InitMessage`
169 * @return #GNUNET_OK if @a im is well-formed
172 check_client_init (void *cls,
173 const struct InitMessage *im)
180 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
182 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
183 * @param im the `struct InitMessage`
186 handle_client_init (void *cls,
187 const struct InitMessage *im)
189 struct GSC_Client *c = cls;
190 struct GNUNET_MQ_Envelope *env;
191 struct InitReplyMessage *irm;
193 const uint16_t *types;
195 /* check that we don't have an entry already */
196 msize = ntohs (im->header.size) - sizeof (struct InitMessage);
197 types = (const uint16_t *) &im[1];
198 c->tcnt = msize / sizeof (uint16_t);
199 c->options = ntohl (im->options);
200 c->got_init = GNUNET_YES;
201 all_client_options |= c->options;
202 c->types = GNUNET_malloc (msize);
203 GNUNET_assert (GNUNET_YES ==
204 GNUNET_CONTAINER_multipeermap_put (c->connectmap,
207 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
208 for (unsigned int i = 0; i < c->tcnt; i++)
209 c->types[i] = ntohs (types[i]);
210 GSC_TYPEMAP_add (c->types,
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "Client connecting to core service is interested in %u message types\n",
214 (unsigned int) c->tcnt);
215 /* send init reply message */
216 env = GNUNET_MQ_msg (irm,
217 GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
218 irm->reserved = htonl (0);
219 irm->my_identity = GSC_my_identity;
220 GNUNET_MQ_send (c->mq,
222 GSC_SESSIONS_notify_client_about_sessions (c);
223 GNUNET_SERVICE_client_continue (c->client);
228 * We will never be ready to transmit the given message in (disconnect
229 * or invalid request). Frees resources associated with @a car. We
230 * don't explicitly tell the client, he'll learn with the disconnect
231 * (or violated the protocol).
233 * @param car request that now permanently failed; the
234 * responsibility for the handle is now returned
235 * to CLIENTS (SESSIONS is done with it).
236 * @param drop_client #GNUNET_YES if the client violated the protocol
237 * and we should thus drop the connection
240 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
243 GNUNET_assert (GNUNET_YES ==
244 GNUNET_CONTAINER_multipeermap_remove (car->
245 client_handle->requests,
248 if (GNUNET_YES == drop_client)
249 GNUNET_SERVICE_client_drop (car->client_handle->client);
255 * Tell a client that we are ready to receive the message.
257 * @param car request that is now ready; the responsibility
258 * for the handle remains shared between CLIENTS
259 * and SESSIONS after this call.
262 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
264 struct GSC_Client *c;
265 struct GNUNET_MQ_Envelope *env;
266 struct SendMessageReady *smr;
267 struct GNUNET_TIME_Relative delay;
268 struct GNUNET_TIME_Relative left;
270 c = car->client_handle;
272 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
275 /* connection has gone down since, drop request */
277 memcmp (&car->target,
279 sizeof (struct GNUNET_PeerIdentity)));
280 GSC_SESSIONS_dequeue_request (car);
281 GSC_CLIENTS_reject_request (car,
285 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
286 left = GNUNET_TIME_absolute_get_duration (car->deadline);
287 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
288 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
289 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
290 GNUNET_STRINGS_relative_time_to_string (delay,
292 GNUNET_i2s (&car->target),
293 (0 == left.rel_value_us)
297 env = GNUNET_MQ_msg (smr,
298 GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
299 smr->size = htons (car->msize);
300 smr->smr_id = car->smr_id;
301 smr->peer = car->target;
302 GNUNET_MQ_send (c->mq,
308 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
310 * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
311 * @param req the `struct SendMessageRequest`
314 handle_client_send_request (void *cls,
315 const struct SendMessageRequest *req)
317 struct GSC_Client *c = cls;
318 struct GSC_ClientActiveRequest *car;
321 if (NULL == c->requests)
322 c->requests = GNUNET_CONTAINER_multipeermap_create (16,
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
325 "Client asked for transmission to `%s'\n",
326 GNUNET_i2s (&req->peer));
331 sizeof (struct GNUNET_PeerIdentity)));
332 if ((! is_loopback) &&
334 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
337 /* neighbour must have disconnected since request was issued,
338 * ignore (client will realize it once it processes the
339 * disconnect notification) */
340 GNUNET_STATISTICS_update (GSC_stats,
342 ("# send requests dropped (disconnected)"), 1,
344 GNUNET_SERVICE_client_continue (c->client);
348 car = GNUNET_CONTAINER_multipeermap_get (c->requests,
352 /* create new entry */
353 car = GNUNET_new (struct GSC_ClientActiveRequest);
354 GNUNET_assert (GNUNET_OK ==
355 GNUNET_CONTAINER_multipeermap_put (c->requests,
358 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
359 car->client_handle = c;
363 /* dequeue and recycle memory from pending request, there can only
364 be at most one per client and peer */
365 GNUNET_STATISTICS_update (GSC_stats,
366 gettext_noop ("# dequeuing CAR (duplicate request)"),
369 GSC_SESSIONS_dequeue_request (car);
370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371 "Transmission request to `%s' was a duplicate!\n",
372 GNUNET_i2s (&req->peer));
374 car->target = req->peer;
375 car->received_time = GNUNET_TIME_absolute_get ();
376 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
377 car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
378 car->msize = ntohs (req->size);
379 car->smr_id = req->smr_id;
380 car->was_solicited = GNUNET_NO;
381 GNUNET_SERVICE_client_continue (c->client);
384 /* loopback, satisfy immediately */
385 GSC_CLIENTS_solicit_request (car);
388 GSC_SESSIONS_queue_request (car);
393 * Closure for the #client_tokenizer_callback().
395 struct TokenizerContext
399 * Active request handle for the message.
401 struct GSC_ClientActiveRequest *car;
404 * How important is this message.
406 enum GNUNET_CORE_Priority priority;
409 * Is corking allowed (set only once we have the real message).
417 * Functions with this signature are called whenever a complete
418 * message is received by the tokenizer. Used by
419 * #handle_client_send() for dispatching messages from clients to
420 * either the SESSION subsystem or other CLIENT (for loopback).
422 * @param cls reservation request (`struct TokenizerContext`)
423 * @param message the actual message
424 * @return #GNUNET_OK on success,
425 * #GNUNET_NO to stop further processing (no error)
426 * #GNUNET_SYSERR to stop further processing with error
429 tokenized_cb (void *cls,
430 const struct GNUNET_MessageHeader *message)
432 struct TokenizerContext *tc = cls;
433 struct GSC_ClientActiveRequest *car = tc->car;
436 GNUNET_snprintf (buf,
438 gettext_noop ("# bytes of messages of type %u received"),
439 (unsigned int) ntohs (message->type));
440 GNUNET_STATISTICS_update (GSC_stats,
442 ntohs (message->size),
445 memcmp (&car->target,
447 sizeof (struct GNUNET_PeerIdentity)))
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Delivering message of type %u to myself\n",
451 ntohs (message->type));
452 GSC_CLIENTS_deliver_message (&GSC_my_identity,
454 ntohs (message->size),
455 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
456 GSC_CLIENTS_deliver_message (&GSC_my_identity,
458 sizeof (struct GNUNET_MessageHeader),
459 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
460 GSC_CLIENTS_deliver_message (&GSC_my_identity,
462 ntohs (message->size),
463 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
464 GSC_CLIENTS_deliver_message (&GSC_my_identity,
466 sizeof (struct GNUNET_MessageHeader),
467 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472 "Delivering message of type %u and size %u to %s\n",
473 ntohs (message->type),
474 ntohs (message->size),
475 GNUNET_i2s (&car->target));
476 GSC_CLIENTS_deliver_message (&car->target,
478 ntohs (message->size),
479 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
480 GSC_CLIENTS_deliver_message (&car->target,
482 sizeof (struct GNUNET_MessageHeader),
483 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
484 GSC_SESSIONS_transmit (car,
494 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
496 * @param cls the `struct GSC_Client`
497 * @param sm the `struct SendMessage`
498 * @return #GNUNET_OK if @a sm is well-formed
501 check_client_send (void *cls,
502 const struct SendMessage *sm)
509 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
511 * @param cls the `struct GSC_Client`
512 * @param sm the `struct SendMessage`
515 handle_client_send (void *cls,
516 const struct SendMessage *sm)
518 struct GSC_Client *c = cls;
519 struct TokenizerContext tc;
521 struct GNUNET_TIME_Relative delay;
522 struct GNUNET_MessageStreamTokenizer *mst;
524 msize = ntohs (sm->header.size) - sizeof (struct SendMessage);
525 GNUNET_break (0 == ntohl (sm->reserved));
526 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
530 /* Must have been that we first approved the request, then got disconnected
531 * (which triggered removal of the 'car') and now the client gives us a message
532 * just *before* the client learns about the disconnect. Theoretically, we
533 * might also now be *again* connected. So this can happen (but should be
534 * rare). If it does happen, the message is discarded. */
535 GNUNET_STATISTICS_update (GSC_stats,
536 gettext_noop ("# messages discarded (session disconnected)"),
539 GNUNET_SERVICE_client_continue (c->client);
542 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
543 tc.cork = ntohl (sm->cork);
544 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
545 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
546 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
547 "Client waited %s for transmission of %u bytes to `%s'%s\n",
548 GNUNET_STRINGS_relative_time_to_string (delay,
551 GNUNET_i2s (&sm->peer),
552 tc.cork ? " (cork)" : " (uncorked)");
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 "Client waited %s for transmission of %u bytes to `%s'%s\n",
556 GNUNET_STRINGS_relative_time_to_string (delay,
559 GNUNET_i2s (&sm->peer),
560 tc.cork ? " (cork)" : " (uncorked)");
562 GNUNET_assert (GNUNET_YES ==
563 GNUNET_CONTAINER_multipeermap_remove (c->requests,
566 mst = GNUNET_MST_create (&tokenized_cb,
568 GNUNET_MST_from_buffer (mst,
569 (const char *) &sm[1],
573 GNUNET_MST_destroy (mst);
574 GSC_SESSIONS_dequeue_request (tc.car);
575 GNUNET_free (tc.car);
576 GNUNET_SERVICE_client_continue (c->client);
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 connected, set up.
610 * @param client identification of the client
611 * @param mq message queue to talk to @a client
612 * @return our client handle
615 client_connect_cb (void *cls,
616 struct GNUNET_SERVICE_Client *client,
617 struct GNUNET_MQ_Handle *mq)
619 struct GSC_Client *c;
621 c = GNUNET_new (struct GSC_Client);
624 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16,
626 GNUNET_CONTAINER_DLL_insert (client_head,
634 * A client disconnected, clean up.
637 * @param client identification of the client
638 * @param app_ctx our `struct GST_Client` for @a client
641 client_disconnect_cb (void *cls,
642 struct GNUNET_SERVICE_Client *client,
645 struct GSC_Client *c = app_ctx;
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648 "Client %p has disconnected from core service.\n",
650 GNUNET_CONTAINER_DLL_remove (client_head,
653 if (NULL != c->requests)
655 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
656 &destroy_active_client_request,
658 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
660 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
661 c->connectmap = NULL;
662 if (NULL != c->types)
664 GSC_TYPEMAP_remove (c->types,
666 GNUNET_free (c->types);
670 /* recalculate 'all_client_options' */
671 all_client_options = 0;
672 for (c = client_head; NULL != c ; c = c->next)
673 all_client_options |= c->options;
678 * Notify a particular client about a change to existing connection to
679 * one of our neighbours (check if the client is interested). Called
680 * from #GSC_SESSIONS_notify_client_about_sessions().
682 * @param client client to notify
683 * @param neighbour identity of the neighbour that changed status
684 * @param tmap_old previous type map for the neighbour, NULL for connect
685 * @param tmap_new updated type map for the neighbour, NULL for disconnect
688 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
689 const struct GNUNET_PeerIdentity *neighbour,
690 const struct GSC_TypeMap *tmap_old,
691 const struct GSC_TypeMap *tmap_new)
693 struct GNUNET_MQ_Envelope *env;
697 if (GNUNET_YES != client->got_init)
699 old_match = GSC_TYPEMAP_test_match (tmap_old,
702 new_match = GSC_TYPEMAP_test_match (tmap_new,
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706 "Notifying client about neighbour %s (%d/%d)\n",
707 GNUNET_i2s (neighbour),
710 if (old_match == new_match)
712 GNUNET_assert (old_match ==
713 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
715 return; /* no change */
717 if (GNUNET_NO == old_match)
719 struct ConnectNotifyMessage *cnm;
722 GNUNET_assert (GNUNET_NO ==
723 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
725 GNUNET_assert (GNUNET_YES ==
726 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
729 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
730 env = GNUNET_MQ_msg (cnm,
731 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
732 cnm->reserved = htonl (0);
733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
735 GNUNET_i2s (neighbour));
736 cnm->peer = *neighbour;
737 GNUNET_MQ_send (client->mq,
742 struct DisconnectNotifyMessage *dcm;
744 /* send disconnect */
745 GNUNET_assert (GNUNET_YES ==
746 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
748 GNUNET_assert (GNUNET_YES ==
749 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
752 env = GNUNET_MQ_msg (dcm,
753 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
754 dcm->reserved = htonl (0);
755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
757 GNUNET_i2s (neighbour));
758 dcm->peer = *neighbour;
759 GNUNET_MQ_send (client->mq,
766 * Notify all clients about a change to existing session.
767 * Called from SESSIONS whenever there is a change in sessions
768 * or types processed by the respective peer.
770 * @param neighbour identity of the neighbour that changed status
771 * @param tmap_old previous type map for the neighbour, NULL for connect
772 * @param tmap_new updated type map for the neighbour, NULL for disconnect
775 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
776 const struct GSC_TypeMap *tmap_old,
777 const struct GSC_TypeMap *tmap_new)
779 struct GSC_Client *c;
781 for (c = client_head; NULL != c; c = c->next)
782 GSC_CLIENTS_notify_client_about_neighbour (c,
790 * Deliver P2P message to interested clients. Caller must have checked
791 * that the sending peer actually lists the given message type as one
794 * @param sender peer who sent us the message
795 * @param msg the message
796 * @param msize number of bytes to transmit
797 * @param options options for checking which clients should
798 * receive the message
801 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
802 const struct GNUNET_MessageHeader *msg,
806 size_t size = msize + sizeof (struct NotifyTrafficMessage);
808 if (size >= GNUNET_MAX_MESSAGE_SIZE)
813 if (! ( (0 != (all_client_options & options)) ||
814 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
815 return; /* no client cares about this message notification */
816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
817 "Core service passes message from `%s' of type %u to client.\n",
819 (unsigned int) ntohs (msg->type));
820 GSC_SESSIONS_add_to_typemap (sender,
823 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
825 struct GNUNET_MQ_Envelope *env;
826 struct NotifyTrafficMessage *ntm;
831 tm = type_match (ntohs (msg->type),
833 if (! ( (0 != (c->options & options)) ||
834 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
835 (GNUNET_YES == tm) ) ) )
836 continue; /* neither options nor type match permit the message */
837 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
838 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
839 (GNUNET_YES == tm) ) )
841 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
842 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
846 1) We are above the hard limit, or
847 2) We are above the soft limit, and a coin toss limited
848 to the message size (giving larger messages a
849 proportionally higher chance of being queued) falls
850 below the threshold. The threshold is based on where
851 we are between the soft and the hard limit, scaled
852 to match the range of message sizes we usually encounter
853 (i.e. up to 32k); so a 64k message has a 50% chance of
854 being kept if we are just barely below the hard max,
855 and a 99% chance of being kept if we are at the soft max.
856 The reason is to make it more likely to drop control traffic
857 (ACK, queries) which may be cummulative or highly redundant,
858 and cheap to drop than data traffic. */
859 qlen = GNUNET_MQ_get_length (c->mq);
860 if ( (qlen >= HARD_MAX_QUEUE) ||
861 ( (qlen > SOFT_MAX_QUEUE) &&
862 ( (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
863 ntohs (msg->size)) ) <
864 (qlen - SOFT_MAX_QUEUE) * 0x8000 /
865 (HARD_MAX_QUEUE - SOFT_MAX_QUEUE) ) ) )
869 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
870 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
871 (unsigned int) ntohs (msg->type));
872 GNUNET_snprintf (buf,
874 gettext_noop ("# messages of type %u discarded (client busy)"),
875 (unsigned int) ntohs (msg->type));
876 GNUNET_STATISTICS_update (GSC_stats,
883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
887 (unsigned int) ntohs (msg->type));
889 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
890 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
892 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
893 env = GNUNET_MQ_msg_extra (ntm,
897 GNUNET_memcpy (&ntm[1],
901 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
902 (GNUNET_YES != tm) ||
904 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
906 GNUNET_MQ_send (c->mq,
913 * Last task run during shutdown. Disconnects us from
916 * @param cls NULL, unused
919 shutdown_task (void *cls)
921 struct GSC_Client *c;
923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924 "Core service shutting down.\n");
925 while (NULL != (c = client_head))
926 GNUNET_SERVICE_client_drop (c->client);
927 GSC_SESSIONS_done ();
930 if (NULL != GSC_stats)
932 GNUNET_STATISTICS_destroy (GSC_stats,
941 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
942 * request type, the client does not have to have transmitted an INIT
943 * request. All current peers are returned, regardless of which
944 * message types they accept.
946 * @param cls client sending the iteration request
947 * @param message iteration request message
950 handle_client_monitor_peers (void *cls,
951 const struct GNUNET_MessageHeader *message)
953 struct GSC_Client *c = cls;
955 GNUNET_SERVICE_client_continue (c->client);
956 GSC_KX_handle_client_monitor_peers (c->mq);
961 * Initiate core service.
964 * @param c configuration to use
965 * @param service the initialized service
969 const struct GNUNET_CONFIGURATION_Handle *c,
970 struct GNUNET_SERVICE_Handle *service)
972 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
977 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
982 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
983 _("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
984 GNUNET_SCHEDULER_shutdown ();
987 GSC_stats = GNUNET_STATISTICS_create ("core",
989 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
991 GNUNET_SERVICE_suspend (service);
993 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
994 GNUNET_free (keyfile);
995 GNUNET_assert (NULL != pk);
996 if (GNUNET_OK != GSC_KX_init (pk))
998 GNUNET_SCHEDULER_shutdown ();
1001 GSC_SESSIONS_init ();
1002 GNUNET_SERVICE_resume (service);
1003 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1004 _("Core service of `%s' ready.\n"),
1005 GNUNET_i2s (&GSC_my_identity));
1010 * Define "main" method using service macro.
1014 GNUNET_SERVICE_OPTION_NONE,
1017 &client_disconnect_cb,
1019 GNUNET_MQ_hd_var_size (client_init,
1020 GNUNET_MESSAGE_TYPE_CORE_INIT,
1023 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
1024 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
1025 struct GNUNET_MessageHeader,
1027 GNUNET_MQ_hd_fixed_size (client_send_request,
1028 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
1029 struct SendMessageRequest,
1031 GNUNET_MQ_hd_var_size (client_send,
1032 GNUNET_MESSAGE_TYPE_CORE_SEND,
1035 GNUNET_MQ_handler_end ());
1038 /* end of gnunet-service-core.c */