better error message
[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   return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
133 }
134
135
136 /**
137  * Free the given entry for the neighbour.
138  *
139  * @param n neighbour to free
140  */
141 static void
142 free_neighbour (struct Neighbour *n)
143 {
144   struct NeighbourMessageEntry *m;
145
146 #if DEBUG_CORE
147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148               "Destroying neighbour entry for peer `%4s'\n",
149               GNUNET_i2s (&n->peer));
150 #endif
151   while (NULL != (m = n->message_head))
152   {
153     GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
154     GNUNET_free (m);
155   }
156   if (NULL != n->th)
157   {
158     GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
159     n->th = NULL;
160   }
161   GNUNET_STATISTICS_update (GSC_stats,
162                             gettext_noop
163                             ("# sessions terminated by transport disconnect"),
164                             1, GNUNET_NO);
165   GSC_SESSIONS_end (&n->peer);
166   if (NULL != n->kxinfo)
167   {
168     GSC_KX_stop (n->kxinfo);
169     n->kxinfo = NULL;
170   }
171   if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
172   {
173     GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
174     n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
175   }
176   GNUNET_assert (GNUNET_OK ==
177                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
178                                                        &n->peer.hashPubKey, n));
179   GNUNET_STATISTICS_set (GSC_stats,
180                          gettext_noop ("# neighbour entries allocated"),
181                          GNUNET_CONTAINER_multihashmap_size (neighbours),
182                          GNUNET_NO);
183   GNUNET_free (n);
184 }
185
186
187 /**
188  * Check if we have encrypted messages for the specified neighbour
189  * pending, and if so, check with the transport about sending them
190  * out.
191  *
192  * @param n neighbour to check.
193  */
194 static void
195 process_queue (struct Neighbour *n);
196
197
198 /**
199  * Function called when the transport service is ready to receive a
200  * message for the respective peer
201  *
202  * @param cls neighbour to use message from
203  * @param size number of bytes we can transmit
204  * @param buf where to copy the message
205  * @return number of bytes transmitted
206  */
207 static size_t
208 transmit_ready (void *cls, size_t size, void *buf)
209 {
210   struct Neighbour *n = cls;
211   struct NeighbourMessageEntry *m;
212   size_t ret;
213   char *cbuf;
214
215   n->th = NULL;
216   m = n->message_head;
217   if (m == NULL)
218   {
219     GNUNET_break (0);
220     return 0;
221   }
222   GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
223   if (buf == NULL)
224   {
225 #if DEBUG_CORE
226     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
227                 "Transmission of message of type %u and size %u failed\n",
228                 (unsigned int)
229                 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
230                 (unsigned int) m->size);
231 #endif
232     GNUNET_free (m);
233     process_queue (n);
234     return 0;
235   }
236   ret = 0;
237   cbuf = buf;
238   GNUNET_assert (size >= m->size);
239   memcpy (cbuf, &m[1], m->size);
240   ret = m->size;
241 #if DEBUG_CORE
242   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243               "Copied message of type %u and size %u into transport buffer for `%4s'\n",
244               (unsigned int)
245               ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
246               (unsigned int) ret, GNUNET_i2s (&n->peer));
247 #endif
248   GNUNET_free (m);
249   process_queue (n);
250   GNUNET_STATISTICS_update (GSC_stats,
251                             gettext_noop
252                             ("# encrypted bytes given to transport"), ret,
253                             GNUNET_NO);
254   return ret;
255 }
256
257
258 /**
259  * Check if we have messages for the specified neighbour pending, and
260  * if so, check with the transport about sending them out.
261  *
262  * @param n neighbour to check.
263  */
264 static void
265 process_queue (struct Neighbour *n)
266 {
267   struct NeighbourMessageEntry *m;
268
269   if (n->th != NULL)
270     return;                     /* request already pending */
271   m = n->message_head;
272   if (m == NULL)
273   {
274     /* notify sessions that the queue is empty and more messages
275      * could thus be queued now */
276     GSC_SESSIONS_solicit (&n->peer);
277     return;
278   }
279 #if DEBUG_CORE > 1
280   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281               "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
282               (unsigned int) m->size, GNUNET_i2s (&n->peer),
283               (unsigned long long)
284               GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
285 #endif
286   n->th =
287       GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size, 0,
288                                               GNUNET_TIME_absolute_get_remaining
289                                               (m->deadline), &transmit_ready,
290                                               n);
291   if (n->th != NULL)
292     return;
293   /* message request too large or duplicate request */
294   GNUNET_break (0);
295   /* discard encrypted message */
296   GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
297   GNUNET_free (m);
298   process_queue (n);
299 }
300
301
302
303 /**
304  * Function called by transport to notify us that
305  * a peer connected to us (on the network level).
306  *
307  * @param cls closure
308  * @param peer the peer that connected
309  * @param atsi performance data
310  * @param atsi_count number of entries in ats (excluding 0-termination)
311  */
312 static void
313 handle_transport_notify_connect (void *cls,
314                                  const struct GNUNET_PeerIdentity *peer,
315                                  const struct GNUNET_ATS_Information *atsi,
316                                  uint32_t atsi_count)
317 {
318   struct Neighbour *n;
319
320   if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
321   {
322     GNUNET_break (0);
323     return;
324   }
325   n = find_neighbour (peer);
326   if (n != NULL)
327   {
328     /* duplicate connect notification!? */
329     GNUNET_break (0);
330     return;
331   }
332 #if DEBUG_CORE
333   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%4s'.\n",
334               GNUNET_i2s (peer));
335 #endif
336   n = GNUNET_malloc (sizeof (struct Neighbour));
337   n->peer = *peer;
338   GNUNET_assert (GNUNET_OK ==
339                  GNUNET_CONTAINER_multihashmap_put (neighbours,
340                                                     &n->peer.hashPubKey, n,
341                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
342   GNUNET_STATISTICS_set (GSC_stats,
343                          gettext_noop ("# neighbour entries allocated"),
344                          GNUNET_CONTAINER_multihashmap_size (neighbours),
345                          GNUNET_NO);
346   n->kxinfo = GSC_KX_start (peer);
347 }
348
349
350 /**
351  * Function called by transport telling us that a peer
352  * disconnected.
353  *
354  * @param cls closure
355  * @param peer the peer that disconnected
356  */
357 static void
358 handle_transport_notify_disconnect (void *cls,
359                                     const struct GNUNET_PeerIdentity *peer)
360 {
361   struct Neighbour *n;
362
363 #if DEBUG_CORE
364   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365               "Peer `%4s' disconnected from us; received notification from transport.\n",
366               GNUNET_i2s (peer));
367 #endif
368   n = find_neighbour (peer);
369   if (n == NULL)
370   {
371     GNUNET_break (0);
372     return;
373   }
374   free_neighbour (n);
375 }
376
377
378 /**
379  * Function called by the transport for each received message.
380  *
381  * @param cls closure
382  * @param peer (claimed) identity of the other peer
383  * @param message the message
384  * @param atsi performance data
385  * @param atsi_count number of entries in ats (excluding 0-termination)
386  */
387 static void
388 handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
389                           const struct GNUNET_MessageHeader *message,
390                           const struct GNUNET_ATS_Information *atsi,
391                           uint32_t atsi_count)
392 {
393   struct Neighbour *n;
394   uint16_t type;
395
396 #if DEBUG_CORE > 1
397   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398               "Received message of type %u from `%4s', demultiplexing.\n",
399               (unsigned int) ntohs (message->type), GNUNET_i2s (peer));
400 #endif
401   if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
402   {
403     GNUNET_break (0);
404     return;
405   }
406   n = find_neighbour (peer);
407   if (n == NULL)
408   {
409     /* received message from peer that is not connected!? */
410     GNUNET_break (0);
411     return;
412   }
413   type = ntohs (message->type);
414   switch (type)
415   {
416   case GNUNET_MESSAGE_TYPE_CORE_SET_KEY:
417     GSC_KX_handle_set_key (n->kxinfo, message);
418     break;
419   case GNUNET_MESSAGE_TYPE_CORE_PING:
420     GSC_KX_handle_ping (n->kxinfo, message);
421     break;
422   case GNUNET_MESSAGE_TYPE_CORE_PONG:
423     GSC_KX_handle_pong (n->kxinfo, message);
424     break;
425   case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
426     GSC_KX_handle_encrypted_message (n->kxinfo, message, atsi, atsi_count);
427     break;
428   default:
429     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
430                 _("Unsupported message of type %u (%u bytes) received from peer `%s'\n"),
431                 (unsigned int) type,
432                 (unsigned int) ntohs (message->size),
433                 GNUNET_i2s (peer));
434     return;
435   }
436 }
437
438
439 /**
440  * Transmit the given message to the given target.
441  *
442  * @param target peer that should receive the message (must be connected)
443  * @param msg message to transmit
444  * @param timeout by when should the transmission be done?
445  */
446 void
447 GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target,
448                          const struct GNUNET_MessageHeader *msg,
449                          struct GNUNET_TIME_Relative timeout)
450 {
451   struct NeighbourMessageEntry *me;
452   struct Neighbour *n;
453   size_t msize;
454
455   n = find_neighbour (target);
456   if (NULL == n)
457   {
458     GNUNET_break (0);
459     return;
460   }
461   msize = ntohs (msg->size);
462   me = GNUNET_malloc (sizeof (struct NeighbourMessageEntry) + msize);
463   me->deadline = GNUNET_TIME_relative_to_absolute (timeout);
464   me->size = msize;
465   memcpy (&me[1], msg, msize);
466   GNUNET_CONTAINER_DLL_insert_tail (n->message_head, n->message_tail, me);
467   process_queue (n);
468 }
469
470
471 /**
472  * Initialize neighbours subsystem.
473  */
474 int
475 GSC_NEIGHBOURS_init ()
476 {
477   neighbours = GNUNET_CONTAINER_multihashmap_create (128);
478   transport =
479       GNUNET_TRANSPORT_connect (GSC_cfg, &GSC_my_identity, NULL,
480                                 &handle_transport_receive,
481                                 &handle_transport_notify_connect,
482                                 &handle_transport_notify_disconnect);
483   if (NULL == transport)
484   {
485     GNUNET_CONTAINER_multihashmap_destroy (neighbours);
486     neighbours = NULL;
487     return GNUNET_SYSERR;
488   }
489   return GNUNET_OK;
490 }
491
492
493 /**
494  * Wrapper around 'free_neighbour'.
495  *
496  * @param cls unused
497  * @param key peer identity
498  * @param value the 'struct Neighbour' to free
499  * @return GNUNET_OK (continue to iterate)
500  */
501 static int
502 free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value)
503 {
504   struct Neighbour *n = value;
505
506   /* transport should have 'disconnected' all neighbours... */
507   GNUNET_break (0);
508   free_neighbour (n);
509   return GNUNET_OK;
510 }
511
512
513 /**
514  * Shutdown neighbours subsystem.
515  */
516 void
517 GSC_NEIGHBOURS_done ()
518 {
519   if (NULL == transport)
520     return;
521   GNUNET_TRANSPORT_disconnect (transport);
522   transport = NULL;
523   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
524                                          NULL);
525   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
526   neighbours = NULL;
527 }
528
529 /* end of gnunet-service-core_neighbours.c */