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