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