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 Affero 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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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, it'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
429 * @return #GNUNET_OK on success,
430 * #GNUNET_NO to stop further processing (no error)
431 * #GNUNET_SYSERR to stop further processing with error
434 tokenized_cb (void *cls,
435 const struct GNUNET_MessageHeader *message)
437 struct TokenizerContext *tc = cls;
438 struct GSC_ClientActiveRequest *car = tc->car;
441 GNUNET_snprintf (buf,
443 gettext_noop ("# bytes of messages of type %u received"),
444 (unsigned int) ntohs (message->type));
445 GNUNET_STATISTICS_update (GSC_stats,
447 ntohs (message->size),
450 memcmp (&car->target,
452 sizeof (struct GNUNET_PeerIdentity)))
454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "Delivering message of type %u to myself\n",
456 ntohs (message->type));
457 GSC_CLIENTS_deliver_message (&GSC_my_identity,
459 ntohs (message->size),
460 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
461 GSC_CLIENTS_deliver_message (&GSC_my_identity,
463 sizeof (struct GNUNET_MessageHeader),
464 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
465 GSC_CLIENTS_deliver_message (&GSC_my_identity,
467 ntohs (message->size),
468 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
469 GSC_CLIENTS_deliver_message (&GSC_my_identity,
471 sizeof (struct GNUNET_MessageHeader),
472 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
477 "Delivering message of type %u and size %u to %s\n",
478 ntohs (message->type),
479 ntohs (message->size),
480 GNUNET_i2s (&car->target));
481 GSC_CLIENTS_deliver_message (&car->target,
483 ntohs (message->size),
484 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
485 GSC_CLIENTS_deliver_message (&car->target,
487 sizeof (struct GNUNET_MessageHeader),
488 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
489 GSC_SESSIONS_transmit (car,
499 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
501 * @param cls the `struct GSC_Client`
502 * @param sm the `struct SendMessage`
503 * @return #GNUNET_OK if @a sm is well-formed
506 check_client_send (void *cls,
507 const struct SendMessage *sm)
514 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
516 * @param cls the `struct GSC_Client`
517 * @param sm the `struct SendMessage`
520 handle_client_send (void *cls,
521 const struct SendMessage *sm)
523 struct GSC_Client *c = cls;
524 struct TokenizerContext tc;
526 struct GNUNET_TIME_Relative delay;
527 struct GNUNET_MessageStreamTokenizer *mst;
529 msize = ntohs (sm->header.size) - sizeof (struct SendMessage);
530 GNUNET_break (0 == ntohl (sm->reserved));
531 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
535 /* Must have been that we first approved the request, then got disconnected
536 * (which triggered removal of the 'car') and now the client gives us a message
537 * just *before* the client learns about the disconnect. Theoretically, we
538 * might also now be *again* connected. So this can happen (but should be
539 * rare). If it does happen, the message is discarded. */
540 GNUNET_STATISTICS_update (GSC_stats,
541 gettext_noop ("# messages discarded (session disconnected)"),
544 GNUNET_SERVICE_client_continue (c->client);
547 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
548 tc.cork = ntohl (sm->cork);
549 tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
550 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
551 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
552 "Client waited %s for transmission of %u bytes to `%s'%s\n",
553 GNUNET_STRINGS_relative_time_to_string (delay,
556 GNUNET_i2s (&sm->peer),
557 tc.cork ? " (cork)" : " (uncorked)");
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Client waited %s for transmission of %u bytes to `%s'%s\n",
561 GNUNET_STRINGS_relative_time_to_string (delay,
564 GNUNET_i2s (&sm->peer),
565 tc.cork ? " (cork)" : " (uncorked)");
567 GNUNET_assert (GNUNET_YES ==
568 GNUNET_CONTAINER_multipeermap_remove (c->requests,
571 mst = GNUNET_MST_create (&tokenized_cb,
573 GNUNET_MST_from_buffer (mst,
574 (const char *) &sm[1],
578 GNUNET_MST_destroy (mst);
579 GSC_SESSIONS_dequeue_request (tc.car);
580 GNUNET_free (tc.car);
581 GNUNET_SERVICE_client_continue (c->client);
586 * Free client request records.
589 * @param key identity of peer for which this is an active request
590 * @param value the `struct GSC_ClientActiveRequest` to free
591 * @return #GNUNET_YES (continue iteration)
594 destroy_active_client_request (void *cls,
595 const struct GNUNET_PeerIdentity *key,
598 struct GSC_ClientActiveRequest *car = value;
600 GNUNET_assert (GNUNET_YES ==
601 GNUNET_CONTAINER_multipeermap_remove (car->
602 client_handle->requests,
605 GSC_SESSIONS_dequeue_request (car);
612 * A client connected, set up.
615 * @param client identification of the client
616 * @param mq message queue to talk to @a client
617 * @return our client handle
620 client_connect_cb (void *cls,
621 struct GNUNET_SERVICE_Client *client,
622 struct GNUNET_MQ_Handle *mq)
624 struct GSC_Client *c;
626 c = GNUNET_new (struct GSC_Client);
629 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16,
631 GNUNET_CONTAINER_DLL_insert (client_head,
639 * A client disconnected, clean up.
642 * @param client identification of the client
643 * @param app_ctx our `struct GST_Client` for @a client
646 client_disconnect_cb (void *cls,
647 struct GNUNET_SERVICE_Client *client,
650 struct GSC_Client *c = app_ctx;
652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653 "Client %p has disconnected from core service.\n",
655 GNUNET_CONTAINER_DLL_remove (client_head,
658 if (NULL != c->requests)
660 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
661 &destroy_active_client_request,
663 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
665 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
666 c->connectmap = NULL;
667 if (NULL != c->types)
669 GSC_TYPEMAP_remove (c->types,
671 GNUNET_free (c->types);
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 * Notify a particular client about a change to existing connection to
684 * one of our neighbours (check if the client is interested). Called
685 * from #GSC_SESSIONS_notify_client_about_sessions().
687 * @param client client to notify
688 * @param neighbour identity of the neighbour that changed status
689 * @param tmap_old previous type map for the neighbour, NULL for connect
690 * @param tmap_new updated type map for the neighbour, NULL for disconnect
693 GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
694 const struct GNUNET_PeerIdentity *neighbour,
695 const struct GSC_TypeMap *tmap_old,
696 const struct GSC_TypeMap *tmap_new)
698 struct GNUNET_MQ_Envelope *env;
702 if (GNUNET_YES != client->got_init)
704 old_match = GSC_TYPEMAP_test_match (tmap_old,
707 new_match = GSC_TYPEMAP_test_match (tmap_new,
710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
711 "Notifying client about neighbour %s (%d/%d)\n",
712 GNUNET_i2s (neighbour),
715 if (old_match == new_match)
717 GNUNET_assert (old_match ==
718 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
720 return; /* no change */
722 if (GNUNET_NO == old_match)
724 struct ConnectNotifyMessage *cnm;
727 GNUNET_assert (GNUNET_NO ==
728 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
730 GNUNET_assert (GNUNET_YES ==
731 GNUNET_CONTAINER_multipeermap_put (client->connectmap,
734 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
735 env = GNUNET_MQ_msg (cnm,
736 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
737 cnm->reserved = htonl (0);
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
739 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
740 GNUNET_i2s (neighbour));
741 cnm->peer = *neighbour;
742 GNUNET_MQ_send (client->mq,
747 struct DisconnectNotifyMessage *dcm;
749 /* send disconnect */
750 GNUNET_assert (GNUNET_YES ==
751 GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
753 GNUNET_assert (GNUNET_YES ==
754 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
757 env = GNUNET_MQ_msg (dcm,
758 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
759 dcm->reserved = htonl (0);
760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
762 GNUNET_i2s (neighbour));
763 dcm->peer = *neighbour;
764 GNUNET_MQ_send (client->mq,
771 * Notify all clients about a change to existing session.
772 * Called from SESSIONS whenever there is a change in sessions
773 * or types processed by the respective peer.
775 * @param neighbour identity of the neighbour that changed status
776 * @param tmap_old previous type map for the neighbour, NULL for connect
777 * @param tmap_new updated type map for the neighbour, NULL for disconnect
780 GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
781 const struct GSC_TypeMap *tmap_old,
782 const struct GSC_TypeMap *tmap_new)
784 struct GSC_Client *c;
786 for (c = client_head; NULL != c; c = c->next)
787 GSC_CLIENTS_notify_client_about_neighbour (c,
795 * Deliver P2P message to interested clients. Caller must have checked
796 * that the sending peer actually lists the given message type as one
799 * @param sender peer who sent us the message
800 * @param msg the message
801 * @param msize number of bytes to transmit
802 * @param options options for checking which clients should
803 * receive the message
806 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
807 const struct GNUNET_MessageHeader *msg,
811 size_t size = msize + sizeof (struct NotifyTrafficMessage);
813 if (size >= GNUNET_MAX_MESSAGE_SIZE)
818 if (! ( (0 != (all_client_options & options)) ||
819 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
820 return; /* no client cares about this message notification */
821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
822 "Core service passes message from `%s' of type %u to client.\n",
824 (unsigned int) ntohs (msg->type));
825 GSC_SESSIONS_add_to_typemap (sender,
828 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
830 struct GNUNET_MQ_Envelope *env;
831 struct NotifyTrafficMessage *ntm;
836 tm = type_match (ntohs (msg->type),
838 if (! ( (0 != (c->options & options)) ||
839 ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
840 (GNUNET_YES == tm) ) ) )
841 continue; /* neither options nor type match permit the message */
842 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
843 ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
844 (GNUNET_YES == tm) ) )
846 if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
847 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
851 1) We are above the hard limit, or
852 2) We are above the soft limit, and a coin toss limited
853 to the message size (giving larger messages a
854 proportionally higher chance of being queued) falls
855 below the threshold. The threshold is based on where
856 we are between the soft and the hard limit, scaled
857 to match the range of message sizes we usually encounter
858 (i.e. up to 32k); so a 64k message has a 50% chance of
859 being kept if we are just barely below the hard max,
860 and a 99% chance of being kept if we are at the soft max.
861 The reason is to make it more likely to drop control traffic
862 (ACK, queries) which may be cummulative or highly redundant,
863 and cheap to drop than data traffic. */
864 qlen = GNUNET_MQ_get_length (c->mq);
865 if ( (qlen >= HARD_MAX_QUEUE) ||
866 ( (qlen > SOFT_MAX_QUEUE) &&
867 ( (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
868 ntohs (msg->size)) ) <
869 (qlen - SOFT_MAX_QUEUE) * 0x8000 /
870 (HARD_MAX_QUEUE - SOFT_MAX_QUEUE) ) ) )
874 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
875 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
876 (unsigned int) ntohs (msg->type));
877 GNUNET_snprintf (buf,
879 gettext_noop ("# messages of type %u discarded (client busy)"),
880 (unsigned int) ntohs (msg->type));
881 GNUNET_STATISTICS_update (GSC_stats,
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
889 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
892 (unsigned int) ntohs (msg->type));
894 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
895 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
897 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
898 env = GNUNET_MQ_msg_extra (ntm,
902 GNUNET_memcpy (&ntm[1],
906 GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
907 (GNUNET_YES != tm) ||
909 GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
911 GNUNET_MQ_send (c->mq,
918 * Last task run during shutdown. Disconnects us from
921 * @param cls NULL, unused
924 shutdown_task (void *cls)
926 struct GSC_Client *c;
928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929 "Core service shutting down.\n");
930 while (NULL != (c = client_head))
931 GNUNET_SERVICE_client_drop (c->client);
932 GSC_SESSIONS_done ();
935 if (NULL != GSC_stats)
937 GNUNET_STATISTICS_destroy (GSC_stats,
946 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
947 * request type, the client does not have to have transmitted an INIT
948 * request. All current peers are returned, regardless of which
949 * message types they accept.
951 * @param cls client sending the iteration request
952 * @param message iteration request message
955 handle_client_monitor_peers (void *cls,
956 const struct GNUNET_MessageHeader *message)
958 struct GSC_Client *c = cls;
960 GNUNET_SERVICE_client_continue (c->client);
961 GSC_KX_handle_client_monitor_peers (c->mq);
966 * Initiate core service.
969 * @param c configuration to use
970 * @param service the initialized service
974 const struct GNUNET_CONFIGURATION_Handle *c,
975 struct GNUNET_SERVICE_Handle *service)
977 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
982 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
987 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
988 _("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
989 GNUNET_SCHEDULER_shutdown ();
992 GSC_stats = GNUNET_STATISTICS_create ("core",
994 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
996 GNUNET_SERVICE_suspend (service);
998 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
999 GNUNET_free (keyfile);
1000 GNUNET_assert (NULL != pk);
1001 if (GNUNET_OK != GSC_KX_init (pk))
1003 GNUNET_SCHEDULER_shutdown ();
1006 GSC_SESSIONS_init ();
1007 GNUNET_SERVICE_resume (service);
1008 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1009 _("Core service of `%s' ready.\n"),
1010 GNUNET_i2s (&GSC_my_identity));
1015 * Define "main" method using service macro.
1019 GNUNET_SERVICE_OPTION_NONE,
1022 &client_disconnect_cb,
1024 GNUNET_MQ_hd_var_size (client_init,
1025 GNUNET_MESSAGE_TYPE_CORE_INIT,
1028 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
1029 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
1030 struct GNUNET_MessageHeader,
1032 GNUNET_MQ_hd_fixed_size (client_send_request,
1033 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
1034 struct SendMessageRequest,
1036 GNUNET_MQ_hd_var_size (client_send,
1037 GNUNET_MESSAGE_TYPE_CORE_SEND,
1040 GNUNET_MQ_handler_end ());
1043 /* end of gnunet-service-core.c */