aboutsummaryrefslogtreecommitdiff
path: root/src/core/gnunet-service-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/gnunet-service-core.c')
-rw-r--r--src/core/gnunet-service-core.c987
1 files changed, 0 insertions, 987 deletions
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c
deleted file mode 100644
index c9c3e3ff5..000000000
--- a/src/core/gnunet-service-core.c
+++ /dev/null
@@ -1,987 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file core/gnunet-service-core.c
23 * @brief high-level P2P messaging
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include <gcrypt.h>
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"
33
34/**
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.
39 */
40#define SOFT_MAX_QUEUE 128
41
42/**
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.
46 */
47#define HARD_MAX_QUEUE 256
48
49
50/**
51 * Data structure for each client connected to the CORE service.
52 */
53struct GSC_Client
54{
55 /**
56 * Clients are kept in a linked list.
57 */
58 struct GSC_Client *next;
59
60 /**
61 * Clients are kept in a linked list.
62 */
63 struct GSC_Client *prev;
64
65 /**
66 * Handle for the client with the server API.
67 */
68 struct GNUNET_SERVICE_Client *client;
69
70 /**
71 * Message queue to talk to @e client.
72 */
73 struct GNUNET_MQ_Handle *mq;
74
75 /**
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!
79 */
80 uint16_t *types;
81
82 /**
83 * Map of peer identities to active transmission requests of this
84 * client to the peer (of type `struct GSC_ClientActiveRequest`).
85 */
86 struct GNUNET_CONTAINER_MultiPeerMap *requests;
87
88 /**
89 * Map containing all peers that this client knows we're connected to.
90 */
91 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
92
93 /**
94 * Options for messages this client cares about,
95 * see GNUNET_CORE_OPTION_ values.
96 */
97 uint32_t options;
98
99 /**
100 * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message
101 * from this client already?
102 */
103 int got_init;
104
105 /**
106 * Number of types of incoming messages this client
107 * specifically cares about. Size of the @e types array.
108 */
109 unsigned int tcnt;
110};
111
112
113/**
114 * Our identity.
115 */
116struct GNUNET_PeerIdentity GSC_my_identity;
117
118/**
119 * Our configuration.
120 */
121const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
122
123/**
124 * For creating statistics.
125 */
126struct GNUNET_STATISTICS_Handle *GSC_stats;
127
128/**
129 * Big "or" of all client options.
130 */
131static uint32_t all_client_options;
132
133/**
134 * Head of linked list of our clients.
135 */
136static struct GSC_Client *client_head;
137
138/**
139 * Tail of linked list of our clients.
140 */
141static struct GSC_Client *client_tail;
142
143
144/**
145 * Test if the client is interested in messages of the given type.
146 *
147 * @param type message type
148 * @param c client to test
149 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
150 */
151static int
152type_match (uint16_t type, struct GSC_Client *c)
153{
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)
158 return GNUNET_NO;
159 for (unsigned int i = 0; i < c->tcnt; i++)
160 if (type == c->types[i])
161 return GNUNET_YES;
162 return GNUNET_NO;
163}
164
165
166/**
167 * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
168 *
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
172 */
173static int
174check_client_init (void *cls, const struct InitMessage *im)
175{
176 return GNUNET_OK;
177}
178
179
180/**
181 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
182 *
183 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
184 * @param im the `struct InitMessage`
185 */
186static void
187handle_client_init (void *cls, const struct InitMessage *im)
188{
189 struct GSC_Client *c = cls;
190 struct GNUNET_MQ_Envelope *env;
191 struct InitReplyMessage *irm;
192 uint16_t msize;
193 const uint16_t *types;
194
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 (
205 c->connectmap,
206 &GSC_my_identity,
207 NULL,
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);
212 GNUNET_log (
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);
223}
224
225
226/**
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).
231 *
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
237 */
238void
239GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
240 int drop_client)
241{
242 GNUNET_assert (
243 GNUNET_YES ==
244 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
245 &car->target,
246 car));
247 if (GNUNET_YES == drop_client)
248 GNUNET_SERVICE_client_drop (car->client_handle->client);
249 GNUNET_free (car);
250}
251
252
253/**
254 * Tell a client that we are ready to receive the message.
255 *
256 * @param car request that is now ready; the responsibility
257 * for the handle remains shared between CLIENTS
258 * and SESSIONS after this call.
259 */
260void
261GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
262{
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;
268
269 c = car->client_handle;
270 if (GNUNET_YES !=
271 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &car->target))
272 {
273 /* connection has gone down since, drop request */
274 GNUNET_assert (0 !=
275 GNUNET_memcmp (&car->target,
276 &GSC_my_identity));
277 GSC_SESSIONS_dequeue_request (car);
278 GSC_CLIENTS_reject_request (car, GNUNET_NO);
279 return;
280 }
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)
284 GNUNET_log (
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)" : "",
290 car->priority);
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);
296}
297
298
299/**
300 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
301 *
302 * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
303 * @param req the `struct SendMessageRequest`
304 */
305static void
306handle_client_send_request (void *cls, const struct SendMessageRequest *req)
307{
308 struct GSC_Client *c = cls;
309 struct GSC_ClientActiveRequest *car;
310 int is_loopback;
311
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 == GNUNET_memcmp (&req->peer,
318 &GSC_my_identity));
319 if ((! is_loopback) &&
320 (GNUNET_YES !=
321 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &req->peer)))
322 {
323 /* neighbour must have disconnected since request was issued,
324 * ignore (client will realize it once it processes the
325 * disconnect notification) */
326 GNUNET_STATISTICS_update (GSC_stats,
327 gettext_noop (
328 "# send requests dropped (disconnected)"),
329 1,
330 GNUNET_NO);
331 GNUNET_SERVICE_client_continue (c->client);
332 return;
333 }
334
335 car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer);
336 if (NULL == car)
337 {
338 /* create new entry */
339 car = GNUNET_new (struct GSC_ClientActiveRequest);
340 GNUNET_assert (GNUNET_OK ==
341 GNUNET_CONTAINER_multipeermap_put (
342 c->requests,
343 &req->peer,
344 car,
345 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
346 car->client_handle = c;
347 }
348 else
349 {
350 /* dequeue and recycle memory from pending request, there can only
351 be at most one per client and peer */
352 GNUNET_STATISTICS_update (GSC_stats,
353 gettext_noop (
354 "# dequeuing CAR (duplicate request)"),
355 1,
356 GNUNET_NO);
357 GSC_SESSIONS_dequeue_request (car);
358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359 "Transmission request to `%s' was a duplicate!\n",
360 GNUNET_i2s (&req->peer));
361 }
362 car->target = req->peer;
363 car->received_time = GNUNET_TIME_absolute_get ();
364 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
365 car->priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (req->priority);
366 car->msize = ntohs (req->size);
367 car->smr_id = req->smr_id;
368 car->was_solicited = GNUNET_NO;
369 GNUNET_SERVICE_client_continue (c->client);
370 if (is_loopback)
371 {
372 /* loopback, satisfy immediately */
373 GSC_CLIENTS_solicit_request (car);
374 return;
375 }
376 GSC_SESSIONS_queue_request (car);
377}
378
379
380/**
381 * Closure for the #client_tokenizer_callback().
382 */
383struct TokenizerContext
384{
385 /**
386 * Active request handle for the message.
387 */
388 struct GSC_ClientActiveRequest *car;
389
390 /**
391 * How important is this message.
392 */
393 enum GNUNET_MQ_PriorityPreferences priority;
394};
395
396
397/**
398 * Functions with this signature are called whenever a complete
399 * message is received by the tokenizer. Used by
400 * #handle_client_send() for dispatching messages from clients to
401 * either the SESSION subsystem or other CLIENT (for loopback).
402 *
403 * @param cls reservation request (`struct TokenizerContext`)
404 * @param message the actual message
405 * @return #GNUNET_OK on success,
406 * #GNUNET_NO to stop further processing (no error)
407 * #GNUNET_SYSERR to stop further processing with error
408 */
409static int
410tokenized_cb (void *cls, const struct GNUNET_MessageHeader *message)
411{
412 struct TokenizerContext *tc = cls;
413 struct GSC_ClientActiveRequest *car = tc->car;
414 char buf[92];
415
416 GNUNET_snprintf (buf,
417 sizeof(buf),
418 gettext_noop ("# bytes of messages of type %u received"),
419 (unsigned int) ntohs (message->type));
420 GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO);
421 if (0 == GNUNET_memcmp (&car->target,
422 &GSC_my_identity))
423 {
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425 "Delivering message of type %u to myself\n",
426 ntohs (message->type));
427 GSC_CLIENTS_deliver_message (&GSC_my_identity,
428 message,
429 ntohs (message->size),
430 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
431 GSC_CLIENTS_deliver_message (&GSC_my_identity,
432 message,
433 sizeof(struct GNUNET_MessageHeader),
434 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
435 GSC_CLIENTS_deliver_message (&GSC_my_identity,
436 message,
437 ntohs (message->size),
438 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
439 GSC_CLIENTS_deliver_message (&GSC_my_identity,
440 message,
441 sizeof(struct GNUNET_MessageHeader),
442 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
443 }
444 else
445 {
446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447 "Delivering message of type %u and size %u to %s\n",
448 ntohs (message->type),
449 ntohs (message->size),
450 GNUNET_i2s (&car->target));
451 GSC_CLIENTS_deliver_message (&car->target,
452 message,
453 ntohs (message->size),
454 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
455 GSC_CLIENTS_deliver_message (&car->target,
456 message,
457 sizeof(struct GNUNET_MessageHeader),
458 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
459 GSC_SESSIONS_transmit (car, message, tc->priority);
460 }
461 return GNUNET_OK;
462}
463
464
465/**
466 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
467 *
468 * @param cls the `struct GSC_Client`
469 * @param sm the `struct SendMessage`
470 * @return #GNUNET_OK if @a sm is well-formed
471 */
472static int
473check_client_send (void *cls, const struct SendMessage *sm)
474{
475 return GNUNET_OK;
476}
477
478
479/**
480 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
481 *
482 * @param cls the `struct GSC_Client`
483 * @param sm the `struct SendMessage`
484 */
485static void
486handle_client_send (void *cls, const struct SendMessage *sm)
487{
488 struct GSC_Client *c = cls;
489 struct TokenizerContext tc;
490 uint16_t msize;
491 struct GNUNET_TIME_Relative delay;
492 struct GNUNET_MessageStreamTokenizer *mst;
493
494 msize = ntohs (sm->header.size) - sizeof(struct SendMessage);
495 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
496 if (NULL == tc.car)
497 {
498 /* Must have been that we first approved the request, then got disconnected
499 * (which triggered removal of the 'car') and now the client gives us a message
500 * just *before* the client learns about the disconnect. Theoretically, we
501 * might also now be *again* connected. So this can happen (but should be
502 * rare). If it does happen, the message is discarded. */GNUNET_STATISTICS_update (GSC_stats,
503 gettext_noop (
504 "# messages discarded (session disconnected)"),
505 1,
506 GNUNET_NO);
507 GNUNET_SERVICE_client_continue (c->client);
508 return;
509 }
510 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
511 tc.priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (sm->priority);
512 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
513 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
514 "Client waited %s for transmission of %u bytes to `%s'\n",
515 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
516 msize,
517 GNUNET_i2s (&sm->peer));
518 else
519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
520 "Client waited %s for transmission of %u bytes to `%s'\n",
521 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
522 msize,
523 GNUNET_i2s (&sm->peer));
524
525 GNUNET_assert (
526 GNUNET_YES ==
527 GNUNET_CONTAINER_multipeermap_remove (c->requests, &sm->peer, tc.car));
528 mst = GNUNET_MST_create (&tokenized_cb, &tc);
529 GNUNET_MST_from_buffer (mst,
530 (const char *) &sm[1],
531 msize,
532 GNUNET_YES,
533 GNUNET_NO);
534 GNUNET_MST_destroy (mst);
535 GSC_SESSIONS_dequeue_request (tc.car);
536 GNUNET_free (tc.car);
537 GNUNET_SERVICE_client_continue (c->client);
538}
539
540
541/**
542 * Free client request records.
543 *
544 * @param cls NULL
545 * @param key identity of peer for which this is an active request
546 * @param value the `struct GSC_ClientActiveRequest` to free
547 * @return #GNUNET_YES (continue iteration)
548 */
549static int
550destroy_active_client_request (void *cls,
551 const struct GNUNET_PeerIdentity *key,
552 void *value)
553{
554 struct GSC_ClientActiveRequest *car = value;
555
556 GNUNET_assert (
557 GNUNET_YES ==
558 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
559 &car->target,
560 car));
561 GSC_SESSIONS_dequeue_request (car);
562 GNUNET_free (car);
563 return GNUNET_YES;
564}
565
566
567/**
568 * A client connected, set up.
569 *
570 * @param cls closure
571 * @param client identification of the client
572 * @param mq message queue to talk to @a client
573 * @return our client handle
574 */
575static void *
576client_connect_cb (void *cls,
577 struct GNUNET_SERVICE_Client *client,
578 struct GNUNET_MQ_Handle *mq)
579{
580 struct GSC_Client *c;
581
582 c = GNUNET_new (struct GSC_Client);
583 c->client = client;
584 c->mq = mq;
585 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
586 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
587 return c;
588}
589
590
591/**
592 * A client disconnected, clean up.
593 *
594 * @param cls closure
595 * @param client identification of the client
596 * @param app_ctx our `struct GST_Client` for @a client
597 */
598static void
599client_disconnect_cb (void *cls,
600 struct GNUNET_SERVICE_Client *client,
601 void *app_ctx)
602{
603 struct GSC_Client *c = app_ctx;
604
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Client %p has disconnected from core service.\n",
607 client);
608 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
609 if (NULL != c->requests)
610 {
611 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
612 &destroy_active_client_request,
613 NULL);
614 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
615 }
616 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
617 c->connectmap = NULL;
618 if (NULL != c->types)
619 {
620 GSC_TYPEMAP_remove (c->types, c->tcnt);
621 GNUNET_free (c->types);
622 }
623 GNUNET_free (c);
624
625 /* recalculate 'all_client_options' */
626 all_client_options = 0;
627 for (c = client_head; NULL != c; c = c->next)
628 all_client_options |= c->options;
629}
630
631
632/**
633 * Notify a particular client about a change to existing connection to
634 * one of our neighbours (check if the client is interested). Called
635 * from #GSC_SESSIONS_notify_client_about_sessions().
636 *
637 * @param client client to notify
638 * @param neighbour identity of the neighbour that changed status
639 * @param tmap_old previous type map for the neighbour, NULL for connect
640 * @param tmap_new updated type map for the neighbour, NULL for disconnect
641 */
642void
643GSC_CLIENTS_notify_client_about_neighbour (
644 struct GSC_Client *client,
645 const struct GNUNET_PeerIdentity *neighbour,
646 const struct GSC_TypeMap *tmap_old,
647 const struct GSC_TypeMap *tmap_new)
648{
649 struct GNUNET_MQ_Envelope *env;
650 int old_match;
651 int new_match;
652
653 if (GNUNET_YES != client->got_init)
654 return;
655 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
656 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Notifying client about neighbour %s (%d/%d)\n",
659 GNUNET_i2s (neighbour),
660 old_match,
661 new_match);
662 if (old_match == new_match)
663 {
664 GNUNET_assert (
665 old_match ==
666 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
667 return; /* no change */
668 }
669 if (GNUNET_NO == old_match)
670 {
671 struct ConnectNotifyMessage *cnm;
672
673 /* send connect */
674 GNUNET_assert (
675 GNUNET_NO ==
676 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
677 GNUNET_assert (GNUNET_YES ==
678 GNUNET_CONTAINER_multipeermap_put (
679 client->connectmap,
680 neighbour,
681 NULL,
682 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
683 env = GNUNET_MQ_msg (cnm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
684 cnm->reserved = htonl (0);
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
687 GNUNET_i2s (neighbour));
688 cnm->peer = *neighbour;
689 GNUNET_MQ_send (client->mq, env);
690 }
691 else
692 {
693 struct DisconnectNotifyMessage *dcm;
694
695 /* send disconnect */
696 GNUNET_assert (
697 GNUNET_YES ==
698 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
699 GNUNET_assert (GNUNET_YES ==
700 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
701 neighbour,
702 NULL));
703 env = GNUNET_MQ_msg (dcm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
704 dcm->reserved = htonl (0);
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
707 GNUNET_i2s (neighbour));
708 dcm->peer = *neighbour;
709 GNUNET_MQ_send (client->mq, env);
710 }
711}
712
713
714/**
715 * Notify all clients about a change to existing session.
716 * Called from SESSIONS whenever there is a change in sessions
717 * or types processed by the respective peer.
718 *
719 * @param neighbour identity of the neighbour that changed status
720 * @param tmap_old previous type map for the neighbour, NULL for connect
721 * @param tmap_new updated type map for the neighbour, NULL for disconnect
722 */
723void
724GSC_CLIENTS_notify_clients_about_neighbour (
725 const struct GNUNET_PeerIdentity *neighbour,
726 const struct GSC_TypeMap *tmap_old,
727 const struct GSC_TypeMap *tmap_new)
728{
729 struct GSC_Client *c;
730
731 for (c = client_head; NULL != c; c = c->next)
732 GSC_CLIENTS_notify_client_about_neighbour (c,
733 neighbour,
734 tmap_old,
735 tmap_new);
736}
737
738
739/**
740 * Deliver P2P message to interested clients. Caller must have checked
741 * that the sending peer actually lists the given message type as one
742 * of its types.
743 *
744 * @param sender peer who sent us the message
745 * @param msg the message
746 * @param msize number of bytes to transmit
747 * @param options options for checking which clients should
748 * receive the message
749 */
750void
751GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
752 const struct GNUNET_MessageHeader *msg,
753 uint16_t msize,
754 uint32_t options)
755{
756 size_t size = msize + sizeof(struct NotifyTrafficMessage);
757
758 if (size >= GNUNET_MAX_MESSAGE_SIZE)
759 {
760 GNUNET_break (0);
761 return;
762 }
763 if (! ((0 != (all_client_options & options)) ||
764 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))))
765 return; /* no client cares about this message notification */
766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
767 "Core service passes message from `%s' of type %u to client.\n",
768 GNUNET_i2s (sender),
769 (unsigned int) ntohs (msg->type));
770 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
771
772 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
773 {
774 struct GNUNET_MQ_Envelope *env;
775 struct NotifyTrafficMessage *ntm;
776 uint16_t mtype;
777 unsigned int qlen;
778 int tm;
779
780 tm = type_match (ntohs (msg->type), c);
781 if (! ((0 != (c->options & options)) ||
782 ((0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
783 (GNUNET_YES == tm))))
784 continue; /* neither options nor type match permit the message */
785 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
786 ((0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
787 (GNUNET_YES == tm)))
788 continue;
789 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
790 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)))
791 continue;
792
793 /* Drop messages if:
794 1) We are above the hard limit, or
795 2) We are above the soft limit, and a coin toss limited
796 to the message size (giving larger messages a
797 proportionally higher chance of being queued) falls
798 below the threshold. The threshold is based on where
799 we are between the soft and the hard limit, scaled
800 to match the range of message sizes we usually encounter
801 (i.e. up to 32k); so a 64k message has a 50% chance of
802 being kept if we are just barely below the hard max,
803 and a 99% chance of being kept if we are at the soft max.
804 The reason is to make it more likely to drop control traffic
805 (ACK, queries) which may be cumulative or highly redundant,
806 and cheap to drop than data traffic. */qlen = GNUNET_MQ_get_length (c->mq);
807 if ((qlen >= HARD_MAX_QUEUE) ||
808 ((qlen > SOFT_MAX_QUEUE) &&
809 ((GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
810 ntohs (msg->size))) <
811 (qlen - SOFT_MAX_QUEUE) * 0x8000
812 / (HARD_MAX_QUEUE - SOFT_MAX_QUEUE))))
813 {
814 char buf[1024];
815
816 GNUNET_log (
817 GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
818 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
819 (unsigned int) ntohs (msg->type));
820 GNUNET_snprintf (buf,
821 sizeof(buf),
822 gettext_noop (
823 "# messages of type %u discarded (client busy)"),
824 (unsigned int) ntohs (msg->type));
825 GNUNET_STATISTICS_update (GSC_stats, buf, 1, GNUNET_NO);
826 continue;
827 }
828
829 GNUNET_log (
830 GNUNET_ERROR_TYPE_DEBUG,
831 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
832 options,
833 ntohs (msg->size),
834 (unsigned int) ntohs (msg->type));
835
836 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND
837 | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
838 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
839 else
840 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
841 env = GNUNET_MQ_msg_extra (ntm, msize, mtype);
842 ntm->peer = *sender;
843 GNUNET_memcpy (&ntm[1], msg, msize);
844
845 GNUNET_assert (
846 (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
847 (GNUNET_YES != tm) ||
848 (GNUNET_YES ==
849 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, sender)));
850 GNUNET_MQ_send (c->mq, env);
851 }
852}
853
854
855/**
856 * Last task run during shutdown. Disconnects us from
857 * the transport.
858 *
859 * @param cls NULL, unused
860 */
861static void
862shutdown_task (void *cls)
863{
864 struct GSC_Client *c;
865
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n");
867 while (NULL != (c = client_head))
868 GNUNET_SERVICE_client_drop (c->client);
869 GSC_SESSIONS_done ();
870 GSC_KX_done ();
871 GSC_TYPEMAP_done ();
872 if (NULL != GSC_stats)
873 {
874 GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO);
875 GSC_stats = NULL;
876 }
877 GSC_cfg = NULL;
878}
879
880
881/**
882 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
883 * request type, the client does not have to have transmitted an INIT
884 * request. All current peers are returned, regardless of which
885 * message types they accept.
886 *
887 * @param cls client sending the iteration request
888 * @param message iteration request message
889 */
890static void
891handle_client_monitor_peers (void *cls,
892 const struct GNUNET_MessageHeader *message)
893{
894 struct GSC_Client *c = cls;
895
896 GNUNET_SERVICE_client_continue (c->client);
897 GSC_KX_handle_client_monitor_peers (c->mq);
898}
899
900
901/**
902 * Initiate core service.
903 *
904 * @param cls closure
905 * @param c configuration to use
906 * @param service the initialized service
907 */
908static void
909run (void *cls,
910 const struct GNUNET_CONFIGURATION_Handle *c,
911 struct GNUNET_SERVICE_Handle *service)
912{
913 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
914 char *keyfile;
915
916 GSC_cfg = c;
917 if (GNUNET_OK !=
918 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
919 "PEER",
920 "PRIVATE_KEY",
921 &keyfile))
922 {
923 GNUNET_log (
924 GNUNET_ERROR_TYPE_ERROR,
925 _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
926 GNUNET_SCHEDULER_shutdown ();
927 return;
928 }
929 GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg);
930 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
931 GNUNET_SERVICE_suspend (service);
932 GSC_TYPEMAP_init ();
933 if (GNUNET_SYSERR ==
934 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
935 GNUNET_YES,
936 &pk))
937 {
938 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
939 "Failed to setup peer's private key\n");
940 GNUNET_SCHEDULER_shutdown ();
941 GNUNET_free (keyfile);
942 return;
943 }
944 GNUNET_free (keyfile);
945 if (GNUNET_OK != GSC_KX_init (&pk))
946 {
947 GNUNET_SCHEDULER_shutdown ();
948 return;
949 }
950 GSC_SESSIONS_init ();
951 GNUNET_SERVICE_resume (service);
952 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
953 _ ("Core service of `%s' ready.\n"),
954 GNUNET_i2s (&GSC_my_identity));
955}
956
957
958/**
959 * Define "main" method using service macro.
960 */
961GNUNET_SERVICE_MAIN (
962 "core",
963 GNUNET_SERVICE_OPTION_NONE,
964 &run,
965 &client_connect_cb,
966 &client_disconnect_cb,
967 NULL,
968 GNUNET_MQ_hd_var_size (client_init,
969 GNUNET_MESSAGE_TYPE_CORE_INIT,
970 struct InitMessage,
971 NULL),
972 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
973 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
974 struct GNUNET_MessageHeader,
975 NULL),
976 GNUNET_MQ_hd_fixed_size (client_send_request,
977 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
978 struct SendMessageRequest,
979 NULL),
980 GNUNET_MQ_hd_var_size (client_send,
981 GNUNET_MESSAGE_TYPE_CORE_SEND,
982 struct SendMessage,
983 NULL),
984 GNUNET_MQ_handler_end ());
985
986
987/* end of gnunet-service-core.c */