add statistics for packets dropped by cadet due to full buffer
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_core.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2017 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 cadet/gnunet-service-cadet_core.c
23  * @brief cadet service; interaction with CORE service
24  * @author Bartlomiej Polot
25  * @author Christian Grothoff
26  *
27  * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
28  *
29  * TODO:
30  * - Optimization: given BROKEN messages, destroy paths (?)
31  */
32 #include "platform.h"
33 #include "gnunet-service-cadet-new_core.h"
34 #include "gnunet-service-cadet-new_paths.h"
35 #include "gnunet-service-cadet-new_peer.h"
36 #include "gnunet-service-cadet-new_connection.h"
37 #include "gnunet-service-cadet-new_tunnels.h"
38 #include "gnunet_core_service.h"
39 #include "cadet_protocol.h"
40
41
42 #define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
43
44
45 /**
46  * Number of messages we are willing to buffer per route.
47  */
48 #define ROUTE_BUFFER_SIZE 8
49
50
51 /**
52  * Information we keep per direction for a route.
53  */
54 struct RouteDirection
55 {
56   /**
57    * Target peer.
58    */
59   struct CadetPeer *hop;
60
61   /**
62    * Route this direction is part of.
63    */
64   struct CadetRoute *my_route;
65
66   /**
67    * Message queue manager for @e hop.
68    */
69   struct GCP_MessageQueueManager *mqm;
70
71   /**
72    * Cyclic message buffer to @e hop.
73    */
74   struct GNUNET_MQ_Envelope *out_buffer[ROUTE_BUFFER_SIZE];
75
76   /**
77    * Next write offset to use to append messages to @e out_buffer.
78    */
79   unsigned int out_wpos;
80
81   /**
82    * Next read offset to use to retrieve messages from @e out_buffer.
83    */
84   unsigned int out_rpos;
85
86   /**
87    * Is @e mqm currently ready for transmission?
88    */
89   int is_ready;
90
91 };
92
93
94 /**
95  * Description of a segment of a `struct CadetConnection` at the
96  * intermediate peers.  Routes are basically entries in a peer's
97  * routing table for forwarding traffic.  At both endpoints, the
98  * routes are terminated by a `struct CadetConnection`, which knows
99  * the complete `struct CadetPath` that is formed by the individual
100  * routes.
101  */
102 struct CadetRoute
103 {
104
105   /**
106    * Information about the next hop on this route.
107    */
108   struct RouteDirection next;
109
110   /**
111    * Information about the previous hop on this route.
112    */
113   struct RouteDirection prev;
114
115   /**
116    * Unique identifier for the connection that uses this route.
117    */
118   struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
119
120   /**
121    * When was this route last in use?
122    */
123   struct GNUNET_TIME_Absolute last_use;
124
125 };
126
127
128 /**
129  * Handle to the CORE service.
130  */
131 static struct GNUNET_CORE_Handle *core;
132
133 /**
134  * Routes on which this peer is an intermediate.
135  */
136 static struct GNUNET_CONTAINER_MultiShortmap *routes;
137
138
139 /**
140  * Get the route corresponding to a hash.
141  *
142  * @param cid hash generated from the connection identifier
143  */
144 static struct CadetRoute *
145 get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
146 {
147   return GNUNET_CONTAINER_multishortmap_get (routes,
148                                              &cid->connection_of_tunnel);
149 }
150
151
152 /**
153  * We message @a msg from @a prev.  Find its route by @a cid and
154  * forward to the next hop.  Drop and signal broken route if we do not
155  * have a route.
156  *
157  * @param prev previous hop (sender)
158  * @param cid connection identifier, tells us which route to use
159  * @param msg the message to forward
160  */
161 static void
162 route_message (struct CadetPeer *prev,
163                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
164                const struct GNUNET_MessageHeader *msg)
165 {
166   struct CadetRoute *route;
167   struct RouteDirection *dir;
168   struct GNUNET_MQ_Envelope *env;
169
170   route = get_route (cid);
171   if (NULL == route)
172   {
173     struct GNUNET_MQ_Envelope *env;
174     struct GNUNET_CADET_ConnectionBrokenMessage *bm;
175
176     LOG (GNUNET_ERROR_TYPE_DEBUG,
177          "Failed to route message of type %u from %s on connection %s: no route\n",
178          ntohs (msg->type),
179          GCP_2s (prev),
180          GNUNET_sh2s (&cid->connection_of_tunnel));
181     env = GNUNET_MQ_msg (bm,
182                          GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
183     bm->cid = *cid;
184     bm->peer1 = my_full_id;
185     GCP_send_ooo (prev,
186                   env);
187     return;
188   }
189   dir = (prev == route->prev.hop) ? &route->next : &route->prev;
190   if (GNUNET_YES == dir->is_ready)
191   {
192     LOG (GNUNET_ERROR_TYPE_DEBUG,
193          "Routing message of type %u from %s to %s on connection %s\n",
194          ntohs (msg->type),
195          GCP_2s (prev),
196          GNUNET_i2s (GCP_get_id (dir->hop)),
197          GNUNET_sh2s (&cid->connection_of_tunnel));
198     dir->is_ready = GNUNET_NO;
199     GCP_send (dir->mqm,
200               GNUNET_MQ_msg_copy (msg));
201     return;
202   }
203   env = dir->out_buffer[dir->out_wpos];
204   if (NULL != env)
205   {
206     /* Queue full, drop earliest message in queue */
207     LOG (GNUNET_ERROR_TYPE_DEBUG,
208          "Queue full due to new message of type %u from %s to %s on connection %s, dropping old message\n",
209          ntohs (msg->type),
210          GCP_2s (prev),
211          GNUNET_i2s (GCP_get_id (dir->hop)),
212          GNUNET_sh2s (&cid->connection_of_tunnel));
213     GNUNET_STATISTICS_update (stats,
214                               "# messages dropped due to full buffer",
215                               1,
216                               GNUNET_NO);
217   GNUNET_assert (dir->out_rpos == dir->out_wpos);
218     GNUNET_MQ_discard (env);
219     dir->out_rpos++;
220     if (ROUTE_BUFFER_SIZE == dir->out_rpos)
221       dir->out_rpos = 0;
222   }
223   LOG (GNUNET_ERROR_TYPE_DEBUG,
224        "Queueing new message of type %u from %s to %s on connection %s\n",
225        ntohs (msg->type),
226        GCP_2s (prev),
227        GNUNET_i2s (GCP_get_id (dir->hop)),
228        GNUNET_sh2s (&cid->connection_of_tunnel));
229   env = GNUNET_MQ_msg_copy (msg);
230   dir->out_buffer[dir->out_wpos] = env;
231   dir->out_wpos++;
232   if (ROUTE_BUFFER_SIZE == dir->out_wpos)
233     dir->out_wpos = 0;
234 }
235
236
237 /**
238  * Check if the create_connection message has the appropriate size.
239  *
240  * @param cls Closure (unused).
241  * @param msg Message to check.
242  *
243  * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
244  */
245 static int
246 check_connection_create (void *cls,
247                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
248 {
249   uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
250
251   if (0 != (size % sizeof (struct GNUNET_PeerIdentity)))
252   {
253     GNUNET_break_op (0);
254     return GNUNET_NO;
255   }
256   return GNUNET_YES;
257 }
258
259
260 /**
261  * Free internal data of a route direction.
262  *
263  * @param dir direction to destroy (do NOT free memory of 'dir' itself)
264  */
265 static void
266 destroy_direction (struct RouteDirection *dir)
267 {
268   for (unsigned int i=0;i<ROUTE_BUFFER_SIZE;i++)
269     if (NULL != dir->out_buffer[i])
270     {
271       GNUNET_MQ_discard (dir->out_buffer[i]);
272       dir->out_buffer[i] = NULL;
273     }
274   if (NULL != dir->mqm)
275   {
276     GCP_request_mq_cancel (dir->mqm,
277                            NULL);
278     dir->mqm = NULL;
279   }
280 }
281
282
283 /**
284  * Destroy our state for @a route.
285  *
286  * @param route route to destroy
287  */
288 static void
289 destroy_route (struct CadetRoute *route)
290 {
291   LOG (GNUNET_ERROR_TYPE_DEBUG,
292        "Destroying route from %s to %s of connection %s\n",
293        GNUNET_i2s  (GCP_get_id (route->prev.hop)),
294        GNUNET_i2s2 (GCP_get_id (route->next.hop)),
295        GNUNET_sh2s (&route->cid.connection_of_tunnel));
296   destroy_direction (&route->prev);
297   destroy_direction (&route->next);
298   GNUNET_free (route);
299 }
300
301
302 /**
303  * Send message that a route is broken between @a peer1 and @a peer2.
304  *
305  * @param target where to send the message
306  * @param cid connection identifier to use
307  * @param peer1 one of the peers where a link is broken
308  * @param peer2 another one of the peers where a link is broken
309  */
310 static void
311 send_broken (struct RouteDirection *target,
312              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
313              const struct GNUNET_PeerIdentity *peer1,
314              const struct GNUNET_PeerIdentity *peer2)
315 {
316   struct GNUNET_MQ_Envelope *env;
317   struct GNUNET_CADET_ConnectionBrokenMessage *bm;
318
319   if (NULL == target->mqm)
320     return; /* Can't send notification, connection is down! */
321   LOG (GNUNET_ERROR_TYPE_DEBUG,
322        "Notifying %s about BROKEN route at %s-%s of connection %s\n",
323        GCP_2s (target->hop),
324        GNUNET_i2s (peer1),
325        GNUNET_i2s2 (peer2),
326        GNUNET_sh2s (&cid->connection_of_tunnel));
327
328   env = GNUNET_MQ_msg (bm,
329                        GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
330   bm->cid = *cid;
331   if (NULL != peer1)
332     bm->peer1 = *peer1;
333   if (NULL != peer2)
334     bm->peer2 = *peer2;
335
336   GCP_request_mq_cancel (target->mqm,
337                          env);
338   target->mqm = NULL;
339 }
340
341
342 /**
343  * Function called when the message queue to the previous hop
344  * becomes available/unavailable.  We expect this function to
345  * be called immediately when we register, and then again
346  * later if the connection ever goes down.
347  *
348  * @param cls the `struct RouteDirection`
349  * @param available #GNUNET_YES if sending is now possible,
350  *                  #GNUNET_NO if sending is no longer possible
351  *                  #GNUNET_SYSERR if sending is no longer possible
352  *                                 and the last envelope was discarded
353  */
354 static void
355 dir_ready_cb (void *cls,
356               int ready)
357 {
358   struct RouteDirection *dir = cls;
359   struct CadetRoute *route = dir->my_route;
360   struct RouteDirection *odir;
361
362   if (GNUNET_YES == ready)
363   {
364     struct GNUNET_MQ_Envelope *env;
365
366     dir->is_ready = GNUNET_YES;
367     if (NULL != (env = dir->out_buffer[dir->out_rpos]))
368     {
369       dir->out_buffer[dir->out_rpos] = NULL;
370       dir->out_rpos++;
371       if (ROUTE_BUFFER_SIZE == dir->out_rpos)
372         dir->out_rpos = 0;
373       dir->is_ready = GNUNET_NO;
374       GCP_send (dir->mqm,
375                 env);
376     }
377     return;
378   }
379   odir = (dir == &route->next) ? &route->prev : &route->next;
380   send_broken (&route->next,
381                &route->cid,
382                GCP_get_id (odir->hop),
383                &my_full_id);
384   destroy_route (route);
385 }
386
387
388 /**
389  * Initialize one of the directions of a route.
390  *
391  * @param route route the direction belongs to
392  * @param dir direction to initialize
393  * @param hop next hop on in the @a dir
394  */
395 static void
396 dir_init (struct RouteDirection *dir,
397           struct CadetRoute *route,
398           struct CadetPeer *hop)
399 {
400   dir->hop = hop;
401   dir->my_route = route;
402   dir->mqm = GCP_request_mq (hop,
403                              &dir_ready_cb,
404                              dir);
405   GNUNET_assert (GNUNET_YES == dir->is_ready);
406 }
407
408
409 /**
410  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
411  *
412  * @param cls Closure (CadetPeer for neighbor that sent the message).
413  * @param msg Message itself.
414  */
415 static void
416 handle_connection_create (void *cls,
417                           const struct GNUNET_CADET_ConnectionCreateMessage *msg)
418 {
419   struct CadetPeer *sender = cls;
420   struct CadetPeer *next;
421   const struct GNUNET_PeerIdentity *pids = (const struct GNUNET_PeerIdentity *) &msg[1];
422   struct CadetRoute *route;
423   uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
424   unsigned int path_length;
425   unsigned int off;
426
427   path_length = size / sizeof (struct GNUNET_PeerIdentity);
428   /* Initiator is at offset 0. */
429   for (off=1;off<path_length;off++)
430     if (0 == memcmp (&my_full_id,
431                      &pids[off],
432                      sizeof (struct GNUNET_PeerIdentity)))
433       break;
434   if (off == path_length)
435   {
436     /* We are not on the path, bogus request */
437     GNUNET_break_op (0);
438     return;
439   }
440   /* Check previous hop */
441   if (sender != GCP_get (&pids[off - 1],
442                          GNUNET_NO))
443   {
444     /* sender is not on the path, not allowed */
445     GNUNET_break_op (0);
446     return;
447   }
448   if (NULL !=
449       get_route (&msg->cid))
450   {
451     /* Duplicate CREATE, pass it on, previous one might have been lost! */
452     LOG (GNUNET_ERROR_TYPE_DEBUG,
453          "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n",
454          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
455     route_message (sender,
456                    &msg->cid,
457                    &msg->header);
458     return;
459   }
460   if (off == path_length - 1)
461   {
462     /* We are the destination, create connection */
463     struct CadetConnection *cc;
464     struct CadetPeerPath *path;
465     struct CadetPeer *origin;
466
467     cc = GNUNET_CONTAINER_multishortmap_get (connections,
468                                              &msg->cid.connection_of_tunnel);
469     if (NULL != cc)
470     {
471       LOG (GNUNET_ERROR_TYPE_DEBUG,
472            "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n",
473            GNUNET_sh2s (&msg->cid.connection_of_tunnel));
474       GCC_handle_duplicate_create (cc);
475       return;
476     }
477
478     origin = GCP_get (&pids[0],
479                       GNUNET_YES);
480     LOG (GNUNET_ERROR_TYPE_DEBUG,
481          "Received CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n",
482          GCP_2s (origin),
483          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
484     path = GCPP_get_path_from_route (path_length - 1,
485                                      pids);
486     if (GNUNET_OK !=
487         GCT_add_inbound_connection (GCP_get_tunnel (origin,
488                                                     GNUNET_YES),
489                                     &msg->cid,
490                                     path))
491     {
492       /* Send back BROKEN: duplicate connection on the same path,
493          we will use the other one. */
494       struct GNUNET_MQ_Envelope *env;
495       struct GNUNET_CADET_ConnectionBrokenMessage *bm;
496
497       LOG (GNUNET_ERROR_TYPE_DEBUG,
498            "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
499            GCP_2s (sender),
500            GNUNET_sh2s (&msg->cid.connection_of_tunnel),
501            GCPP_2s (path));
502       env = GNUNET_MQ_msg (bm,
503                            GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
504       bm->cid = msg->cid;
505       bm->peer1 = my_full_id;
506       GCP_send_ooo (sender,
507                     env);
508       return;
509     }
510     return;
511   }
512   /* We are merely a hop on the way, check if we can support the route */
513   next = GCP_get (&pids[off + 1],
514                   GNUNET_NO);
515   if ( (NULL == next) ||
516        (GNUNET_NO == GCP_has_core_connection (next)) )
517   {
518     /* unworkable, send back BROKEN notification */
519     struct GNUNET_MQ_Envelope *env;
520     struct GNUNET_CADET_ConnectionBrokenMessage *bm;
521
522     LOG (GNUNET_ERROR_TYPE_DEBUG,
523          "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
524          GCP_2s (sender),
525          GNUNET_sh2s (&msg->cid.connection_of_tunnel),
526          GNUNET_i2s (&pids[off + 1]),
527          off + 1);
528     env = GNUNET_MQ_msg (bm,
529                          GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
530     bm->cid = msg->cid;
531     bm->peer1 = pids[off + 1];
532     bm->peer2 = my_full_id;
533     GCP_send_ooo (sender,
534                   env);
535     return;
536   }
537
538   /* Workable route, create routing entry */
539   LOG (GNUNET_ERROR_TYPE_DEBUG,
540        "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n",
541        GCP_2s (sender),
542        GNUNET_sh2s (&msg->cid.connection_of_tunnel),
543        GNUNET_i2s (&pids[off + 1]),
544        off + 1);
545   route = GNUNET_new (struct CadetRoute);
546   route->cid = msg->cid;
547   dir_init (&route->prev,
548             route,
549             sender);
550   dir_init (&route->next,
551             route,
552             next);
553   GNUNET_assert (GNUNET_OK ==
554                  GNUNET_CONTAINER_multishortmap_put (routes,
555                                                      &route->cid.connection_of_tunnel,
556                                                      route,
557                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
558 }
559
560
561 /**
562  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
563  *
564  * @param cls Closure (CadetPeer for neighbor that sent the message).
565  * @param msg Message itself.
566  */
567 static void
568 handle_connection_create_ack (void *cls,
569                               const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
570 {
571   struct CadetPeer *peer = cls;
572   struct CadetConnection *cc;
573
574   /* First, check if ACK belongs to a connection that ends here. */
575   cc = GNUNET_CONTAINER_multishortmap_get (connections,
576                                            &msg->cid.connection_of_tunnel);
577   if (NULL != cc)
578   {
579     /* verify ACK came from the right direction */
580     struct CadetPeerPath *path = GCC_get_path (cc);
581
582     if (peer !=
583         GCPP_get_peer_at_offset (path,
584                                  0))
585     {
586       /* received ACK from unexpected direction, ignore! */
587       GNUNET_break_op (0);
588       return;
589     }
590     LOG (GNUNET_ERROR_TYPE_DEBUG,
591          "Received CONNECTION_CREATE_ACK for connection %s.\n",
592          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
593     GCC_handle_connection_create_ack (cc);
594     return;
595   }
596
597   /* We're just an intermediary peer, route the message along its path */
598   route_message (peer,
599                  &msg->cid,
600                  &msg->header);
601 }
602
603
604 /**
605  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
606  *
607  * @param cls Closure (CadetPeer for neighbor that sent the message).
608  * @param msg Message itself.
609  * @deprecated duplicate logic with #handle_destroy(); dedup!
610  */
611 static void
612 handle_connection_broken (void *cls,
613                           const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
614 {
615   struct CadetPeer *peer = cls;
616   struct CadetConnection *cc;
617   struct CadetRoute *route;
618
619   /* First, check if message belongs to a connection that ends here. */
620   cc = GNUNET_CONTAINER_multishortmap_get (connections,
621                                            &msg->cid.connection_of_tunnel);
622   if (NULL != cc)
623   {
624     /* verify message came from the right direction */
625     struct CadetPeerPath *path = GCC_get_path (cc);
626
627     if (peer !=
628         GCPP_get_peer_at_offset (path,
629                                  0))
630     {
631       /* received message from unexpected direction, ignore! */
632       GNUNET_break_op (0);
633       return;
634     }
635     LOG (GNUNET_ERROR_TYPE_DEBUG,
636          "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
637          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
638     GCC_destroy_without_core (cc);
639
640     /* FIXME: also destroy the path up to the specified link! */
641     return;
642   }
643
644   /* We're just an intermediary peer, route the message along its path */
645   route = get_route (&msg->cid);
646   route_message (peer,
647                  &msg->cid,
648                  &msg->header);
649   destroy_route (route);
650   /* FIXME: also destroy paths we MAY have up to the specified link! */
651 }
652
653
654 /**
655  * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
656  *
657  * @param cls Closure (CadetPeer for neighbor that sent the message).
658  * @param msg Message itself.
659  */
660 static void
661 handle_connection_destroy (void *cls,
662                            const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
663 {
664   struct CadetPeer *peer = cls;
665   struct CadetConnection *cc;
666   struct CadetRoute *route;
667
668   /* First, check if message belongs to a connection that ends here. */
669   cc = GNUNET_CONTAINER_multishortmap_get (connections,
670                                            &msg->cid.connection_of_tunnel);
671   if (NULL != cc)
672   {
673     /* verify message came from the right direction */
674     struct CadetPeerPath *path = GCC_get_path (cc);
675
676     if (peer !=
677         GCPP_get_peer_at_offset (path,
678                                  0))
679     {
680       /* received message from unexpected direction, ignore! */
681       GNUNET_break_op (0);
682       return;
683     }
684     LOG (GNUNET_ERROR_TYPE_DEBUG,
685          "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
686          GNUNET_sh2s (&msg->cid.connection_of_tunnel));
687
688     GCC_destroy_without_core (cc);
689     return;
690   }
691
692   /* We're just an intermediary peer, route the message along its path */
693   LOG (GNUNET_ERROR_TYPE_DEBUG,
694        "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
695        GNUNET_sh2s (&msg->cid.connection_of_tunnel));
696   route = get_route (&msg->cid);
697   route_message (peer,
698                  &msg->cid,
699                  &msg->header);
700   destroy_route (route);
701 }
702
703
704 /**
705  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
706  *
707  * @param cls Closure (CadetPeer for neighbor that sent the message).
708  * @param msg Message itself.
709  */
710 static void
711 handle_tunnel_kx (void *cls,
712                   const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
713 {
714   struct CadetPeer *peer = cls;
715   struct CadetConnection *cc;
716
717   /* First, check if message belongs to a connection that ends here. */
718   cc = GNUNET_CONTAINER_multishortmap_get (connections,
719                                            &msg->cid.connection_of_tunnel);
720   if (NULL != cc)
721   {
722     /* verify message came from the right direction */
723     struct CadetPeerPath *path = GCC_get_path (cc);
724
725     if (peer !=
726         GCPP_get_peer_at_offset (path,
727                                  0))
728     {
729       /* received message from unexpected direction, ignore! */
730       GNUNET_break_op (0);
731       return;
732     }
733     GCC_handle_kx (cc,
734                    msg);
735     return;
736   }
737
738   /* We're just an intermediary peer, route the message along its path */
739   route_message (peer,
740                  &msg->cid,
741                  &msg->header);
742 }
743
744
745 /**
746  * Check if the encrypted message has the appropriate size.
747  *
748  * @param cls Closure (unused).
749  * @param msg Message to check.
750  *
751  * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
752  */
753 static int
754 check_tunnel_encrypted (void *cls,
755                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
756 {
757   return GNUNET_YES;
758 }
759
760
761 /**
762  * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
763  *
764  * @param cls Closure (CadetPeer for neighbor that sent the message).
765  * @param msg Message itself.
766  */
767 static void
768 handle_tunnel_encrypted (void *cls,
769                          const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
770 {
771   struct CadetPeer *peer = cls;
772   struct CadetConnection *cc;
773
774   /* First, check if message belongs to a connection that ends here. */
775   cc = GNUNET_CONTAINER_multishortmap_get (connections,
776                                            &msg->cid.connection_of_tunnel);
777   if (NULL != cc)
778   {
779     /* verify message came from the right direction */
780     struct CadetPeerPath *path = GCC_get_path (cc);
781
782     if (peer !=
783         GCPP_get_peer_at_offset (path,
784                                  0))
785     {
786       /* received message from unexpected direction, ignore! */
787       GNUNET_break_op (0);
788       return;
789     }
790     GCC_handle_encrypted (cc,
791                           msg);
792     return;
793   }
794   /* We're just an intermediary peer, route the message along its path */
795   route_message (peer,
796                  &msg->cid,
797                  &msg->header);
798 }
799
800
801 /**
802  * Function called after #GNUNET_CORE_connect has succeeded (or failed
803  * for good).  Note that the private key of the peer is intentionally
804  * not exposed here; if you need it, your process should try to read
805  * the private key file directly (which should work if you are
806  * authorized...).  Implementations of this function must not call
807  * #GNUNET_CORE_disconnect (other than by scheduling a new task to
808  * do this later).
809  *
810  * @param cls closure
811  * @param my_identity ID of this peer, NULL if we failed
812  */
813 static void
814 core_init_cb (void *cls,
815               const struct GNUNET_PeerIdentity *my_identity)
816 {
817   if (NULL == my_identity)
818   {
819     GNUNET_break (0);
820     return;
821   }
822   GNUNET_break (0 ==
823                 memcmp (my_identity,
824                         &my_full_id,
825                         sizeof (struct GNUNET_PeerIdentity)));
826 }
827
828
829 /**
830  * Method called whenever a given peer connects.
831  *
832  * @param cls closure
833  * @param peer peer identity this notification is about
834  */
835 static void *
836 core_connect_cb (void *cls,
837                  const struct GNUNET_PeerIdentity *peer,
838                  struct GNUNET_MQ_Handle *mq)
839 {
840   struct CadetPeer *cp;
841
842   LOG (GNUNET_ERROR_TYPE_DEBUG,
843        "CORE connection to peer %s was established.\n",
844        GNUNET_i2s (peer));
845   cp = GCP_get (peer,
846                 GNUNET_YES);
847   GCP_set_mq (cp,
848               mq);
849   return cp;
850 }
851
852
853 /**
854  * Method called whenever a peer disconnects.
855  *
856  * @param cls closure
857  * @param peer peer identity this notification is about
858  */
859 static void
860 core_disconnect_cb (void *cls,
861                     const struct GNUNET_PeerIdentity *peer,
862                     void *peer_cls)
863 {
864   struct CadetPeer *cp = peer_cls;
865
866   LOG (GNUNET_ERROR_TYPE_DEBUG,
867        "CORE connection to peer %s went down.\n",
868        GNUNET_i2s (peer));
869   GCP_set_mq (cp,
870               NULL);
871 }
872
873
874 /**
875  * Initialize the CORE subsystem.
876  *
877  * @param c Configuration.
878  */
879 void
880 GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
881 {
882   struct GNUNET_MQ_MessageHandler handlers[] = {
883     GNUNET_MQ_hd_var_size (connection_create,
884                            GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
885                            struct GNUNET_CADET_ConnectionCreateMessage,
886                            NULL),
887     GNUNET_MQ_hd_fixed_size (connection_create_ack,
888                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
889                              struct GNUNET_CADET_ConnectionCreateAckMessage,
890                              NULL),
891     GNUNET_MQ_hd_fixed_size (connection_broken,
892                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
893                              struct GNUNET_CADET_ConnectionBrokenMessage,
894                              NULL),
895     GNUNET_MQ_hd_fixed_size (connection_destroy,
896                              GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
897                              struct GNUNET_CADET_ConnectionDestroyMessage,
898                              NULL),
899     GNUNET_MQ_hd_fixed_size (tunnel_kx,
900                              GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
901                              struct GNUNET_CADET_TunnelKeyExchangeMessage,
902                              NULL),
903     GNUNET_MQ_hd_var_size (tunnel_encrypted,
904                            GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
905                            struct GNUNET_CADET_TunnelEncryptedMessage,
906                            NULL),
907     GNUNET_MQ_handler_end ()
908   };
909
910   routes = GNUNET_CONTAINER_multishortmap_create (1024,
911                                                   GNUNET_NO);
912   core = GNUNET_CORE_connect (c,
913                               NULL,
914                               &core_init_cb,
915                               &core_connect_cb,
916                               &core_disconnect_cb,
917                               handlers);
918 }
919
920
921 /**
922  * Shut down the CORE subsystem.
923  */
924 void
925 GCO_shutdown ()
926 {
927   if (NULL != core)
928   {
929     GNUNET_CORE_disconnect (core);
930     core = NULL;
931   }
932   GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
933   GNUNET_CONTAINER_multishortmap_destroy (routes);
934 }
935
936 /* end of gnunet-cadet-service_core.c */