-fixing #2195
[oweals/gnunet.git] / src / core / gnunet-service-core_neighbours.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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-service-core.h"
31 #include "gnunet-service-core_neighbours.h"
32 #include "gnunet-service-core_kx.h"
33 #include "gnunet-service-core_sessions.h"
34 #include "gnunet_constants.h"
35
36
37 /**
38  * Message ready for transmission via transport service.  This struct
39  * is followed by the actual content of the message.
40  */
41 struct NeighbourMessageEntry
42 {
43
44   /**
45    * We keep messages in a doubly linked list.
46    */
47   struct NeighbourMessageEntry *next;
48
49   /**
50    * We keep messages in a doubly linked list.
51    */
52   struct NeighbourMessageEntry *prev;
53
54   /**
55    * By when are we supposed to transmit this message?
56    */
57   struct GNUNET_TIME_Absolute deadline;
58
59   /**
60    * How long is the message? (number of bytes following the "struct
61    * MessageEntry", but not including the size of "struct
62    * MessageEntry" itself!)
63    */
64   size_t size;
65
66 };
67
68
69 /**
70  * Data kept per transport-connected peer.
71  */
72 struct Neighbour
73 {
74
75   /**
76    * Head of the batched message queue (already ordered, transmit
77    * starting with the head).
78    */
79   struct NeighbourMessageEntry *message_head;
80
81   /**
82    * Tail of the batched message queue (already ordered, append new
83    * messages to tail).
84    */
85   struct NeighbourMessageEntry *message_tail;
86
87   /**
88    * Handle for pending requests for transmission to this peer
89    * with the transport service.  NULL if no request is pending.
90    */
91   struct GNUNET_TRANSPORT_TransmitHandle *th;
92
93   /**
94    * Information about the key exchange with the other peer.
95    */
96   struct GSC_KeyExchangeInfo *kxinfo;
97
98   /**
99    * Identity of the other peer.
100    */
101   struct GNUNET_PeerIdentity peer;
102
103   /**
104    * ID of task used for re-trying plaintext scheduling.
105    */
106   GNUNET_SCHEDULER_TaskIdentifier retry_plaintext_task;
107
108 };
109
110
111 /**
112  * Map of peer identities to 'struct Neighbour'.
113  */
114 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
115
116 /**
117  * Transport service.
118  */
119 static struct GNUNET_TRANSPORT_Handle *transport;
120
121
122 /**
123  * Find the entry for the given neighbour.
124  *
125  * @param peer identity of the neighbour
126  * @return NULL if we are not connected, otherwise the
127  *         neighbour's entry.
128  */
129 static struct Neighbour *
130 find_neighbour (const struct GNUNET_PeerIdentity *peer)
131 {
132   if (NULL == neighbours)
133     return NULL;
134   return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
135 }
136
137
138 /**
139  * Free the given entry for the neighbour.
140  *
141  * @param n neighbour to free
142  */
143 static void
144 free_neighbour (struct Neighbour *n)
145 {
146   struct NeighbourMessageEntry *m;
147
148 #if DEBUG_CORE
149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150               "Destroying neighbour entry for peer `%4s'\n",
151               GNUNET_i2s (&n->peer));
152 #endif
153   while (NULL != (m = n->message_head))
154   {
155     GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
156     GNUNET_free (m);
157   }
158   if (NULL != n->th)
159   {
160     GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
161     n->th = NULL;
162   }
163   GNUNET_STATISTICS_update (GSC_stats,
164                             gettext_noop
165                             ("# sessions terminated by transport disconnect"),
166                             1, GNUNET_NO);
167   GSC_SESSIONS_end (&n->peer);
168   if (NULL != n->kxinfo)
169   {
170     GSC_KX_stop (n->kxinfo);
171     n->kxinfo = NULL;
172   }
173   if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
174   {
175     GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
176     n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
177   }
178   GNUNET_assert (GNUNET_OK ==
179                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
180                                                        &n->peer.hashPubKey, n));
181   GNUNET_STATISTICS_set (GSC_stats,
182                          gettext_noop ("# neighbour entries allocated"),
183                          GNUNET_CONTAINER_multihashmap_size (neighbours),
184                          GNUNET_NO);
185   GNUNET_free (n);
186 }
187
188
189 /**
190  * Check if we have encrypted messages for the specified neighbour
191  * pending, and if so, check with the transport about sending them
192  * out.
193  *
194  * @param n neighbour to check.
195  */
196 static void
197 process_queue (struct Neighbour *n);
198
199
200 /**
201  * Function called when the transport service is ready to receive a
202  * message for the respective peer
203  *
204  * @param cls neighbour to use message from
205  * @param size number of bytes we can transmit
206  * @param buf where to copy the message
207  * @return number of bytes transmitted
208  */
209 static size_t
210 transmit_ready (void *cls, size_t size, void *buf)
211 {
212   struct Neighbour *n = cls;
213   struct NeighbourMessageEntry *m;
214   size_t ret;
215   char *cbuf;
216
217   n->th = NULL;
218   m = n->message_head;
219   if (m == NULL)
220   {
221     GNUNET_break (0);
222     return 0;
223   }
224   GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
225   if (buf == NULL)
226   {
227 #if DEBUG_CORE
228     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
229                 "Transmission of message of type %u and size %u failed\n",
230                 (unsigned int)
231                 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
232                 (unsigned int) m->size);
233 #endif
234     GNUNET_free (m);
235     process_queue (n);
236     return 0;
237   }
238   cbuf = buf;
239   GNUNET_assert (size >= m->size);
240   memcpy (cbuf, &m[1], m->size);
241   ret = m->size;
242 #if DEBUG_CORE
243   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244               "Copied message of type %u and size %u into transport buffer for `%4s'\n",
245               (unsigned int)
246               ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
247               (unsigned int) ret, GNUNET_i2s (&n->peer));
248 #endif
249   GNUNET_free (m);
250   process_queue (n);
251   GNUNET_STATISTICS_update (GSC_stats,
252                             gettext_noop
253                             ("# encrypted bytes given to transport"), ret,
254                             GNUNET_NO);
255   return ret;
256 }
257
258
259 /**
260  * Check if we have messages for the specified neighbour pending, and
261  * if so, check with the transport about sending them out.
262  *
263  * @param n neighbour to check.
264  */
265 static void
266 process_queue (struct Neighbour *n)
267 {
268   struct NeighbourMessageEntry *m;
269
270   if (n->th != NULL)
271     return;                     /* request already pending */
272   m = n->message_head;
273   if (m == NULL)
274   {
275     /* notify sessions that the queue is empty and more messages
276      * could thus be queued now */
277     GSC_SESSIONS_solicit (&n->peer);
278     return;
279   }
280 #if DEBUG_CORE > 1
281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282               "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
283               (unsigned int) m->size, GNUNET_i2s (&n->peer),
284               (unsigned long long)
285               GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
286 #endif
287   n->th =
288       GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size, 0,
289                                               GNUNET_TIME_absolute_get_remaining
290                                               (m->deadline), &transmit_ready,
291                                               n);
292   if (n->th != NULL)
293     return;
294   /* message request too large or duplicate request */
295   GNUNET_break (0);
296   /* discard encrypted message */
297   GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
298   GNUNET_free (m);
299   process_queue (n);
300 }
301
302
303
304 /**
305  * Function called by transport to notify us that
306  * a peer connected to us (on the network level).
307  *
308  * @param cls closure
309  * @param peer the peer that connected
310  * @param atsi performance data
311  * @param atsi_count number of entries in ats (excluding 0-termination)
312  */
313 static void
314 handle_transport_notify_connect (void *cls,
315                                  const struct GNUNET_PeerIdentity *peer,
316                                  const struct GNUNET_ATS_Information *atsi,
317                                  uint32_t atsi_count)
318 {
319   struct Neighbour *n;
320
321   if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
322   {
323     GNUNET_break (0);
324     return;
325   }
326   n = find_neighbour (peer);
327   if (n != NULL)
328   {
329     /* duplicate connect notification!? */
330     GNUNET_break (0);
331     return;
332   }
333 #if DEBUG_CORE
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%4s'.\n",
335               GNUNET_i2s (peer));
336 #endif
337   n = GNUNET_malloc (sizeof (struct Neighbour));
338   n->peer = *peer;
339   GNUNET_assert (GNUNET_OK ==
340                  GNUNET_CONTAINER_multihashmap_put (neighbours,
341                                                     &n->peer.hashPubKey, n,
342                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
343   GNUNET_STATISTICS_set (GSC_stats,
344                          gettext_noop ("# neighbour entries allocated"),
345                          GNUNET_CONTAINER_multihashmap_size (neighbours),
346                          GNUNET_NO);
347   n->kxinfo = GSC_KX_start (peer);
348 }
349
350
351 /**
352  * Function called by transport telling us that a peer
353  * disconnected.
354  *
355  * @param cls closure
356  * @param peer the peer that disconnected
357  */
358 static void
359 handle_transport_notify_disconnect (void *cls,
360                                     const struct GNUNET_PeerIdentity *peer)
361 {
362   struct Neighbour *n;
363
364 #if DEBUG_CORE
365   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
366               "Peer `%4s' disconnected from us; received notification from transport.\n",
367               GNUNET_i2s (peer));
368 #endif
369   n = find_neighbour (peer);
370   if (n == NULL)
371   {
372     GNUNET_break (0);
373     return;
374   }
375   free_neighbour (n);
376 }
377
378
379 /**
380  * Function called by the transport for each received message.
381  *
382  * @param cls closure
383  * @param peer (claimed) identity of the other peer
384  * @param message the message
385  * @param atsi performance data
386  * @param atsi_count number of entries in ats (excluding 0-termination)
387  */
388 static void
389 handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
390                           const struct GNUNET_MessageHeader *message,
391                           const struct GNUNET_ATS_Information *atsi,
392                           uint32_t atsi_count)
393 {
394   struct Neighbour *n;
395   uint16_t type;
396
397 #if DEBUG_CORE > 1
398   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399               "Received message of type %u from `%4s', demultiplexing.\n",
400               (unsigned int) ntohs (message->type), GNUNET_i2s (peer));
401 #endif
402   if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
403   {
404     GNUNET_break (0);
405     return;
406   }
407   n = find_neighbour (peer);
408   if (n == NULL)
409   {
410     /* received message from peer that is not connected!? */
411     GNUNET_break (0);
412     return;
413   }
414   type = ntohs (message->type);
415   switch (type)
416   {
417   case GNUNET_MESSAGE_TYPE_CORE_SET_KEY:
418     GSC_KX_handle_set_key (n->kxinfo, message);
419     break;
420   case GNUNET_MESSAGE_TYPE_CORE_PING:
421     GSC_KX_handle_ping (n->kxinfo, message);
422     break;
423   case GNUNET_MESSAGE_TYPE_CORE_PONG:
424     GSC_KX_handle_pong (n->kxinfo, message);
425     break;
426   case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
427     GSC_KX_handle_encrypted_message (n->kxinfo, message, atsi, atsi_count);
428     break;
429   default:
430     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
431                 _
432                 ("Unsupported message of type %u (%u bytes) received from peer `%s'\n"),
433                 (unsigned int) type, (unsigned int) ntohs (message->size),
434                 GNUNET_i2s (peer));
435     return;
436   }
437 }
438
439
440 /**
441  * Transmit the given message to the given target.
442  *
443  * @param target peer that should receive the message (must be connected)
444  * @param msg message to transmit
445  * @param timeout by when should the transmission be done?
446  */
447 void
448 GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target,
449                          const struct GNUNET_MessageHeader *msg,
450                          struct GNUNET_TIME_Relative timeout)
451 {
452   struct NeighbourMessageEntry *me;
453   struct Neighbour *n;
454   size_t msize;
455
456   n = find_neighbour (target);
457   if (NULL == n)
458   {
459     GNUNET_break (0);
460     return;
461   }
462   msize = ntohs (msg->size);
463   me = GNUNET_malloc (sizeof (struct NeighbourMessageEntry) + msize);
464   me->deadline = GNUNET_TIME_relative_to_absolute (timeout);
465   me->size = msize;
466   memcpy (&me[1], msg, msize);
467   GNUNET_CONTAINER_DLL_insert_tail (n->message_head, n->message_tail, me);
468   process_queue (n);
469 }
470
471
472 /**
473  * Initialize neighbours subsystem.
474  */
475 int
476 GSC_NEIGHBOURS_init ()
477 {
478   neighbours = GNUNET_CONTAINER_multihashmap_create (128);
479   transport =
480       GNUNET_TRANSPORT_connect (GSC_cfg, &GSC_my_identity, NULL,
481                                 &handle_transport_receive,
482                                 &handle_transport_notify_connect,
483                                 &handle_transport_notify_disconnect);
484   if (NULL == transport)
485   {
486     GNUNET_CONTAINER_multihashmap_destroy (neighbours);
487     neighbours = NULL;
488     return GNUNET_SYSERR;
489   }
490   return GNUNET_OK;
491 }
492
493
494 /**
495  * Wrapper around 'free_neighbour'.
496  *
497  * @param cls unused
498  * @param key peer identity
499  * @param value the 'struct Neighbour' to free
500  * @return GNUNET_OK (continue to iterate)
501  */
502 static int
503 free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value)
504 {
505   struct Neighbour *n = value;
506
507   /* transport should have 'disconnected' all neighbours... */
508   GNUNET_break (0);
509   free_neighbour (n);
510   return GNUNET_OK;
511 }
512
513
514 /**
515  * Shutdown neighbours subsystem.
516  */
517 void
518 GSC_NEIGHBOURS_done ()
519 {
520   if (NULL == transport)
521     return;
522   GNUNET_TRANSPORT_disconnect (transport);
523   transport = NULL;
524   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
525                                          NULL);
526   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
527   neighbours = NULL;
528 }
529
530 /* end of gnunet-service-core_neighbours.c */