aboutsummaryrefslogtreecommitdiff
path: root/src/core/gnunet-service-core_neighbours.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-07-26 21:12:56 +0000
committerChristian Grothoff <christian@grothoff.org>2016-07-26 21:12:56 +0000
commit8c2dc7d19810d58f23c43bf900e2fb3eebe06fed (patch)
tree9173a966e2f51a34d9259a0126484e05d44dcaac /src/core/gnunet-service-core_neighbours.c
parenta89ea716333ad5ad43757a946efc01cb5e95a0c0 (diff)
downloadgnunet-8c2dc7d19810d58f23c43bf900e2fb3eebe06fed.tar.gz
gnunet-8c2dc7d19810d58f23c43bf900e2fb3eebe06fed.zip
-converting CORE service to new transport MQ API
Diffstat (limited to 'src/core/gnunet-service-core_neighbours.c')
-rw-r--r--src/core/gnunet-service-core_neighbours.c679
1 files changed, 0 insertions, 679 deletions
diff --git a/src/core/gnunet-service-core_neighbours.c b/src/core/gnunet-service-core_neighbours.c
deleted file mode 100644
index 7af49a3b3..000000000
--- a/src/core/gnunet-service-core_neighbours.c
+++ /dev/null
@@ -1,679 +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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @file core/gnunet-service-core_neighbours.c
23 * @brief code for managing low-level 'plaintext' connections with transport (key exchange may or may not be done yet)
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_transport_core_service.h"
31#include "gnunet-service-core.h"
32#include "gnunet-service-core_neighbours.h"
33#include "gnunet-service-core_kx.h"
34#include "gnunet-service-core_sessions.h"
35#include "gnunet_constants.h"
36
37
38/**
39 * Message ready for transmission via transport service. This struct
40 * is followed by the actual content of the message.
41 */
42struct NeighbourMessageEntry
43{
44
45 /**
46 * We keep messages in a doubly linked list.
47 */
48 struct NeighbourMessageEntry *next;
49
50 /**
51 * We keep messages in a doubly linked list.
52 */
53 struct NeighbourMessageEntry *prev;
54
55 /**
56 * By when are we supposed to transmit this message?
57 */
58 struct GNUNET_TIME_Absolute deadline;
59
60 /**
61 * What time did we submit the request?
62 */
63 struct GNUNET_TIME_Absolute submission_time;
64
65 /**
66 * How long is the message? (number of bytes following the `struct
67 * MessageEntry`, but not including the size of `struct
68 * MessageEntry` itself!)
69 */
70 size_t size;
71
72};
73
74
75/**
76 * Data kept per transport-connected peer.
77 */
78struct Neighbour
79{
80
81 /**
82 * Head of the batched message queue (already ordered, transmit
83 * starting with the head).
84 */
85 struct NeighbourMessageEntry *message_head;
86
87 /**
88 * Tail of the batched message queue (already ordered, append new
89 * messages to tail).
90 */
91 struct NeighbourMessageEntry *message_tail;
92
93 /**
94 * Handle for pending requests for transmission to this peer
95 * with the transport service. NULL if no request is pending.
96 */
97 struct GNUNET_TRANSPORT_TransmitHandle *th;
98
99 /**
100 * Information about the key exchange with the other peer.
101 */
102 struct GSC_KeyExchangeInfo *kxinfo;
103
104 /**
105 * Identity of the other peer.
106 */
107 struct GNUNET_PeerIdentity peer;
108
109 /**
110 * ID of task used for re-trying plaintext scheduling.
111 */
112 struct GNUNET_SCHEDULER_Task *retry_plaintext_task;
113
114 /**
115 * How many messages are in the queue for this neighbour?
116 */
117 unsigned int queue_size;
118
119 /**
120 * #GNUNET_YES if this peer currently has excess bandwidth.
121 */
122 int has_excess_bandwidth;
123
124};
125
126
127/**
128 * Map of peer identities to `struct Neighbour`.
129 */
130static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
131
132/**
133 * Transport service.
134 */
135static struct GNUNET_TRANSPORT_Handle *transport;
136
137
138/**
139 * Find the entry for the given neighbour.
140 *
141 * @param peer identity of the neighbour
142 * @return NULL if we are not connected, otherwise the
143 * neighbour's entry.
144 */
145static struct Neighbour *
146find_neighbour (const struct GNUNET_PeerIdentity *peer)
147{
148 if (NULL == neighbours)
149 return NULL;
150 return GNUNET_CONTAINER_multipeermap_get (neighbours,
151 peer);
152}
153
154
155/**
156 * Free the given entry for the neighbour.
157 *
158 * @param n neighbour to free
159 */
160static void
161free_neighbour (struct Neighbour *n)
162{
163 struct NeighbourMessageEntry *m;
164
165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
166 "Destroying neighbour entry for peer `%s'\n",
167 GNUNET_i2s (&n->peer));
168 while (NULL != (m = n->message_head))
169 {
170 GNUNET_CONTAINER_DLL_remove (n->message_head,
171 n->message_tail,
172 m);
173 n->queue_size--;
174 GNUNET_free (m);
175 }
176 GNUNET_assert (0 == n->queue_size);
177 if (NULL != n->th)
178 {
179 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
180 n->th = NULL;
181 }
182 GNUNET_STATISTICS_update (GSC_stats,
183 gettext_noop
184 ("# sessions terminated by transport disconnect"),
185 1, GNUNET_NO);
186 if (NULL != n->kxinfo)
187 {
188 GSC_KX_stop (n->kxinfo);
189 n->kxinfo = NULL;
190 }
191 if (NULL != n->retry_plaintext_task)
192 {
193 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
194 n->retry_plaintext_task = NULL;
195 }
196 GNUNET_assert (GNUNET_OK ==
197 GNUNET_CONTAINER_multipeermap_remove (neighbours,
198 &n->peer, n));
199 GNUNET_STATISTICS_set (GSC_stats,
200 gettext_noop ("# neighbour entries allocated"),
201 GNUNET_CONTAINER_multipeermap_size (neighbours),
202 GNUNET_NO);
203 GNUNET_free (n);
204}
205
206
207/**
208 * Check if we have encrypted messages for the specified neighbour
209 * pending, and if so, check with the transport about sending them
210 * out.
211 *
212 * @param n neighbour to check.
213 */
214static void
215process_queue (struct Neighbour *n);
216
217
218/**
219 * Function called when the transport service is ready to receive a
220 * message for the respective peer
221 *
222 * @param cls neighbour to use message from
223 * @param size number of bytes we can transmit
224 * @param buf where to copy the message
225 * @return number of bytes transmitted
226 */
227static size_t
228transmit_ready (void *cls,
229 size_t size,
230 void *buf)
231{
232 struct Neighbour *n = cls;
233 struct NeighbourMessageEntry *m;
234 size_t ret;
235 char *cbuf;
236 struct GNUNET_TIME_Relative delay;
237 struct GNUNET_TIME_Relative overdue;
238
239 n->th = NULL;
240 m = n->message_head;
241 if (NULL == m)
242 {
243 GNUNET_break (0);
244 return 0;
245 }
246 GNUNET_CONTAINER_DLL_remove (n->message_head,
247 n->message_tail,
248 m);
249 n->queue_size--;
250 if (NULL == buf)
251 {
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253 "Transmission of message of type %u and size %u failed\n",
254 (unsigned int)
255 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
256 (unsigned int) m->size);
257 GNUNET_free (m);
258 process_queue (n);
259 return 0;
260 }
261 delay = GNUNET_TIME_absolute_get_duration (m->submission_time);
262 overdue = GNUNET_TIME_absolute_get_duration (m->deadline);
263 cbuf = buf;
264 GNUNET_assert (size >= m->size);
265 GNUNET_memcpy (cbuf,
266 &m[1],
267 m->size);
268 ret = m->size;
269 if (overdue.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
270 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
271 "Copied overdue message of type %u and size %u into transport buffer for `%s' with delay of %s\n",
272 (unsigned int)
273 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
274 (unsigned int) ret,
275 GNUNET_i2s (&n->peer),
276 GNUNET_STRINGS_relative_time_to_string (delay,
277 GNUNET_YES));
278 else
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 "Copied message of type %u and size %u into transport buffer for `%s' with delay of %s\n",
281 (unsigned int)
282 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
283 (unsigned int) ret,
284 GNUNET_i2s (&n->peer),
285 GNUNET_STRINGS_relative_time_to_string (delay,
286 GNUNET_YES));
287 GNUNET_free (m);
288 n->has_excess_bandwidth = GNUNET_NO;
289 process_queue (n);
290 GNUNET_STATISTICS_update (GSC_stats,
291 gettext_noop
292 ("# encrypted bytes given to transport"), ret,
293 GNUNET_NO);
294 return ret;
295}
296
297
298/**
299 * Check if we have messages for the specified neighbour pending, and
300 * if so, check with the transport about sending them out.
301 *
302 * @param n neighbour to check.
303 */
304static void
305process_queue (struct Neighbour *n)
306{
307 struct NeighbourMessageEntry *m;
308
309 if (NULL != n->th)
310 return; /* request already pending */
311 m = n->message_head;
312 if (NULL == m)
313 {
314 /* notify sessions that the queue is empty and more messages
315 * could thus be queued now */
316 GSC_SESSIONS_solicit (&n->peer);
317 return;
318 }
319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320 "Asking transport for transmission of %u bytes to `%s' in next %s\n",
321 (unsigned int) m->size,
322 GNUNET_i2s (&n->peer),
323 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (m->deadline),
324 GNUNET_NO));
325 m->submission_time = GNUNET_TIME_absolute_get ();
326 n->th
327 = GNUNET_TRANSPORT_notify_transmit_ready (transport,
328 &n->peer,
329 m->size,
330 GNUNET_TIME_absolute_get_remaining (m->deadline),
331 &transmit_ready,
332 n);
333 if (NULL != n->th)
334 return;
335 /* message request too large or duplicate request */
336 GNUNET_break (0);
337 /* discard encrypted message */
338 GNUNET_CONTAINER_DLL_remove (n->message_head,
339 n->message_tail,
340 m);
341 n->queue_size--;
342 GNUNET_free (m);
343 process_queue (n);
344}
345
346
347/**
348 * Function called by transport to notify us that
349 * a peer connected to us (on the network level).
350 *
351 * @param cls closure
352 * @param peer the peer that connected
353 */
354static void
355handle_transport_notify_connect (void *cls,
356 const struct GNUNET_PeerIdentity *peer)
357{
358 struct Neighbour *n;
359
360 if (0 == memcmp (peer,
361 &GSC_my_identity,
362 sizeof (struct GNUNET_PeerIdentity)))
363 {
364 GNUNET_break (0);
365 return;
366 }
367 n = find_neighbour (peer);
368 if (NULL != n)
369 {
370 /* duplicate connect notification!? */
371 GNUNET_break (0);
372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373 "Peer %s exists already\n",
374 GNUNET_i2s (peer));
375 return;
376 }
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Received connection from `%s'.\n",
379 GNUNET_i2s (peer));
380 n = GNUNET_new (struct Neighbour);
381 n->peer = *peer;
382 GNUNET_assert (GNUNET_OK ==
383 GNUNET_CONTAINER_multipeermap_put (neighbours,
384 &n->peer,
385 n,
386 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
387 GNUNET_STATISTICS_set (GSC_stats,
388 gettext_noop ("# neighbour entries allocated"),
389 GNUNET_CONTAINER_multipeermap_size (neighbours),
390 GNUNET_NO);
391 n->kxinfo = GSC_KX_start (peer);
392}
393
394
395/**
396 * Function called by transport telling us that a peer
397 * disconnected.
398 *
399 * @param cls closure
400 * @param peer the peer that disconnected
401 */
402static void
403handle_transport_notify_disconnect (void *cls,
404 const struct GNUNET_PeerIdentity *peer)
405{
406 struct Neighbour *n;
407
408 if (0 == memcmp (peer,
409 &GSC_my_identity,
410 sizeof (struct GNUNET_PeerIdentity)))
411 {
412 GNUNET_break (0);
413 return;
414 }
415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416 "Peer `%s' disconnected from us; received notification from transport.\n",
417 GNUNET_i2s (peer));
418 n = find_neighbour (peer);
419 if (NULL == n)
420 {
421 GNUNET_break (0);
422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
423 "Peer %s not found\n",
424 GNUNET_i2s (peer));
425 return;
426 }
427 free_neighbour (n);
428}
429
430
431/**
432 * Function called by the transport for each received message.
433 *
434 * @param cls closure
435 * @param peer (claimed) identity of the other peer
436 * @param message the message
437 */
438static void
439handle_transport_receive (void *cls,
440 const struct GNUNET_PeerIdentity *peer,
441 const struct GNUNET_MessageHeader *message)
442{
443 struct Neighbour *n;
444 uint16_t type;
445
446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447 "Received message of type %u from `%s', demultiplexing.\n",
448 (unsigned int) ntohs (message->type),
449 GNUNET_i2s (peer));
450 if (0 == memcmp (peer,
451 &GSC_my_identity,
452 sizeof (struct GNUNET_PeerIdentity)))
453 {
454 GNUNET_break (0);
455 return;
456 }
457 n = find_neighbour (peer);
458 if (NULL == n)
459 {
460 /* received message from peer that is not connected!? */
461 GNUNET_break (0);
462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
463 "Peer %s not found\n",
464 GNUNET_i2s (peer));
465 return;
466 }
467 type = ntohs (message->type);
468 switch (type)
469 {
470 case GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY:
471 GSC_KX_handle_ephemeral_key (n->kxinfo, message);
472 break;
473 case GNUNET_MESSAGE_TYPE_CORE_PING:
474 GSC_KX_handle_ping (n->kxinfo, message);
475 break;
476 case GNUNET_MESSAGE_TYPE_CORE_PONG:
477 GSC_KX_handle_pong (n->kxinfo, message);
478 break;
479 case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
480 GSC_KX_handle_encrypted_message (n->kxinfo, message);
481 break;
482 default:
483 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
484 _("Unsupported message of type %u (%u bytes) received from peer `%s'\n"),
485 (unsigned int) type,
486 (unsigned int) ntohs (message->size),
487 GNUNET_i2s (peer));
488 return;
489 }
490}
491
492
493/**
494 * Transmit the given message to the given target.
495 *
496 * @param target peer that should receive the message (must be connected)
497 * @param msg message to transmit
498 * @param timeout by when should the transmission be done?
499 */
500void
501GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target,
502 const struct GNUNET_MessageHeader *msg,
503 struct GNUNET_TIME_Relative timeout)
504{
505 struct NeighbourMessageEntry *me;
506 struct Neighbour *n;
507 size_t msize;
508
509 n = find_neighbour (target);
510 if (NULL == n)
511 {
512 GNUNET_break (0);
513 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
514 "Peer %s not found\n",
515 GNUNET_i2s (target));
516 return;
517 }
518 msize = ntohs (msg->size);
519 me = GNUNET_malloc (sizeof (struct NeighbourMessageEntry) + msize);
520 me->deadline = GNUNET_TIME_relative_to_absolute (timeout);
521 me->size = msize;
522 GNUNET_memcpy (&me[1],
523 msg,
524 msize);
525 GNUNET_CONTAINER_DLL_insert_tail (n->message_head,
526 n->message_tail,
527 me);
528 n->queue_size++;
529 process_queue (n);
530}
531
532
533/**
534 * One of our neighbours has excess bandwidth, remember this.
535 *
536 * @param cls NULL
537 * @param pid identity of the peer with excess bandwidth
538 */
539static void
540handle_transport_notify_excess_bw (void *cls,
541 const struct GNUNET_PeerIdentity *pid)
542{
543 struct Neighbour *n;
544
545 n = find_neighbour (pid);
546 if (NULL == n)
547 {
548 GNUNET_break (0);
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 "Peer %s not found\n",
551 GNUNET_i2s (pid));
552 return;
553 }
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 "Peer %s has excess bandwidth available\n",
556 GNUNET_i2s (pid));
557 n->has_excess_bandwidth = GNUNET_YES;
558 GSC_SESSIONS_solicit (pid);
559}
560
561
562/**
563 * Check how many messages are queued for the given neighbour.
564 *
565 * @param target neighbour to check
566 * @return number of items in the message queue
567 */
568unsigned int
569GSC_NEIGHBOURS_get_queue_size (const struct GNUNET_PeerIdentity *target)
570{
571 struct Neighbour *n;
572
573 n = find_neighbour (target);
574 if (NULL == n)
575 {
576 GNUNET_break (0);
577 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
578 "Peer %s not found\n",
579 GNUNET_i2s (target));
580 return UINT_MAX;
581 }
582 return n->queue_size;
583}
584
585
586/**
587 * Check if the given neighbour has excess bandwidth available.
588 *
589 * @param target neighbour to check
590 * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not
591 */
592int
593GSC_NEIGHBOURS_check_excess_bandwidth (const struct GNUNET_PeerIdentity *target)
594{
595 struct Neighbour *n;
596
597 n = find_neighbour (target);
598 if (NULL == n)
599 {
600 GNUNET_break (0);
601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
602 "Peer %s not found\n",
603 GNUNET_i2s (target));
604 return GNUNET_SYSERR;
605 }
606 return n->has_excess_bandwidth;
607}
608
609
610/**
611 * Initialize neighbours subsystem.
612 */
613int
614GSC_NEIGHBOURS_init ()
615{
616 neighbours = GNUNET_CONTAINER_multipeermap_create (128,
617 GNUNET_YES);
618 transport =
619 GNUNET_TRANSPORT_connect2 (GSC_cfg,
620 &GSC_my_identity,
621 NULL,
622 &handle_transport_receive,
623 &handle_transport_notify_connect,
624 &handle_transport_notify_disconnect,
625 &handle_transport_notify_excess_bw);
626 if (NULL == transport)
627 {
628 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
629 neighbours = NULL;
630 return GNUNET_SYSERR;
631 }
632 return GNUNET_OK;
633}
634
635
636/**
637 * Wrapper around #free_neighbour().
638 *
639 * @param cls unused
640 * @param key peer identity
641 * @param value the `struct Neighbour` to free
642 * @return #GNUNET_OK (continue to iterate)
643 */
644static int
645free_neighbour_helper (void *cls,
646 const struct GNUNET_PeerIdentity * key,
647 void *value)
648{
649 struct Neighbour *n = value;
650
651 /* transport should have 'disconnected' all neighbours... */
652 GNUNET_break (0);
653 free_neighbour (n);
654 return GNUNET_OK;
655}
656
657
658/**
659 * Shutdown neighbours subsystem.
660 */
661void
662GSC_NEIGHBOURS_done ()
663{
664 if (NULL != transport)
665 {
666 GNUNET_TRANSPORT_disconnect (transport);
667 transport = NULL;
668 }
669 if (NULL != neighbours)
670 {
671 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
672 &free_neighbour_helper,
673 NULL);
674 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
675 neighbours = NULL;
676 }
677}
678
679/* end of gnunet-service-core_neighbours.c */