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.c989
1 files changed, 0 insertions, 989 deletions
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c
deleted file mode 100644
index 8f53072d9..000000000
--- a/src/core/gnunet-service-core.c
+++ /dev/null
@@ -1,989 +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 != memcmp (&car->target,
275 &GSC_my_identity,
276 sizeof(struct GNUNET_PeerIdentity)));
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 == memcmp (&req->peer,
318 &GSC_my_identity,
319 sizeof(struct GNUNET_PeerIdentity)));
320 if ((! is_loopback) &&
321 (GNUNET_YES !=
322 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &req->peer)))
323 {
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,
328 gettext_noop (
329 "# send requests dropped (disconnected)"),
330 1,
331 GNUNET_NO);
332 GNUNET_SERVICE_client_continue (c->client);
333 return;
334 }
335
336 car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer);
337 if (NULL == car)
338 {
339 /* create new entry */
340 car = GNUNET_new (struct GSC_ClientActiveRequest);
341 GNUNET_assert (GNUNET_OK ==
342 GNUNET_CONTAINER_multipeermap_put (
343 c->requests,
344 &req->peer,
345 car,
346 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
347 car->client_handle = c;
348 }
349 else
350 {
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,
354 gettext_noop (
355 "# dequeuing CAR (duplicate request)"),
356 1,
357 GNUNET_NO);
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));
362 }
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);
371 if (is_loopback)
372 {
373 /* loopback, satisfy immediately */
374 GSC_CLIENTS_solicit_request (car);
375 return;
376 }
377 GSC_SESSIONS_queue_request (car);
378}
379
380
381/**
382 * Closure for the #client_tokenizer_callback().
383 */
384struct TokenizerContext
385{
386 /**
387 * Active request handle for the message.
388 */
389 struct GSC_ClientActiveRequest *car;
390
391 /**
392 * How important is this message.
393 */
394 enum GNUNET_MQ_PriorityPreferences priority;
395};
396
397
398/**
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).
403 *
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
409 */
410static int
411tokenized_cb (void *cls, const struct GNUNET_MessageHeader *message)
412{
413 struct TokenizerContext *tc = cls;
414 struct GSC_ClientActiveRequest *car = tc->car;
415 char buf[92];
416
417 GNUNET_snprintf (buf,
418 sizeof(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,
423 &GSC_my_identity,
424 sizeof(struct GNUNET_PeerIdentity)))
425 {
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,
430 message,
431 ntohs (message->size),
432 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
433 GSC_CLIENTS_deliver_message (&GSC_my_identity,
434 message,
435 sizeof(struct GNUNET_MessageHeader),
436 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
437 GSC_CLIENTS_deliver_message (&GSC_my_identity,
438 message,
439 ntohs (message->size),
440 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
441 GSC_CLIENTS_deliver_message (&GSC_my_identity,
442 message,
443 sizeof(struct GNUNET_MessageHeader),
444 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
445 }
446 else
447 {
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,
454 message,
455 ntohs (message->size),
456 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
457 GSC_CLIENTS_deliver_message (&car->target,
458 message,
459 sizeof(struct GNUNET_MessageHeader),
460 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
461 GSC_SESSIONS_transmit (car, message, tc->priority);
462 }
463 return GNUNET_OK;
464}
465
466
467/**
468 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
469 *
470 * @param cls the `struct GSC_Client`
471 * @param sm the `struct SendMessage`
472 * @return #GNUNET_OK if @a sm is well-formed
473 */
474static int
475check_client_send (void *cls, const struct SendMessage *sm)
476{
477 return GNUNET_OK;
478}
479
480
481/**
482 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
483 *
484 * @param cls the `struct GSC_Client`
485 * @param sm the `struct SendMessage`
486 */
487static void
488handle_client_send (void *cls, const struct SendMessage *sm)
489{
490 struct GSC_Client *c = cls;
491 struct TokenizerContext tc;
492 uint16_t msize;
493 struct GNUNET_TIME_Relative delay;
494 struct GNUNET_MessageStreamTokenizer *mst;
495
496 msize = ntohs (sm->header.size) - sizeof(struct SendMessage);
497 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
498 if (NULL == tc.car)
499 {
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,
505 gettext_noop (
506 "# messages discarded (session disconnected)"),
507 1,
508 GNUNET_NO);
509 GNUNET_SERVICE_client_continue (c->client);
510 return;
511 }
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),
518 msize,
519 GNUNET_i2s (&sm->peer));
520 else
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),
524 msize,
525 GNUNET_i2s (&sm->peer));
526
527 GNUNET_assert (
528 GNUNET_YES ==
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],
533 msize,
534 GNUNET_YES,
535 GNUNET_NO);
536 GNUNET_MST_destroy (mst);
537 GSC_SESSIONS_dequeue_request (tc.car);
538 GNUNET_free (tc.car);
539 GNUNET_SERVICE_client_continue (c->client);
540}
541
542
543/**
544 * Free client request records.
545 *
546 * @param cls NULL
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)
550 */
551static int
552destroy_active_client_request (void *cls,
553 const struct GNUNET_PeerIdentity *key,
554 void *value)
555{
556 struct GSC_ClientActiveRequest *car = value;
557
558 GNUNET_assert (
559 GNUNET_YES ==
560 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
561 &car->target,
562 car));
563 GSC_SESSIONS_dequeue_request (car);
564 GNUNET_free (car);
565 return GNUNET_YES;
566}
567
568
569/**
570 * A client connected, set up.
571 *
572 * @param cls closure
573 * @param client identification of the client
574 * @param mq message queue to talk to @a client
575 * @return our client handle
576 */
577static void *
578client_connect_cb (void *cls,
579 struct GNUNET_SERVICE_Client *client,
580 struct GNUNET_MQ_Handle *mq)
581{
582 struct GSC_Client *c;
583
584 c = GNUNET_new (struct GSC_Client);
585 c->client = client;
586 c->mq = mq;
587 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
588 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
589 return c;
590}
591
592
593/**
594 * A client disconnected, clean up.
595 *
596 * @param cls closure
597 * @param client identification of the client
598 * @param app_ctx our `struct GST_Client` for @a client
599 */
600static void
601client_disconnect_cb (void *cls,
602 struct GNUNET_SERVICE_Client *client,
603 void *app_ctx)
604{
605 struct GSC_Client *c = app_ctx;
606
607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608 "Client %p has disconnected from core service.\n",
609 client);
610 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
611 if (NULL != c->requests)
612 {
613 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
614 &destroy_active_client_request,
615 NULL);
616 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
617 }
618 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
619 c->connectmap = NULL;
620 if (NULL != c->types)
621 {
622 GSC_TYPEMAP_remove (c->types, c->tcnt);
623 GNUNET_free (c->types);
624 }
625 GNUNET_free (c);
626
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;
631}
632
633
634/**
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().
638 *
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
643 */
644void
645GSC_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)
650{
651 struct GNUNET_MQ_Envelope *env;
652 int old_match;
653 int new_match;
654
655 if (GNUNET_YES != client->got_init)
656 return;
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),
662 old_match,
663 new_match);
664 if (old_match == new_match)
665 {
666 GNUNET_assert (
667 old_match ==
668 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
669 return; /* no change */
670 }
671 if (GNUNET_NO == old_match)
672 {
673 struct ConnectNotifyMessage *cnm;
674
675 /* send connect */
676 GNUNET_assert (
677 GNUNET_NO ==
678 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
679 GNUNET_assert (GNUNET_YES ==
680 GNUNET_CONTAINER_multipeermap_put (
681 client->connectmap,
682 neighbour,
683 NULL,
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);
692 }
693 else
694 {
695 struct DisconnectNotifyMessage *dcm;
696
697 /* send disconnect */
698 GNUNET_assert (
699 GNUNET_YES ==
700 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
701 GNUNET_assert (GNUNET_YES ==
702 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
703 neighbour,
704 NULL));
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);
712 }
713}
714
715
716/**
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.
720 *
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
724 */
725void
726GSC_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)
730{
731 struct GSC_Client *c;
732
733 for (c = client_head; NULL != c; c = c->next)
734 GSC_CLIENTS_notify_client_about_neighbour (c,
735 neighbour,
736 tmap_old,
737 tmap_new);
738}
739
740
741/**
742 * Deliver P2P message to interested clients. Caller must have checked
743 * that the sending peer actually lists the given message type as one
744 * of its types.
745 *
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
751 */
752void
753GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
754 const struct GNUNET_MessageHeader *msg,
755 uint16_t msize,
756 uint32_t options)
757{
758 size_t size = msize + sizeof(struct NotifyTrafficMessage);
759
760 if (size >= GNUNET_MAX_MESSAGE_SIZE)
761 {
762 GNUNET_break (0);
763 return;
764 }
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",
770 GNUNET_i2s (sender),
771 (unsigned int) ntohs (msg->type));
772 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
773
774 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
775 {
776 struct GNUNET_MQ_Envelope *env;
777 struct NotifyTrafficMessage *ntm;
778 uint16_t mtype;
779 unsigned int qlen;
780 int tm;
781
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)) ||
789 (GNUNET_YES == tm)))
790 continue;
791 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
792 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)))
793 continue;
794
795 /* Drop messages if:
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 cumulative 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))))
815 {
816 char buf[1024];
817
818 GNUNET_log (
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,
823 sizeof(buf),
824 gettext_noop (
825 "# messages of type %u discarded (client busy)"),
826 (unsigned int) ntohs (msg->type));
827 GNUNET_STATISTICS_update (GSC_stats, buf, 1, GNUNET_NO);
828 continue;
829 }
830
831 GNUNET_log (
832 GNUNET_ERROR_TYPE_DEBUG,
833 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
834 options,
835 ntohs (msg->size),
836 (unsigned int) ntohs (msg->type));
837
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;
841 else
842 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
843 env = GNUNET_MQ_msg_extra (ntm, msize, mtype);
844 ntm->peer = *sender;
845 GNUNET_memcpy (&ntm[1], msg, msize);
846
847 GNUNET_assert (
848 (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
849 (GNUNET_YES != tm) ||
850 (GNUNET_YES ==
851 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, sender)));
852 GNUNET_MQ_send (c->mq, env);
853 }
854}
855
856
857/**
858 * Last task run during shutdown. Disconnects us from
859 * the transport.
860 *
861 * @param cls NULL, unused
862 */
863static void
864shutdown_task (void *cls)
865{
866 struct GSC_Client *c;
867
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 ();
872 GSC_KX_done ();
873 GSC_TYPEMAP_done ();
874 if (NULL != GSC_stats)
875 {
876 GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO);
877 GSC_stats = NULL;
878 }
879 GSC_cfg = NULL;
880}
881
882
883/**
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.
888 *
889 * @param cls client sending the iteration request
890 * @param message iteration request message
891 */
892static void
893handle_client_monitor_peers (void *cls,
894 const struct GNUNET_MessageHeader *message)
895{
896 struct GSC_Client *c = cls;
897
898 GNUNET_SERVICE_client_continue (c->client);
899 GSC_KX_handle_client_monitor_peers (c->mq);
900}
901
902
903/**
904 * Initiate core service.
905 *
906 * @param cls closure
907 * @param c configuration to use
908 * @param service the initialized service
909 */
910static void
911run (void *cls,
912 const struct GNUNET_CONFIGURATION_Handle *c,
913 struct GNUNET_SERVICE_Handle *service)
914{
915 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
916 char *keyfile;
917
918 GSC_cfg = c;
919 if (GNUNET_OK !=
920 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
921 "PEER",
922 "PRIVATE_KEY",
923 &keyfile))
924 {
925 GNUNET_log (
926 GNUNET_ERROR_TYPE_ERROR,
927 _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
928 GNUNET_SCHEDULER_shutdown ();
929 return;
930 }
931 GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg);
932 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
933 GNUNET_SERVICE_suspend (service);
934 GSC_TYPEMAP_init ();
935 if (GNUNET_SYSERR ==
936 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
937 GNUNET_YES,
938 &pk))
939 {
940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
941 "Failed to setup peer's private key\n");
942 GNUNET_SCHEDULER_shutdown ();
943 GNUNET_free (keyfile);
944 return;
945 }
946 GNUNET_free (keyfile);
947 if (GNUNET_OK != GSC_KX_init (&pk))
948 {
949 GNUNET_SCHEDULER_shutdown ();
950 return;
951 }
952 GSC_SESSIONS_init ();
953 GNUNET_SERVICE_resume (service);
954 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
955 _ ("Core service of `%s' ready.\n"),
956 GNUNET_i2s (&GSC_my_identity));
957}
958
959
960/**
961 * Define "main" method using service macro.
962 */
963GNUNET_SERVICE_MAIN (
964 "core",
965 GNUNET_SERVICE_OPTION_NONE,
966 &run,
967 &client_connect_cb,
968 &client_disconnect_cb,
969 NULL,
970 GNUNET_MQ_hd_var_size (client_init,
971 GNUNET_MESSAGE_TYPE_CORE_INIT,
972 struct InitMessage,
973 NULL),
974 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
975 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
976 struct GNUNET_MessageHeader,
977 NULL),
978 GNUNET_MQ_hd_fixed_size (client_send_request,
979 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
980 struct SendMessageRequest,
981 NULL),
982 GNUNET_MQ_hd_var_size (client_send,
983 GNUNET_MESSAGE_TYPE_CORE_SEND,
984 struct SendMessage,
985 NULL),
986 GNUNET_MQ_handler_end ());
987
988
989/* end of gnunet-service-core.c */