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.
116 struct GNUNET_PeerIdentity GSC_my_identity;
121 const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
124 * For creating statistics.
126 struct GNUNET_STATISTICS_Handle *GSC_stats;
129 * Big "or" of all client options.
131 static uint32_t all_client_options;
134 * Head of linked list of our clients.
136 static struct GSC_Client *client_head;
139 * Tail of linked list of our clients.
141 static struct GSC_Client *client_tail;
145 * Test if the client is interested in messages of the given type.
147 * @param type message type
148 * @param c client to test
149 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
152 type_match (uint16_t type, struct GSC_Client *c)
154 if ((0 == c->tcnt) && (0 != c->options))
155 return GNUNET_YES; /* peer without handlers and inbound/outbond
156 callbacks matches ALL */
157 if (NULL == c->types)
159 for (unsigned int i = 0; i < c->tcnt; i++)
160 if (type == c->types[i])
167 * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
169 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
170 * @param im the `struct InitMessage`
171 * @return #GNUNET_OK if @a im is well-formed
174 check_client_init (void *cls, const struct InitMessage *im)
181 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
183 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
184 * @param im the `struct InitMessage`
187 handle_client_init (void *cls, 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 (
208 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
209 for (unsigned int i = 0; i < c->tcnt; i++)
210 c->types[i] = ntohs (types[i]);
211 GSC_TYPEMAP_add (c->types, c->tcnt);
213 GNUNET_ERROR_TYPE_DEBUG,
214 "Client connecting to core service is interested in %u message types\n",
215 (unsigned int) c->tcnt);
216 /* send init reply message */
217 env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
218 irm->reserved = htonl (0);
219 irm->my_identity = GSC_my_identity;
220 GNUNET_MQ_send (c->mq, env);
221 GSC_SESSIONS_notify_client_about_sessions (c);
222 GNUNET_SERVICE_client_continue (c->client);
227 * We will never be ready to transmit the given message in (disconnect
228 * or invalid request). Frees resources associated with @a car. We
229 * don't explicitly tell the client, it'll learn with the disconnect
230 * (or violated the protocol).
232 * @param car request that now permanently failed; the
233 * responsibility for the handle is now returned
234 * to CLIENTS (SESSIONS is done with it).
235 * @param drop_client #GNUNET_YES if the client violated the protocol
236 * and we should thus drop the connection
239 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
244 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
247 if (GNUNET_YES == drop_client)
248 GNUNET_SERVICE_client_drop (car->client_handle->client);
254 * Tell a client that we are ready to receive the message.
256 * @param car request that is now ready; the responsibility
257 * for the handle remains shared between CLIENTS
258 * and SESSIONS after this call.
261 GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
263 struct GSC_Client *c;
264 struct GNUNET_MQ_Envelope *env;
265 struct SendMessageReady *smr;
266 struct GNUNET_TIME_Relative delay;
267 struct GNUNET_TIME_Relative left;
269 c = car->client_handle;
271 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &car->target))
273 /* connection has gone down since, drop request */
274 GNUNET_assert (0 != memcmp (&car->target,
276 sizeof(struct GNUNET_PeerIdentity)));
277 GSC_SESSIONS_dequeue_request (car);
278 GSC_CLIENTS_reject_request (car, GNUNET_NO);
281 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
282 left = GNUNET_TIME_absolute_get_duration (car->deadline);
283 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
285 GNUNET_ERROR_TYPE_WARNING,
286 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
287 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
288 GNUNET_i2s (&car->target),
289 (0 == left.rel_value_us) ? " (past deadline)" : "",
291 env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
292 smr->size = htons (car->msize);
293 smr->smr_id = car->smr_id;
294 smr->peer = car->target;
295 GNUNET_MQ_send (c->mq, env);
300 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
302 * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
303 * @param req the `struct SendMessageRequest`
306 handle_client_send_request (void *cls, const struct SendMessageRequest *req)
308 struct GSC_Client *c = cls;
309 struct GSC_ClientActiveRequest *car;
312 if (NULL == c->requests)
313 c->requests = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Client asked for transmission to `%s'\n",
316 GNUNET_i2s (&req->peer));
317 is_loopback = (0 == memcmp (&req->peer,
319 sizeof(struct GNUNET_PeerIdentity)));
320 if ((! is_loopback) &&
322 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &req->peer)))
324 /* neighbour must have disconnected since request was issued,
325 * ignore (client will realize it once it processes the
326 * disconnect notification) */
327 GNUNET_STATISTICS_update (GSC_stats,
329 "# send requests dropped (disconnected)"),
332 GNUNET_SERVICE_client_continue (c->client);
336 car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer);
339 /* create new entry */
340 car = GNUNET_new (struct GSC_ClientActiveRequest);
341 GNUNET_assert (GNUNET_OK ==
342 GNUNET_CONTAINER_multipeermap_put (
346 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
347 car->client_handle = c;
351 /* dequeue and recycle memory from pending request, there can only
352 be at most one per client and peer */
353 GNUNET_STATISTICS_update (GSC_stats,
355 "# dequeuing CAR (duplicate request)"),
358 GSC_SESSIONS_dequeue_request (car);
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "Transmission request to `%s' was a duplicate!\n",
361 GNUNET_i2s (&req->peer));
363 car->target = req->peer;
364 car->received_time = GNUNET_TIME_absolute_get ();
365 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
366 car->priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (req->priority);
367 car->msize = ntohs (req->size);
368 car->smr_id = req->smr_id;
369 car->was_solicited = GNUNET_NO;
370 GNUNET_SERVICE_client_continue (c->client);
373 /* loopback, satisfy immediately */
374 GSC_CLIENTS_solicit_request (car);
377 GSC_SESSIONS_queue_request (car);
382 * Closure for the #client_tokenizer_callback().
384 struct TokenizerContext
387 * Active request handle for the message.
389 struct GSC_ClientActiveRequest *car;
392 * How important is this message.
394 enum GNUNET_MQ_PriorityPreferences priority;
399 * Functions with this signature are called whenever a complete
400 * message is received by the tokenizer. Used by
401 * #handle_client_send() for dispatching messages from clients to
402 * either the SESSION subsystem or other CLIENT (for loopback).
404 * @param cls reservation request (`struct TokenizerContext`)
405 * @param message the actual message
406 * @return #GNUNET_OK on success,
407 * #GNUNET_NO to stop further processing (no error)
408 * #GNUNET_SYSERR to stop further processing with error
411 tokenized_cb (void *cls, const struct GNUNET_MessageHeader *message)
413 struct TokenizerContext *tc = cls;
414 struct GSC_ClientActiveRequest *car = tc->car;
417 GNUNET_snprintf (buf,
419 gettext_noop ("# bytes of messages of type %u received"),
420 (unsigned int) ntohs (message->type));
421 GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO);
422 if (0 == memcmp (&car->target,
424 sizeof(struct GNUNET_PeerIdentity)))
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Delivering message of type %u to myself\n",
428 ntohs (message->type));
429 GSC_CLIENTS_deliver_message (&GSC_my_identity,
431 ntohs (message->size),
432 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
433 GSC_CLIENTS_deliver_message (&GSC_my_identity,
435 sizeof(struct GNUNET_MessageHeader),
436 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
437 GSC_CLIENTS_deliver_message (&GSC_my_identity,
439 ntohs (message->size),
440 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
441 GSC_CLIENTS_deliver_message (&GSC_my_identity,
443 sizeof(struct GNUNET_MessageHeader),
444 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "Delivering message of type %u and size %u to %s\n",
450 ntohs (message->type),
451 ntohs (message->size),
452 GNUNET_i2s (&car->target));
453 GSC_CLIENTS_deliver_message (&car->target,
455 ntohs (message->size),
456 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
457 GSC_CLIENTS_deliver_message (&car->target,
459 sizeof(struct GNUNET_MessageHeader),
460 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
461 GSC_SESSIONS_transmit (car, message, tc->priority);
468 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
470 * @param cls the `struct GSC_Client`
471 * @param sm the `struct SendMessage`
472 * @return #GNUNET_OK if @a sm is well-formed
475 check_client_send (void *cls, const struct SendMessage *sm)
482 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
484 * @param cls the `struct GSC_Client`
485 * @param sm the `struct SendMessage`
488 handle_client_send (void *cls, const struct SendMessage *sm)
490 struct GSC_Client *c = cls;
491 struct TokenizerContext tc;
493 struct GNUNET_TIME_Relative delay;
494 struct GNUNET_MessageStreamTokenizer *mst;
496 msize = ntohs (sm->header.size) - sizeof(struct SendMessage);
497 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
500 /* Must have been that we first approved the request, then got disconnected
501 * (which triggered removal of the 'car') and now the client gives us a message
502 * just *before* the client learns about the disconnect. Theoretically, we
503 * might also now be *again* connected. So this can happen (but should be
504 * rare). If it does happen, the message is discarded. */GNUNET_STATISTICS_update (GSC_stats,
506 "# messages discarded (session disconnected)"),
509 GNUNET_SERVICE_client_continue (c->client);
512 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
513 tc.priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (sm->priority);
514 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
515 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
516 "Client waited %s for transmission of %u bytes to `%s'\n",
517 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
519 GNUNET_i2s (&sm->peer));
521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522 "Client waited %s for transmission of %u bytes to `%s'\n",
523 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
525 GNUNET_i2s (&sm->peer));
529 GNUNET_CONTAINER_multipeermap_remove (c->requests, &sm->peer, tc.car));
530 mst = GNUNET_MST_create (&tokenized_cb, &tc);
531 GNUNET_MST_from_buffer (mst,
532 (const char *) &sm[1],
536 GNUNET_MST_destroy (mst);
537 GSC_SESSIONS_dequeue_request (tc.car);
538 GNUNET_free (tc.car);
539 GNUNET_SERVICE_client_continue (c->client);
544 * Free client request records.
547 * @param key identity of peer for which this is an active request
548 * @param value the `struct GSC_ClientActiveRequest` to free
549 * @return #GNUNET_YES (continue iteration)
552 destroy_active_client_request (void *cls,
553 const struct GNUNET_PeerIdentity *key,
556 struct GSC_ClientActiveRequest *car = value;
560 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
563 GSC_SESSIONS_dequeue_request (car);
570 * A client connected, set up.
573 * @param client identification of the client
574 * @param mq message queue to talk to @a client
575 * @return our client handle
578 client_connect_cb (void *cls,
579 struct GNUNET_SERVICE_Client *client,
580 struct GNUNET_MQ_Handle *mq)
582 struct GSC_Client *c;
584 c = GNUNET_new (struct GSC_Client);
587 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
588 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
594 * A client disconnected, clean up.
597 * @param client identification of the client
598 * @param app_ctx our `struct GST_Client` for @a client
601 client_disconnect_cb (void *cls,
602 struct GNUNET_SERVICE_Client *client,
605 struct GSC_Client *c = app_ctx;
607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608 "Client %p has disconnected from core service.\n",
610 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
611 if (NULL != c->requests)
613 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
614 &destroy_active_client_request,
616 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
618 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
619 c->connectmap = NULL;
620 if (NULL != c->types)
622 GSC_TYPEMAP_remove (c->types, c->tcnt);
623 GNUNET_free (c->types);
627 /* recalculate 'all_client_options' */
628 all_client_options = 0;
629 for (c = client_head; NULL != c; c = c->next)
630 all_client_options |= c->options;
635 * Notify a particular client about a change to existing connection to
636 * one of our neighbours (check if the client is interested). Called
637 * from #GSC_SESSIONS_notify_client_about_sessions().
639 * @param client client to notify
640 * @param neighbour identity of the neighbour that changed status
641 * @param tmap_old previous type map for the neighbour, NULL for connect
642 * @param tmap_new updated type map for the neighbour, NULL for disconnect
645 GSC_CLIENTS_notify_client_about_neighbour (
646 struct GSC_Client *client,
647 const struct GNUNET_PeerIdentity *neighbour,
648 const struct GSC_TypeMap *tmap_old,
649 const struct GSC_TypeMap *tmap_new)
651 struct GNUNET_MQ_Envelope *env;
655 if (GNUNET_YES != client->got_init)
657 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
658 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "Notifying client about neighbour %s (%d/%d)\n",
661 GNUNET_i2s (neighbour),
664 if (old_match == new_match)
668 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
669 return; /* no change */
671 if (GNUNET_NO == old_match)
673 struct ConnectNotifyMessage *cnm;
678 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
679 GNUNET_assert (GNUNET_YES ==
680 GNUNET_CONTAINER_multipeermap_put (
684 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
685 env = GNUNET_MQ_msg (cnm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
686 cnm->reserved = htonl (0);
687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
688 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
689 GNUNET_i2s (neighbour));
690 cnm->peer = *neighbour;
691 GNUNET_MQ_send (client->mq, env);
695 struct DisconnectNotifyMessage *dcm;
697 /* send disconnect */
700 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
701 GNUNET_assert (GNUNET_YES ==
702 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
705 env = GNUNET_MQ_msg (dcm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
706 dcm->reserved = htonl (0);
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
709 GNUNET_i2s (neighbour));
710 dcm->peer = *neighbour;
711 GNUNET_MQ_send (client->mq, env);
717 * Notify all clients about a change to existing session.
718 * Called from SESSIONS whenever there is a change in sessions
719 * or types processed by the respective peer.
721 * @param neighbour identity of the neighbour that changed status
722 * @param tmap_old previous type map for the neighbour, NULL for connect
723 * @param tmap_new updated type map for the neighbour, NULL for disconnect
726 GSC_CLIENTS_notify_clients_about_neighbour (
727 const struct GNUNET_PeerIdentity *neighbour,
728 const struct GSC_TypeMap *tmap_old,
729 const struct GSC_TypeMap *tmap_new)
731 struct GSC_Client *c;
733 for (c = client_head; NULL != c; c = c->next)
734 GSC_CLIENTS_notify_client_about_neighbour (c,
742 * Deliver P2P message to interested clients. Caller must have checked
743 * that the sending peer actually lists the given message type as one
746 * @param sender peer who sent us the message
747 * @param msg the message
748 * @param msize number of bytes to transmit
749 * @param options options for checking which clients should
750 * receive the message
753 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
754 const struct GNUNET_MessageHeader *msg,
758 size_t size = msize + sizeof(struct NotifyTrafficMessage);
760 if (size >= GNUNET_MAX_MESSAGE_SIZE)
765 if (! ((0 != (all_client_options & options)) ||
766 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))))
767 return; /* no client cares about this message notification */
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769 "Core service passes message from `%s' of type %u to client.\n",
771 (unsigned int) ntohs (msg->type));
772 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
774 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
776 struct GNUNET_MQ_Envelope *env;
777 struct NotifyTrafficMessage *ntm;
782 tm = type_match (ntohs (msg->type), c);
783 if (! ((0 != (c->options & options)) ||
784 ((0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
785 (GNUNET_YES == tm))))
786 continue; /* neither options nor type match permit the message */
787 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
788 ((0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
791 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
792 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)))
796 1) We are above the hard limit, or
797 2) We are above the soft limit, and a coin toss limited
798 to the message size (giving larger messages a
799 proportionally higher chance of being queued) falls
800 below the threshold. The threshold is based on where
801 we are between the soft and the hard limit, scaled
802 to match the range of message sizes we usually encounter
803 (i.e. up to 32k); so a 64k message has a 50% chance of
804 being kept if we are just barely below the hard max,
805 and a 99% chance of being kept if we are at the soft max.
806 The reason is to make it more likely to drop control traffic
807 (ACK, queries) which may be cummulative or highly redundant,
808 and cheap to drop than data traffic. */qlen = GNUNET_MQ_get_length (c->mq);
809 if ((qlen >= HARD_MAX_QUEUE) ||
810 ((qlen > SOFT_MAX_QUEUE) &&
811 ((GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
812 ntohs (msg->size))) <
813 (qlen - SOFT_MAX_QUEUE) * 0x8000
814 / (HARD_MAX_QUEUE - SOFT_MAX_QUEUE))))
819 GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
820 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
821 (unsigned int) ntohs (msg->type));
822 GNUNET_snprintf (buf,
825 "# messages of type %u discarded (client busy)"),
826 (unsigned int) ntohs (msg->type));
827 GNUNET_STATISTICS_update (GSC_stats, buf, 1, GNUNET_NO);
832 GNUNET_ERROR_TYPE_DEBUG,
833 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
836 (unsigned int) ntohs (msg->type));
838 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND
839 | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
840 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
842 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
843 env = GNUNET_MQ_msg_extra (ntm, msize, mtype);
845 GNUNET_memcpy (&ntm[1], msg, msize);
848 (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
849 (GNUNET_YES != tm) ||
851 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, sender)));
852 GNUNET_MQ_send (c->mq, env);
858 * Last task run during shutdown. Disconnects us from
861 * @param cls NULL, unused
864 shutdown_task (void *cls)
866 struct GSC_Client *c;
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n");
869 while (NULL != (c = client_head))
870 GNUNET_SERVICE_client_drop (c->client);
871 GSC_SESSIONS_done ();
874 if (NULL != GSC_stats)
876 GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO);
884 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
885 * request type, the client does not have to have transmitted an INIT
886 * request. All current peers are returned, regardless of which
887 * message types they accept.
889 * @param cls client sending the iteration request
890 * @param message iteration request message
893 handle_client_monitor_peers (void *cls,
894 const struct GNUNET_MessageHeader *message)
896 struct GSC_Client *c = cls;
898 GNUNET_SERVICE_client_continue (c->client);
899 GSC_KX_handle_client_monitor_peers (c->mq);
904 * Initiate core service.
907 * @param c configuration to use
908 * @param service the initialized service
912 const struct GNUNET_CONFIGURATION_Handle *c,
913 struct GNUNET_SERVICE_Handle *service)
915 struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
919 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
925 GNUNET_ERROR_TYPE_ERROR,
926 _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
927 GNUNET_SCHEDULER_shutdown ();
930 GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg);
931 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
932 GNUNET_SERVICE_suspend (service);
934 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
935 GNUNET_free (keyfile);
936 GNUNET_assert (NULL != pk);
937 if (GNUNET_OK != GSC_KX_init (pk))
939 GNUNET_SCHEDULER_shutdown ();
942 GSC_SESSIONS_init ();
943 GNUNET_SERVICE_resume (service);
944 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
945 _ ("Core service of `%s' ready.\n"),
946 GNUNET_i2s (&GSC_my_identity));
951 * Define "main" method using service macro.
953 GNUNET_SERVICE_MAIN (
955 GNUNET_SERVICE_OPTION_NONE,
958 &client_disconnect_cb,
960 GNUNET_MQ_hd_var_size (client_init,
961 GNUNET_MESSAGE_TYPE_CORE_INIT,
964 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
965 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
966 struct GNUNET_MessageHeader,
968 GNUNET_MQ_hd_fixed_size (client_send_request,
969 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
970 struct SendMessageRequest,
972 GNUNET_MQ_hd_var_size (client_send,
973 GNUNET_MESSAGE_TYPE_CORE_SEND,
976 GNUNET_MQ_handler_end ());
979 /* end of gnunet-service-core.c */