first batch of license fixes (boring)
[oweals/gnunet.git] / src / dv / gnunet-service-dv.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file dv/gnunet-service-dv.c
18  * @brief the distance vector service, primarily handles gossip of nearby
19  * peers and sending/receiving DV messages from core and decapsulating
20  * them
21  *
22  * @author Christian Grothoff
23  * @author Nathan Evans
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_protocols.h"
28 #include "gnunet_core_service.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_peerinfo_service.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_set_service.h"
33 #include "gnunet_ats_service.h"
34 #include "dv.h"
35 #include <gcrypt.h>
36
37
38 /**
39  * How often do we establish the consensu?
40  */
41 #define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
42
43 /**
44  * Maximum number of messages we queue per peer.
45  */
46 #define MAX_QUEUE_SIZE 16
47
48 /**
49  * Maximum number of messages we queue towards the clients/plugin.
50  */
51 #define MAX_QUEUE_SIZE_PLUGIN 1024
52
53 /**
54  * The default fisheye depth, from how many hops away will
55  * we keep peers?
56  */
57 #define DEFAULT_FISHEYE_DEPTH 3
58
59 /**
60  * How many hops is a direct neighbor away?
61  */
62 #define DIRECT_NEIGHBOR_COST 1
63
64
65 GNUNET_NETWORK_STRUCT_BEGIN
66
67 /**
68  * Information about a peer DV can route to.  These entries are what
69  * we use as the binary format to establish consensus to create our
70  * routing table and as the address format in the HELLOs.
71  */
72 struct Target
73 {
74
75   /**
76    * Identity of the peer we can reach.
77    */
78   struct GNUNET_PeerIdentity peer;
79
80   /**
81    * How many hops (1-3) is this peer away? in network byte order
82    */
83   uint32_t distance GNUNET_PACKED;
84
85 };
86
87
88 /**
89  * Message exchanged between DV services (via core), requesting a
90  * message to be routed.
91  */
92 struct RouteMessage
93 {
94   /**
95    * Type: #GNUNET_MESSAGE_TYPE_DV_ROUTE
96    */
97   struct GNUNET_MessageHeader header;
98
99   /**
100    * Expected (remaining) distance.  Must be always smaller than
101    * #DEFAULT_FISHEYE_DEPTH, should be zero at the target.  Must
102    * be decremented by one at each hop.  Peers must not forward
103    * these messages further once the counter has reached zero.
104    */
105   uint32_t distance GNUNET_PACKED;
106
107   /**
108    * The (actual) target of the message (this peer, if distance is zero).
109    */
110   struct GNUNET_PeerIdentity target;
111
112   /**
113    * The (actual) sender of the message.
114    */
115   struct GNUNET_PeerIdentity sender;
116
117 };
118
119 GNUNET_NETWORK_STRUCT_END
120
121
122 /**
123  * Information about a direct neighbor (core-level, excluding
124  * DV-links, only DV-enabled peers).
125  */
126 struct DirectNeighbor
127 {
128
129   /**
130    * Identity of the peer.
131    */
132   struct GNUNET_PeerIdentity peer;
133
134   /**
135    * Session ID we use whenever we create a set union with
136    * this neighbor; constructed from the XOR of our peer
137    * IDs and then salted with "DV-SALT" to avoid conflicts
138    * with other applications.
139    */
140   struct GNUNET_HashCode real_session_id;
141
142   /**
143    * Transmit handle to core service.
144    */
145   struct GNUNET_MQ_Handle *mq;
146
147   /**
148    * Routing table of the neighbor, NULL if not yet established.
149    * Keys are peer identities, values are 'struct Target' entries.
150    * Note that the distances in the targets are from the point-of-view
151    * of the peer, not from us!
152    */
153   struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table;
154
155   /**
156    * Updated routing table of the neighbor, under construction,
157    * NULL if we are not currently building it.
158    * Keys are peer identities, values are 'struct Target' entries.
159    * Note that the distances in the targets are from the point-of-view
160    * of the other peer, not from us!
161    */
162   struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table_consensus;
163
164   /**
165    * Our current (exposed) routing table as a set.
166    */
167   struct GNUNET_SET_Handle *my_set;
168
169   /**
170    * Handle for our current active set union operation.
171    */
172   struct GNUNET_SET_OperationHandle *set_op;
173
174   /**
175    * Handle used if we are listening for this peer, waiting for the
176    * other peer to initiate construction of the set union.  NULL if
177    * we ar the initiating peer.
178    */
179   struct GNUNET_SET_ListenHandle *listen_handle;
180
181   /**
182    * ID of the task we use to (periodically) update our consensus
183    * with this peer.  Used if we are the initiating peer.
184    */
185   struct GNUNET_SCHEDULER_Task *initiate_task;
186
187   /**
188    * At what offset are we, with respect to inserting our own routes
189    * into the consensus?
190    */
191   unsigned int consensus_insertion_offset;
192
193   /**
194    * At what distance are we, with respect to inserting our own routes
195    * into the consensus?
196    */
197   unsigned int consensus_insertion_distance;
198
199   /**
200    * Elements in consensus
201    */
202   unsigned int consensus_elements;
203
204   /**
205    * Direct one hop route
206    */
207   struct Route *direct_route;
208
209   /**
210    * Flag set within 'check_target_removed' to trigger full global route refresh.
211    */
212   int target_removed;
213
214   /**
215    * Our distance to this peer, 0 for unknown.
216    */
217   uint32_t distance;
218
219   /**
220    * The network this peer is in
221    */
222   enum GNUNET_ATS_Network_Type network;
223
224   /**
225    * Is this neighbor connected at the core level?
226    */
227   int connected;
228
229 };
230
231
232 /**
233  * A route includes information about the next hop,
234  * the target, and the ultimate distance to the
235  * target.
236  */
237 struct Route
238 {
239
240   /**
241    * Which peer do we need to forward the message to?
242    */
243   struct DirectNeighbor *next_hop;
244
245   /**
246    * What would be the target, and how far is it away?
247    */
248   struct Target target;
249
250   /**
251    * Offset of this target in the respective consensus set.
252    */
253   unsigned int set_offset;
254
255 };
256
257
258 /**
259  * Set of targets we bring to a consensus; all targets in a set have a
260  * distance equal to the sets distance (which is implied by the array
261  * index of the set).
262  */
263 struct ConsensusSet
264 {
265
266   /**
267    * Array of targets in the set, may include NULL entries if a
268    * neighbor has disconnected; the targets are allocated with the
269    * respective container (all_routes), not here.
270    */
271   struct Route **targets;
272
273   /**
274    * Size of the @e targets array.
275    */
276   unsigned int array_length;
277
278 };
279
280
281 /**
282  * Peermap of all of our neighbors; processing these usually requires
283  * first checking to see if the peer is core-connected and if the
284  * distance is 1, in which case they are direct neighbors.
285  */
286 static struct GNUNET_CONTAINER_MultiPeerMap *direct_neighbors;
287
288 /**
289  * Hashmap with all routes that we currently support; contains
290  * routing information for all peers from distance 2
291  * up to distance #DEFAULT_FISHEYE_DEPTH.
292  */
293 static struct GNUNET_CONTAINER_MultiPeerMap *all_routes;
294
295 /**
296  * Array of consensus sets we expose to the outside world.  Sets
297  * are structured by the distance to the target.
298  */
299 static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH];
300
301 /**
302  * Handle to the core service api.
303  */
304 static struct GNUNET_CORE_Handle *core_api;
305
306 /**
307  * The identity of our peer.
308  */
309 static struct GNUNET_PeerIdentity my_identity;
310
311 /**
312  * The configuration for this service.
313  */
314 static const struct GNUNET_CONFIGURATION_Handle *cfg;
315
316 /**
317  * The client, the DV plugin connected to us (or an event monitor).
318  * Hopefully this client will never change, although if the plugin
319  * dies and returns for some reason it may happen.
320  */
321 static struct GNUNET_NotificationContext *nc;
322
323 /**
324  * Handle for the statistics service.
325  */
326 static struct GNUNET_STATISTICS_Handle *stats;
327
328 /**
329  * Handle to ATS service.
330  */
331 static struct GNUNET_ATS_PerformanceHandle *ats;
332
333 /**
334  * Task scheduled to refresh routes based on direct neighbours.
335  */
336 static struct GNUNET_SCHEDULER_Task *rr_task;
337
338 /**
339  * #GNUNET_YES if we are shutting down.
340  */
341 static int in_shutdown;
342
343 /**
344  * Start creating a new DV set union by initiating the connection.
345  *
346  * @param cls the 'struct DirectNeighbor' of the peer we're building
347  *        a routing consensus with
348  */
349 static void
350 initiate_set_union (void *cls);
351
352
353 /**
354  * Start creating a new DV set union construction, our neighbour has
355  * asked for it (callback for listening peer).
356  *
357  * @param cls the 'struct DirectNeighbor' of the peer we're building
358  *        a routing consensus with
359  * @param other_peer the other peer
360  * @param context_msg message with application specific information from
361  *        the other peer
362  * @param request request from the other peer, use GNUNET_SET_accept
363  *        to accept it, otherwise the request will be refused
364  *        Note that we don't use a return value here, as it is also
365  *        necessary to specify the set we want to do the operation with,
366  *        whith sometimes can be derived from the context message.
367  *        Also necessary to specify the timeout.
368  */
369 static void
370 listen_set_union (void *cls,
371                   const struct GNUNET_PeerIdentity *other_peer,
372                   const struct GNUNET_MessageHeader *context_msg,
373                   struct GNUNET_SET_Request *request);
374
375
376 /**
377  * Forward a message from another peer to the plugin.
378  *
379  * @param message the message to send to the plugin
380  * @param origin the original sender of the message
381  * @param distance distance to the original sender of the message
382  */
383 static void
384 send_data_to_plugin (const struct GNUNET_MessageHeader *message,
385                      const struct GNUNET_PeerIdentity *origin,
386                      uint32_t distance)
387 {
388   struct GNUNET_DV_ReceivedMessage *received_msg;
389   size_t size;
390
391   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
392               "Delivering message from peer `%s' at distance %u\n",
393               GNUNET_i2s (origin),
394               (unsigned int) distance);
395   size = sizeof (struct GNUNET_DV_ReceivedMessage) +
396     ntohs (message->size);
397   if (size >= GNUNET_MAX_MESSAGE_SIZE)
398   {
399     GNUNET_break (0); /* too big */
400     return;
401   }
402   received_msg = GNUNET_malloc (size);
403   received_msg->header.size = htons (size);
404   received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
405   received_msg->distance = htonl (distance);
406   received_msg->sender = *origin;
407   GNUNET_memcpy (&received_msg[1], message, ntohs (message->size));
408   GNUNET_notification_context_broadcast (nc,
409                                          &received_msg->header,
410                                          GNUNET_YES);
411   GNUNET_free (received_msg);
412 }
413
414
415 /**
416  * Forward a control message to the plugin.
417  *
418  * @param message the message to send to the plugin
419  */
420 static void
421 send_control_to_plugin (const struct GNUNET_MessageHeader *message)
422 {
423   GNUNET_notification_context_broadcast (nc,
424                                          message,
425                                          GNUNET_NO);
426 }
427
428
429 /**
430  * Send a DISTANCE_CHANGED message to the plugin.
431  *
432  * @param peer peer with a changed distance
433  * @param distance new distance to the peer
434  * @param network network used by the neighbor
435  */
436 static void
437 send_distance_change_to_plugin (const struct GNUNET_PeerIdentity *peer,
438                                 uint32_t distance,
439                                 enum GNUNET_ATS_Network_Type network)
440 {
441   struct GNUNET_DV_DistanceUpdateMessage du_msg;
442
443   GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network);
444   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445               "Delivering DISTANCE_CHANGED for message about peer `%s'\n",
446               GNUNET_i2s (peer));
447   du_msg.header.size = htons (sizeof (du_msg));
448   du_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED);
449   du_msg.distance = htonl (distance);
450   du_msg.peer = *peer;
451   du_msg.network = htonl ((uint32_t) network);
452   send_control_to_plugin (&du_msg.header);
453 }
454
455
456 /**
457  * Give a CONNECT message to the plugin.
458  *
459  * @param target peer that connected
460  * @param distance distance to the target
461  * @param network the network the next hop is located in
462  */
463 static void
464 send_connect_to_plugin (const struct GNUNET_PeerIdentity *target,
465                         uint32_t distance,
466                         enum GNUNET_ATS_Network_Type network)
467 {
468   struct GNUNET_DV_ConnectMessage cm;
469
470   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471               "Delivering CONNECT about peer %s with distance %u\n",
472               GNUNET_i2s (target), distance);
473   cm.header.size = htons (sizeof (cm));
474   cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT);
475   cm.distance = htonl (distance);
476   cm.network = htonl ((uint32_t) network);
477   cm.peer = *target;
478   send_control_to_plugin (&cm.header);
479 }
480
481
482 /**
483  * Give a DISCONNECT message to the plugin.
484  *
485  * @param target peer that disconnected
486  */
487 static void
488 send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target)
489 {
490   struct GNUNET_DV_DisconnectMessage dm;
491
492   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493               "Delivering DISCONNECT about peer `%s'\n",
494               GNUNET_i2s (target));
495   dm.header.size = htons (sizeof (dm));
496   dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
497   dm.reserved = htonl (0);
498   dm.peer = *target;
499   send_control_to_plugin (&dm.header);
500 }
501
502
503 /**
504  * Forward the given payload to the given target.
505  *
506  * @param target where to send the message
507  * @param distance distance to the @a sender
508  * @param sender original sender of the message
509  * @param actual_target ultimate recipient for the message
510  * @param payload payload of the message
511  */
512 static void
513 forward_payload (struct DirectNeighbor *target,
514                  uint32_t distance,
515                  const struct GNUNET_PeerIdentity *sender,
516                  const struct GNUNET_PeerIdentity *actual_target,
517                  const struct GNUNET_MessageHeader *payload)
518 {
519   struct GNUNET_MQ_Envelope *env;
520   struct RouteMessage *rm;
521
522   if ( (GNUNET_MQ_get_length (target->mq) >= MAX_QUEUE_SIZE) &&
523        (0 != memcmp (sender,
524                      &my_identity,
525                      sizeof (struct GNUNET_PeerIdentity))) )
526   {
527     /* not _our_ client and queue is full, drop */
528     GNUNET_STATISTICS_update (stats,
529                               "# messages dropped",
530                               1,
531                               GNUNET_NO);
532     return;
533   }
534   if (sizeof (struct RouteMessage) + ntohs (payload->size)
535       >= GNUNET_MAX_MESSAGE_SIZE)
536   {
537     GNUNET_break (0);
538     return;
539   }
540   env = GNUNET_MQ_msg_nested_mh (rm,
541                                  GNUNET_MESSAGE_TYPE_DV_ROUTE,
542                                  payload);
543   rm->distance = htonl (distance);
544   rm->target = *actual_target;
545   rm->sender = *sender;
546   GNUNET_MQ_send (target->mq,
547                   env);
548 }
549
550
551 /**
552  * Find a free slot for storing a 'route' in the 'consensi'
553  * set at the given distance.
554  *
555  * @param distance distance to use for the set slot
556  */
557 static unsigned int
558 get_consensus_slot (uint32_t distance)
559 {
560   struct ConsensusSet *cs;
561   unsigned int i;
562
563   GNUNET_assert (distance < DEFAULT_FISHEYE_DEPTH);
564   cs = &consensi[distance];
565   i = 0;
566   while ( (i < cs->array_length) &&
567           (NULL != cs->targets[i]) ) i++;
568   if (i == cs->array_length)
569   {
570     GNUNET_array_grow (cs->targets,
571                        cs->array_length,
572                        cs->array_length * 2 + 2);
573   }
574   return i;
575 }
576
577
578 /**
579  * Allocate a slot in the consensus set for a route.
580  *
581  * @param route route to initialize
582  * @param distance which consensus set to use
583  */
584 static void
585 allocate_route (struct Route *route,
586                 uint32_t distance)
587 {
588   unsigned int i;
589
590   if (distance >= DEFAULT_FISHEYE_DEPTH)
591   {
592     route->target.distance = htonl (distance);
593     route->set_offset = UINT_MAX; /* invalid slot */
594     return;
595   }
596   i = get_consensus_slot (distance);
597   route->set_offset = i;
598   consensi[distance].targets[i] = route;
599   route->target.distance = htonl (distance);
600 }
601
602
603 /**
604  * Release a slot in the consensus set for a route.
605  *
606  * @param route route to release the slot from
607  */
608 static void
609 release_route (struct Route *route)
610 {
611   if (UINT_MAX == route->set_offset)
612     return;
613   GNUNET_assert (ntohl (route->target.distance) < DEFAULT_FISHEYE_DEPTH);
614   consensi[ntohl (route->target.distance)].targets[route->set_offset] = NULL;
615   route->set_offset = UINT_MAX; /* indicate invalid slot */
616 }
617
618
619 /**
620  * Move a route from one consensus set to another.
621  *
622  * @param route route to move
623  * @param new_distance new distance for the route (destination set)
624  */
625 static void
626 move_route (struct Route *route,
627             uint32_t new_distance)
628 {
629   release_route (route);
630   allocate_route (route, new_distance);
631 }
632
633
634 /**
635  * Initialize this neighbors 'my_set' and when done give
636  * it to the pending set operation for execution.
637  *
638  * Add a single element to the set per call:
639  *
640  * If we reached the last element of a consensus element: increase distance
641  *
642  *
643  * @param cls the neighbor for which we are building the set
644  */
645 static void
646 build_set (void *cls)
647 {
648   struct DirectNeighbor *neighbor = cls;
649   struct GNUNET_SET_Element element;
650   struct Target *target;
651   struct Route *route;
652
653   target = NULL;
654   /* skip over NULL entries */
655   while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
656           (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) &&
657           (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
658     neighbor->consensus_insertion_offset++;
659   while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
660           (consensi[neighbor->consensus_insertion_distance].array_length == neighbor->consensus_insertion_offset) )
661   {
662     /* If we reached the last element of a consensus array element: increase distance and start with next array */
663     neighbor->consensus_insertion_offset = 0;
664     neighbor->consensus_insertion_distance++;
665     /* skip over NULL entries */
666     while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
667             (consensi[neighbor->consensus_insertion_distance].array_length  > neighbor->consensus_insertion_offset) &&
668             (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
669       neighbor->consensus_insertion_offset++;
670   }
671   if (DEFAULT_FISHEYE_DEPTH == neighbor->consensus_insertion_distance)
672   {
673     /* we have added all elements to the set, run the operation */
674     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675                 "Finished building my SET for peer `%s' with %u elements, committing\n",
676                 GNUNET_i2s (&neighbor->peer),
677                 neighbor->consensus_elements);
678     GNUNET_SET_commit (neighbor->set_op,
679                        neighbor->my_set);
680     GNUNET_SET_destroy (neighbor->my_set);
681     neighbor->my_set = NULL;
682     return;
683   }
684
685   route = consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset];
686   GNUNET_assert (NULL != route);
687   target = &route->target;
688   GNUNET_assert (ntohl (target->distance) < DEFAULT_FISHEYE_DEPTH);
689   element.size = sizeof (struct Target);
690   element.element_type = htons (0);
691   element.data = target;
692
693   /* Find next non-NULL entry */
694   neighbor->consensus_insertion_offset++;
695   if ( (0 != memcmp (&target->peer,
696                      &my_identity,
697                      sizeof (my_identity))) &&
698        (0 != memcmp (&target->peer,
699                      &neighbor->peer,
700                      sizeof (struct GNUNET_PeerIdentity))) )
701   {
702     /* Add target if it is not the neighbor or this peer */
703     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
704                 "Adding peer `%s' with distance %u to SET\n",
705                 GNUNET_i2s (&target->peer),
706                 ntohl (target->distance) + 1);
707     GNUNET_SET_add_element (neighbor->my_set,
708                             &element,
709                             &build_set, neighbor);
710     neighbor->consensus_elements++;
711   }
712   else
713     build_set (neighbor);
714 }
715
716
717 /**
718  * A peer is now connected to us at distance 1.  Initiate DV exchange.
719  *
720  * @param neighbor entry for the neighbor at distance 1
721  */
722 static void
723 handle_direct_connect (struct DirectNeighbor *neighbor)
724 {
725   struct Route *route;
726   struct GNUNET_HashCode h1;
727   struct GNUNET_HashCode h2;
728   struct GNUNET_HashCode session_id;
729
730   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
731               "Direct connection to %s established, routing table exchange begins.\n",
732               GNUNET_i2s (&neighbor->peer));
733   GNUNET_STATISTICS_update (stats,
734                             "# peers connected (1-hop)",
735                             1, GNUNET_NO);
736   route = GNUNET_CONTAINER_multipeermap_get (all_routes,
737                                              &neighbor->peer);
738   if (NULL != route)
739   {
740     GNUNET_assert (GNUNET_YES ==
741                    GNUNET_CONTAINER_multipeermap_remove (all_routes,
742                                                          &neighbor->peer,
743                                                          route));
744     send_disconnect_to_plugin (&neighbor->peer);
745     release_route (route);
746     GNUNET_free (route);
747   }
748
749   neighbor->direct_route = GNUNET_new (struct Route);
750   neighbor->direct_route->next_hop = neighbor;
751   neighbor->direct_route->target.peer = neighbor->peer;
752   allocate_route (neighbor->direct_route, DIRECT_NEIGHBOR_COST);
753
754   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
755               "Adding direct route to %s\n",
756               GNUNET_i2s (&neighbor->direct_route->target.peer));
757
758
759   /* construct session ID seed as XOR of both peer's identities */
760   GNUNET_CRYPTO_hash (&my_identity,
761                       sizeof (my_identity),
762                       &h1);
763   GNUNET_CRYPTO_hash (&neighbor->peer,
764                       sizeof (struct GNUNET_PeerIdentity),
765                       &h2);
766   GNUNET_CRYPTO_hash_xor (&h1,
767                           &h2,
768                           &session_id);
769   /* make sure session ID is unique across applications by salting it with 'DV' */
770   GNUNET_CRYPTO_hkdf (&neighbor->real_session_id, sizeof (struct GNUNET_HashCode),
771                       GCRY_MD_SHA512, GCRY_MD_SHA256,
772                       "DV-SALT", 2,
773                       &session_id, sizeof (session_id),
774                       NULL, 0);
775   if (0 < memcmp (&neighbor->peer,
776                   &my_identity,
777                   sizeof (struct GNUNET_PeerIdentity)))
778   {
779     if (NULL != neighbor->listen_handle)
780     {
781       GNUNET_break (0);
782     }
783     else
784       neighbor->initiate_task = GNUNET_SCHEDULER_add_now (&initiate_set_union,
785                                                           neighbor);
786   }
787   else
788   {
789     if (NULL != neighbor->listen_handle)
790     {
791       GNUNET_break (0);
792     }
793     else
794     {
795       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796                   "Starting SET listen operation with peer `%s'\n",
797                   GNUNET_i2s (&neighbor->peer));
798       neighbor->listen_handle = GNUNET_SET_listen (cfg,
799                                                    GNUNET_SET_OPERATION_UNION,
800                                                    &neighbor->real_session_id,
801                                                    &listen_set_union,
802                                                    neighbor);
803     }
804   }
805 }
806
807
808 /**
809  * Method called whenever a peer connects.
810  *
811  * @param cls closure
812  * @param peer peer identity this notification is about
813  * @param mq message queue for sending data to @a peer
814  * @return our `struct DirectNeighbour` for this peer
815  */
816 static void *
817 handle_core_connect (void *cls,
818                      const struct GNUNET_PeerIdentity *peer,
819                      struct GNUNET_MQ_Handle *mq)
820 {
821   struct DirectNeighbor *neighbor;
822
823   /* Check for connect to self message */
824   if (0 == memcmp (&my_identity,
825                    peer,
826                    sizeof (struct GNUNET_PeerIdentity)))
827     return NULL;
828   /* check if entry exists */
829   neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
830                                                 peer);
831   if (NULL != neighbor)
832   {
833     GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != neighbor->network);
834     GNUNET_break (GNUNET_YES != neighbor->connected);
835     neighbor->connected = GNUNET_YES;
836     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837                 "Core connected to %s (distance %u)\n",
838                 GNUNET_i2s (peer),
839                 (unsigned int) neighbor->distance);
840     if (DIRECT_NEIGHBOR_COST != neighbor->distance)
841       return NULL;
842     handle_direct_connect (neighbor);
843     return NULL;
844   }
845   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846               "Core connected to %s (distance unknown)\n",
847               GNUNET_i2s (peer));
848   neighbor = GNUNET_new (struct DirectNeighbor);
849   neighbor->peer = *peer;
850   GNUNET_assert (GNUNET_YES ==
851                  GNUNET_CONTAINER_multipeermap_put (direct_neighbors,
852                                                     &neighbor->peer,
853                                                     neighbor,
854                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
855   neighbor->connected = GNUNET_YES;
856   neighbor->distance = 0; /* unknown */
857   neighbor->network = GNUNET_ATS_NET_UNSPECIFIED;
858   return neighbor;
859 }
860
861
862 /**
863  * Called for each 'target' in a neighbor table to free the associated memory.
864  *
865  * @param cls NULL
866  * @param key key of the value
867  * @param value value to free
868  * @return #GNUNET_OK to continue to iterate
869  */
870 static int
871 free_targets (void *cls,
872               const struct GNUNET_PeerIdentity *key,
873               void *value)
874 {
875   GNUNET_free (value);
876   return GNUNET_OK;
877 }
878
879
880 /**
881  * Add a new route to the given @a target via the given @a neighbor.
882  *
883  * @param target the target of the route
884  * @param neighbor the next hop for communicating with the @a target
885  */
886 static void
887 add_new_route (struct Target *target,
888                struct DirectNeighbor *neighbor)
889 {
890   struct Route *route;
891
892   route = GNUNET_new (struct Route);
893   route->next_hop = neighbor;
894   route->target.peer = target->peer;
895   allocate_route (route, ntohl (target->distance) + 1);
896   GNUNET_assert (GNUNET_YES ==
897                  GNUNET_CONTAINER_multipeermap_put (all_routes,
898                                                     &route->target.peer,
899                                                     route,
900                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
901   send_connect_to_plugin (&route->target.peer,
902                           ntohl (route->target.distance),
903                           neighbor->network);
904 }
905
906
907 /**
908  * Multipeerhmap iterator for checking if a given route is
909  * (now) useful to this peer.
910  *
911  * @param cls the direct neighbor for the given route
912  * @param key key value stored under
913  * @param value a 'struct Target' that may or may not be useful; not that
914  *        the distance in 'target' does not include the first hop yet
915  * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
916  */
917 static int
918 check_possible_route (void *cls,
919                       const struct GNUNET_PeerIdentity *key,
920                       void *value)
921 {
922   struct DirectNeighbor *neighbor = cls;
923   struct Target *target = value;
924   struct Route *route;
925
926   if (GNUNET_YES ==
927       GNUNET_CONTAINER_multipeermap_contains (direct_neighbors,
928                                               key))
929     return GNUNET_YES; /* direct route, do not care about alternatives */
930   route = GNUNET_CONTAINER_multipeermap_get (all_routes,
931                                              key);
932   if (NULL != route)
933   {
934     /* we have an existing route, check how it compares with going via 'target' */
935     if (ntohl (route->target.distance) > ntohl (target->distance) + 1)
936     {
937       /* via 'target' is cheaper than the existing route; switch to alternative route! */
938       move_route (route, ntohl (target->distance) + 1);
939       route->next_hop = neighbor;
940       send_distance_change_to_plugin (&target->peer,
941                                       ntohl (target->distance) + 1,
942                                       neighbor->network);
943     }
944     return GNUNET_YES; /* got a route to this target already */
945   }
946   if (ntohl (target->distance) >= DEFAULT_FISHEYE_DEPTH)
947     return GNUNET_YES; /* distance is too large to be interesting */
948   add_new_route (target, neighbor);
949   return GNUNET_YES;
950 }
951
952
953 /**
954  * Multipeermap iterator for finding routes that were previously
955  * "hidden" due to a better route (called after a disconnect event).
956  *
957  * @param cls NULL
958  * @param key peer identity of the given direct neighbor
959  * @param value a `struct DirectNeighbor` to check for additional routes
960  * @return #GNUNET_YES to continue iteration
961  */
962 static int
963 refresh_routes (void *cls,
964                 const struct GNUNET_PeerIdentity *key,
965                 void *value)
966 {
967   struct DirectNeighbor *neighbor = value;
968
969   if ( (GNUNET_YES != neighbor->connected) ||
970        (DIRECT_NEIGHBOR_COST != neighbor->distance) )
971     return GNUNET_YES;
972   if (NULL != neighbor->neighbor_table)
973     GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
974                                            &check_possible_route,
975                                            neighbor);
976   return GNUNET_YES;
977 }
978
979
980 /**
981  * Task to run #refresh_routes() on all direct neighbours.
982  *
983  * @param cls NULL
984  */
985 static void
986 refresh_routes_task (void *cls)
987 {
988   rr_task = NULL;
989   GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors,
990                                          &refresh_routes,
991                                          NULL);
992 }
993
994
995 /**
996  * Asynchronously run #refresh_routes() at the next opportunity
997  * on all direct neighbours.
998  */
999 static void
1000 schedule_refresh_routes ()
1001 {
1002   if (NULL == rr_task)
1003     rr_task = GNUNET_SCHEDULER_add_now (&refresh_routes_task,
1004                                         NULL);
1005 }
1006
1007
1008 /**
1009  * Multipeermap iterator for freeing routes that go via a particular
1010  * neighbor that disconnected and is thus no longer available.
1011  *
1012  * @param cls the direct neighbor that is now unavailable
1013  * @param key key value stored under
1014  * @param value a `struct Route` that may or may not go via neighbor
1015  *
1016  * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1017  */
1018 static int
1019 cull_routes (void *cls,
1020              const struct GNUNET_PeerIdentity *key,
1021              void *value)
1022 {
1023   struct DirectNeighbor *neighbor = cls;
1024   struct Route *route = value;
1025
1026   if (route->next_hop != neighbor)
1027     return GNUNET_YES; /* not affected */
1028   GNUNET_assert (GNUNET_YES ==
1029                  GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value));
1030   release_route (route);
1031   send_disconnect_to_plugin (&route->target.peer);
1032   GNUNET_free (route);
1033   return GNUNET_YES;
1034 }
1035
1036
1037 /**
1038  * Handle the case that a direct connection to a peer is
1039  * disrupted.  Remove all routes via that peer and
1040  * stop the consensus with it.
1041  *
1042  * @param neighbor peer that was disconnected (or at least is no
1043  *    longer at distance 1)
1044  */
1045 static void
1046 handle_direct_disconnect (struct DirectNeighbor *neighbor)
1047 {
1048   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1049               "Culling routes via %s due to direct disconnect\n",
1050               GNUNET_i2s (&neighbor->peer));
1051   GNUNET_CONTAINER_multipeermap_iterate (all_routes,
1052                                          &cull_routes,
1053                                          neighbor);
1054   if (NULL != neighbor->direct_route)
1055   {
1056     release_route (neighbor->direct_route);
1057     GNUNET_free (neighbor->direct_route);
1058     neighbor->direct_route = NULL;
1059   }
1060   if (NULL != neighbor->neighbor_table_consensus)
1061   {
1062     GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1063                                            &free_targets,
1064                                            NULL);
1065     GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus);
1066     neighbor->neighbor_table_consensus = NULL;
1067   }
1068   if (NULL != neighbor->neighbor_table)
1069   {
1070     GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1071                                            &free_targets,
1072                                            NULL);
1073     GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table);
1074     neighbor->neighbor_table = NULL;
1075   }
1076   if (NULL != neighbor->set_op)
1077   {
1078     GNUNET_SET_operation_cancel (neighbor->set_op);
1079     neighbor->set_op = NULL;
1080   }
1081   if (NULL != neighbor->my_set)
1082   {
1083     GNUNET_SET_destroy (neighbor->my_set);
1084     neighbor->my_set = NULL;
1085   }
1086   if (NULL != neighbor->listen_handle)
1087   {
1088     GNUNET_SET_listen_cancel (neighbor->listen_handle);
1089     neighbor->listen_handle = NULL;
1090   }
1091   if (NULL != neighbor->initiate_task)
1092   {
1093     GNUNET_SCHEDULER_cancel (neighbor->initiate_task);
1094     neighbor->initiate_task = NULL;
1095   }
1096 }
1097
1098
1099 /**
1100  * Function that is called with QoS information about an address; used
1101  * to update our current distance to another peer.
1102  *
1103  * @param cls closure
1104  * @param address the address
1105  * @param active #GNUNET_YES if this address is actively used
1106  *        to maintain a connection to a peer;
1107  *        #GNUNET_NO if the address is not actively used;
1108  *        #GNUNET_SYSERR if this address is no longer available for ATS
1109  * @param bandwidth_out assigned outbound bandwidth for the connection
1110  * @param bandwidth_in assigned inbound bandwidth for the connection
1111  * @param prop performance data for the address (as far as known)
1112  */
1113 static void
1114 handle_ats_update (void *cls,
1115                    const struct GNUNET_HELLO_Address *address,
1116                    int active,
1117                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
1118                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1119                    const struct GNUNET_ATS_Properties *prop)
1120 {
1121   struct DirectNeighbor *neighbor;
1122   uint32_t distance;
1123   enum GNUNET_ATS_Network_Type network;
1124
1125   if (NULL == address)
1126   {
1127     /* ATS service temporarily disconnected */
1128     return;
1129   }
1130
1131   if (GNUNET_YES != active)
1132   {
1133     // FIXME: handle disconnect/inactive case too!
1134     return;
1135   }
1136   distance = prop->distance;
1137   network = prop->scope;
1138   GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network);
1139   /* check if entry exists */
1140   neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1141                                                 &address->peer);
1142   if (NULL != neighbor)
1143   {
1144     neighbor->network = network;
1145     if (neighbor->distance == distance)
1146       return; /* nothing new to see here, move along */
1147     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148                 "ATS says distance to %s is now %u\n",
1149                 GNUNET_i2s (&address->peer),
1150                 (unsigned int) distance);
1151     if ( (DIRECT_NEIGHBOR_COST == neighbor->distance) &&
1152          (DIRECT_NEIGHBOR_COST == distance) )
1153       return; /* no change */
1154     if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1155     {
1156       neighbor->distance = distance;
1157       GNUNET_STATISTICS_update (stats,
1158                                 "# peers connected (1-hop)",
1159                                 -1, GNUNET_NO);
1160       handle_direct_disconnect (neighbor);
1161       schedule_refresh_routes ();
1162       return;
1163     }
1164     neighbor->distance = distance;
1165     if (DIRECT_NEIGHBOR_COST != neighbor->distance)
1166       return;
1167     if (GNUNET_YES != neighbor->connected)
1168       return;
1169     handle_direct_connect (neighbor);
1170     return;
1171   }
1172   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1173               "ATS says distance to %s is now %u\n",
1174               GNUNET_i2s (&address->peer),
1175               (unsigned int) distance);
1176   neighbor = GNUNET_new (struct DirectNeighbor);
1177   neighbor->peer = address->peer;
1178   GNUNET_assert (GNUNET_YES ==
1179                  GNUNET_CONTAINER_multipeermap_put (direct_neighbors,
1180                                                     &neighbor->peer,
1181                                                     neighbor,
1182                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1183   neighbor->connected = GNUNET_NO; /* not yet */
1184   neighbor->distance = distance;
1185   neighbor->network = network;
1186 }
1187
1188
1189 /**
1190  * Check if a target was removed from the set of the other peer; if so,
1191  * if we also used it for our route, we need to remove it from our
1192  * 'all_routes' set (and later check if an alternative path now exists).
1193  *
1194  * @param cls the `struct DirectNeighbor`
1195  * @param key peer identity for the target
1196  * @param value a `struct Target` previously reachable via the given neighbor
1197  */
1198 static int
1199 check_target_removed (void *cls,
1200                       const struct GNUNET_PeerIdentity *key,
1201                       void *value)
1202 {
1203   struct DirectNeighbor *neighbor = cls;
1204   struct Target *new_target;
1205   struct Route *current_route;
1206
1207   new_target = GNUNET_CONTAINER_multipeermap_get (neighbor->neighbor_table_consensus,
1208                                                   key);
1209   current_route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1210                                                      key);
1211   if (NULL != new_target)
1212   {
1213     /* target was in old set, is in new set */
1214     if ( (NULL != current_route) &&
1215          (current_route->next_hop == neighbor) &&
1216          (current_route->target.distance != new_target->distance) )
1217     {
1218       /* need to recalculate routes due to distance change */
1219       neighbor->target_removed = GNUNET_YES;
1220     }
1221     return GNUNET_OK;
1222   }
1223   /* target was revoked, check if it was used */
1224   if ( (NULL == current_route) ||
1225        (current_route->next_hop != neighbor) )
1226   {
1227     /* didn't matter, wasn't used */
1228     return GNUNET_OK;
1229   }
1230   /* remove existing route */
1231   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1232               "Lost route to %s\n",
1233               GNUNET_i2s (&current_route->target.peer));
1234   GNUNET_assert (GNUNET_YES ==
1235                  GNUNET_CONTAINER_multipeermap_remove (all_routes, key, current_route));
1236   send_disconnect_to_plugin (&current_route->target.peer);
1237   release_route (current_route);
1238   GNUNET_free (current_route);
1239   neighbor->target_removed = GNUNET_YES;
1240   return GNUNET_OK;
1241 }
1242
1243
1244 /**
1245  * Check if a target was added to the set of the other peer; if it
1246  * was added or impoves the existing route, do the needed updates.
1247  *
1248  * @param cls the `struct DirectNeighbor`
1249  * @param key peer identity for the target
1250  * @param value a `struct Target` now reachable via the given neighbor
1251  */
1252 static int
1253 check_target_added (void *cls,
1254                     const struct GNUNET_PeerIdentity *key,
1255                     void *value)
1256 {
1257   struct DirectNeighbor *neighbor = cls;
1258   struct Target *target = value;
1259   struct Route *current_route;
1260
1261   /* target was revoked, check if it was used */
1262   current_route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1263                                                      key);
1264   if (NULL != current_route)
1265   {
1266     /* route exists */
1267     if (current_route->next_hop == neighbor)
1268     {
1269       /* we had the same route before, no change in target */
1270       if (ntohl (target->distance) + 1 != ntohl (current_route->target.distance))
1271       {
1272         /* but distance changed! */
1273         if (ntohl (target->distance) + 1 > DEFAULT_FISHEYE_DEPTH)
1274         {
1275           /* distance increased beyond what is allowed, kill route */
1276           GNUNET_assert (GNUNET_YES ==
1277                          GNUNET_CONTAINER_multipeermap_remove (all_routes,
1278                                                                key,
1279                                                                current_route));
1280           send_disconnect_to_plugin (key);
1281           release_route (current_route);
1282           GNUNET_free (current_route);
1283         }
1284         else
1285         {
1286           /* distance decreased, update route */
1287           move_route (current_route,
1288                       ntohl (target->distance) + 1);
1289           send_distance_change_to_plugin (&target->peer,
1290                                           ntohl (target->distance) + 1,
1291                                           neighbor->network);
1292         }
1293       }
1294       return GNUNET_OK;
1295     }
1296     if (ntohl (current_route->target.distance) <= ntohl (target->distance) + 1)
1297     {
1298       /* alternative, shorter route exists, ignore */
1299       return GNUNET_OK;
1300     }
1301     /* new route is better than the existing one, take over! */
1302     /* NOTE: minor security issue: malicious peers may advertise
1303        very short routes to take over longer paths; as we don't
1304        check that the shorter routes actually work, a malicious
1305        direct neighbor can use this to DoS our long routes */
1306
1307     move_route (current_route, ntohl (target->distance) + 1);
1308     current_route->next_hop = neighbor;
1309     send_distance_change_to_plugin (&target->peer,
1310                                     ntohl (target->distance) + 1,
1311                                     neighbor->network);
1312     return GNUNET_OK;
1313   }
1314   /* new route */
1315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1316               "Discovered new route to %s using %u hops\n",
1317               GNUNET_i2s (&target->peer),
1318               (unsigned int) (ntohl (target->distance) + 1));
1319   current_route = GNUNET_new (struct Route);
1320   current_route->next_hop = neighbor;
1321   current_route->target.peer = target->peer;
1322   allocate_route (current_route, ntohl (target->distance) + 1);
1323   GNUNET_assert (GNUNET_YES ==
1324                  GNUNET_CONTAINER_multipeermap_put (all_routes,
1325                                                     &current_route->target.peer,
1326                                                     current_route,
1327                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1328
1329   send_connect_to_plugin (&current_route->target.peer,
1330                           ntohl (current_route->target.distance),
1331                           neighbor->network);
1332   return GNUNET_OK;
1333 }
1334
1335
1336 /**
1337  * Callback for set operation results. Called for each element
1338  * in the result set.
1339  * We have learned a new route from the other peer.  Add it to the
1340  * route set we're building.
1341  *
1342  * @param cls the `struct DirectNeighbor` we're building the consensus with
1343  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1344  * @param current_size current set size
1345  * @param status see `enum GNUNET_SET_Status`
1346  */
1347 static void
1348 handle_set_union_result (void *cls,
1349                          const struct GNUNET_SET_Element *element,
1350                          uint64_t current_size,
1351                          enum GNUNET_SET_Status status)
1352 {
1353   struct DirectNeighbor *neighbor = cls;
1354   struct DirectNeighbor *dn;
1355   struct Target *target;
1356   const struct Target *ctarget;
1357   char *status_str;
1358
1359   switch (status)
1360   {
1361   case GNUNET_SET_STATUS_OK:
1362     status_str = "GNUNET_SET_STATUS_OK";
1363     break;
1364   case GNUNET_SET_STATUS_FAILURE:
1365     status_str = "GNUNET_SET_STATUS_FAILURE";
1366     break;
1367   case GNUNET_SET_STATUS_HALF_DONE:
1368     status_str = "GNUNET_SET_STATUS_HALF_DONE";
1369     break;
1370   case GNUNET_SET_STATUS_DONE:
1371     status_str = "GNUNET_SET_STATUS_DONE";
1372     break;
1373   default:
1374     status_str = "UNDEFINED";
1375     break;
1376   }
1377
1378   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1379               "Got SET union result: %s\n",
1380               status_str);
1381   switch (status)
1382   {
1383   case GNUNET_SET_STATUS_OK:
1384     if (sizeof (struct Target) != element->size)
1385     {
1386       GNUNET_break_op (0);
1387       return;
1388     }
1389     ctarget = element->data;
1390     if ( (NULL !=
1391           (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1392                                                    &ctarget->peer))) &&
1393          (DIRECT_NEIGHBOR_COST == dn->distance) )
1394     {
1395       /* this is a direct neighbor of ours, we do not care about routes
1396          to this peer */
1397       return;
1398     }
1399     target = GNUNET_new (struct Target);
1400     GNUNET_memcpy (target, element->data, sizeof (struct Target));
1401     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1402                 "Received information about peer `%s' with distance %u from SET\n",
1403                 GNUNET_i2s (&target->peer),
1404                 ntohl (target->distance) + 1);
1405
1406     if (NULL == neighbor->neighbor_table_consensus)
1407       neighbor->neighbor_table_consensus
1408         = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1409     if (GNUNET_YES !=
1410         GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table_consensus,
1411                                            &target->peer,
1412                                            target,
1413                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1414     {
1415       GNUNET_break_op (0);
1416       GNUNET_free (target);
1417     }
1418     break;
1419   case GNUNET_SET_STATUS_FAILURE:
1420     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1421                 "Failed to establish DV union, will try again later\n");
1422     neighbor->set_op = NULL;
1423     if (NULL != neighbor->neighbor_table_consensus)
1424     {
1425       GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1426                                              &free_targets,
1427                                              NULL);
1428       GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus);
1429       neighbor->neighbor_table_consensus = NULL;
1430     }
1431     if (0 < memcmp (&neighbor->peer,
1432                     &my_identity,
1433                     sizeof (struct GNUNET_PeerIdentity)))
1434       neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1435                                                               &initiate_set_union,
1436                                                               neighbor);
1437     break;
1438   case GNUNET_SET_STATUS_HALF_DONE:
1439     break;
1440   case GNUNET_SET_STATUS_DONE:
1441     /* we got all of our updates; integrate routing table! */
1442     neighbor->target_removed = GNUNET_NO;
1443     if (NULL == neighbor->neighbor_table_consensus)
1444       neighbor->neighbor_table_consensus = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1445     if (NULL != neighbor->neighbor_table)
1446       GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1447                                              &check_target_removed,
1448                                              neighbor);
1449     if (GNUNET_YES == neighbor->target_removed)
1450     {
1451       /* check if we got an alternative for the removed routes */
1452       schedule_refresh_routes ();
1453     }
1454     /* add targets that appeared (and check for improved routes) */
1455     GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1456                                            &check_target_added,
1457                                            neighbor);
1458     if (NULL != neighbor->neighbor_table)
1459     {
1460       GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1461                                              &free_targets,
1462                                              NULL);
1463       GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table);
1464       neighbor->neighbor_table = NULL;
1465     }
1466     neighbor->neighbor_table = neighbor->neighbor_table_consensus;
1467     neighbor->neighbor_table_consensus = NULL;
1468
1469     /* operation done, schedule next run! */
1470     neighbor->set_op = NULL;
1471     if (0 < memcmp (&neighbor->peer,
1472                     &my_identity,
1473                     sizeof (struct GNUNET_PeerIdentity)))
1474       neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1475                                                               &initiate_set_union,
1476                                                               neighbor);
1477     break;
1478   default:
1479     GNUNET_break (0);
1480     return;
1481   }
1482 }
1483
1484
1485 /**
1486  * Start creating a new DV set union construction, our neighbour has
1487  * asked for it (callback for listening peer).
1488  *
1489  * @param cls the 'struct DirectNeighbor' of the peer we're building
1490  *        a routing consensus with
1491  * @param other_peer the other peer
1492  * @param context_msg message with application specific information from
1493  *        the other peer
1494  * @param request request from the other peer, use GNUNET_SET_accept
1495  *        to accept it, otherwise the request will be refused
1496  *        Note that we don't use a return value here, as it is also
1497  *        necessary to specify the set we want to do the operation with,
1498  *        whith sometimes can be derived from the context message.
1499  *        Also necessary to specify the timeout.
1500  */
1501 static void
1502 listen_set_union (void *cls,
1503                   const struct GNUNET_PeerIdentity *other_peer,
1504                   const struct GNUNET_MessageHeader *context_msg,
1505                   struct GNUNET_SET_Request *request)
1506 {
1507   struct DirectNeighbor *neighbor = cls;
1508
1509   if (NULL == request)
1510     return; /* why??? */
1511   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512               "Starting to create consensus with %s\n",
1513               GNUNET_i2s (&neighbor->peer));
1514   if (NULL != neighbor->set_op)
1515   {
1516     GNUNET_SET_operation_cancel (neighbor->set_op);
1517     neighbor->set_op = NULL;
1518   }
1519   if (NULL != neighbor->my_set)
1520   {
1521     GNUNET_SET_destroy (neighbor->my_set);
1522     neighbor->my_set = NULL;
1523   }
1524   neighbor->my_set = GNUNET_SET_create (cfg,
1525                                         GNUNET_SET_OPERATION_UNION);
1526   neighbor->set_op = GNUNET_SET_accept (request,
1527                                         GNUNET_SET_RESULT_ADDED,
1528                                         (struct GNUNET_SET_Option[]) {{ 0 }},
1529                                         &handle_set_union_result,
1530                                         neighbor);
1531   neighbor->consensus_insertion_offset = 0;
1532   neighbor->consensus_insertion_distance = 0;
1533   neighbor->consensus_elements = 0;
1534   build_set (neighbor);
1535 }
1536
1537
1538 /**
1539  * Start creating a new DV set union by initiating the connection.
1540  *
1541  * @param cls the `struct DirectNeighbor *` of the peer we're building
1542  *        a routing consensus with
1543  */
1544 static void
1545 initiate_set_union (void *cls)
1546 {
1547   struct DirectNeighbor *neighbor = cls;
1548
1549   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1550               "Initiating SET union with peer `%s'\n",
1551               GNUNET_i2s (&neighbor->peer));
1552   neighbor->initiate_task = NULL;
1553   neighbor->my_set = GNUNET_SET_create (cfg,
1554                                         GNUNET_SET_OPERATION_UNION);
1555   neighbor->set_op = GNUNET_SET_prepare (&neighbor->peer,
1556                                          &neighbor->real_session_id,
1557                                          NULL,
1558                                          GNUNET_SET_RESULT_ADDED,
1559                                          (struct GNUNET_SET_Option[]) {{ 0 }},
1560                                          &handle_set_union_result,
1561                                          neighbor);
1562   neighbor->consensus_insertion_offset = 0;
1563   neighbor->consensus_insertion_distance = 0;
1564   neighbor->consensus_elements = 0;
1565   build_set (neighbor);
1566 }
1567
1568
1569 /**
1570  * Check that @a rm is well-formed.
1571  *
1572  * @param cls closure
1573  * @param rm the message
1574  * @return #GNUNET_OK if @a rm is well-formed.
1575  */
1576 static int
1577 check_dv_route_message (void *cls,
1578                         const struct RouteMessage *rm)
1579 {
1580   const struct GNUNET_MessageHeader *payload;
1581
1582   if (ntohs (rm->header.size) < sizeof (struct RouteMessage) + sizeof (struct GNUNET_MessageHeader))
1583   {
1584     GNUNET_break_op (0);
1585     return GNUNET_SYSERR;
1586   }
1587   payload = (const struct GNUNET_MessageHeader *) &rm[1];
1588   if (ntohs (rm->header.size) != sizeof (struct RouteMessage) + ntohs (payload->size))
1589   {
1590     GNUNET_break_op (0);
1591     return GNUNET_SYSERR;
1592   }
1593   return GNUNET_OK;
1594 }
1595
1596
1597 /**
1598  * Core handler for DV data messages.  Whatever this message
1599  * contains all we really have to do is rip it out of its
1600  * DV layering and give it to our pal the DV plugin to report
1601  * in with.
1602  *
1603  * @param cls closure
1604  * @param rm the message
1605  */
1606 static void
1607 handle_dv_route_message (void *cls,
1608                          const struct RouteMessage *rm)
1609 {
1610   struct DirectNeighbor *neighbor = cls;
1611   const struct GNUNET_MessageHeader *payload;
1612   struct Route *route;
1613   struct DirectNeighbor *nneighbor;
1614   struct DirectNeighbor *dn;
1615   struct Target *target;
1616   uint32_t distance;
1617   char me[5];
1618   char src[5];
1619   char prev[5];
1620   char dst[5];
1621
1622   distance = ntohl (rm->distance);
1623   payload = (const struct GNUNET_MessageHeader *) &rm[1];
1624   strncpy (prev, GNUNET_i2s (&neighbor->peer), 4);
1625   strncpy (me, GNUNET_i2s (&my_identity), 4);
1626   strncpy (src, GNUNET_i2s (&rm->sender), 4);
1627   strncpy (dst, GNUNET_i2s (&rm->target), 4);
1628   prev[4] = me[4] = src[4] = dst[4] = '\0';
1629   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1630               "Handling DV message with %u bytes payload of type %u from %s to %s routed by %s to me (%s @ hop %u)\n",
1631               (unsigned int) (ntohs (rm->header.size) - sizeof (struct RouteMessage)),
1632               ntohs (payload->type),
1633               src,
1634               dst,
1635               prev,
1636               me,
1637               (unsigned int) distance + 1);
1638
1639   if (0 == memcmp (&rm->target,
1640                    &my_identity,
1641                    sizeof (struct GNUNET_PeerIdentity)))
1642   {
1643     if ((NULL !=
1644          (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1645                                                   &rm->sender))) &&
1646         (DIRECT_NEIGHBOR_COST == dn->distance))
1647     {
1648       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1649                   "Discarding DV message, as %s is a direct neighbor\n",
1650                   GNUNET_i2s (&rm->sender));
1651       GNUNET_STATISTICS_update (stats,
1652                                 "# messages discarded (direct neighbor)",
1653                                 1, GNUNET_NO);
1654       return;
1655     }
1656     /* message is for me, check reverse route! */
1657     route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1658                                                &rm->sender);
1659     if ( (NULL == route) &&
1660          (distance < DEFAULT_FISHEYE_DEPTH) )
1661     {
1662       /* don't have reverse route yet, learn it! */
1663       target = GNUNET_new (struct Target);
1664       target->peer = rm->sender;
1665       target->distance = htonl (distance);
1666       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1667                   "Learning sender %s at distance %u from delivery!\n",
1668                   GNUNET_i2s (&rm->sender),
1669                   (unsigned int) distance + 1);
1670       if (NULL == neighbor->neighbor_table)
1671         neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1672       if (GNUNET_YES !=
1673           GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table,
1674                                              &target->peer,
1675                                              target,
1676                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1677       {
1678         GNUNET_break_op (0);
1679         GNUNET_free (target);
1680         return;
1681       }
1682       add_new_route (target, neighbor);
1683     }
1684     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1685                 "Delivering %u bytes from %s to myself!\n",
1686                 ntohs (payload->size),
1687                 GNUNET_i2s (&rm->sender));
1688     send_data_to_plugin (payload,
1689                          &rm->sender,
1690                          1 + distance);
1691     return;
1692   }
1693   if ( (NULL == GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1694                                                    &rm->sender)) &&
1695        (NULL == GNUNET_CONTAINER_multipeermap_get (all_routes,
1696                                                    &rm->sender)) )
1697   {
1698     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1699                 "Learning sender %s at distance %u from forwarding!\n",
1700                 GNUNET_i2s (&rm->sender),
1701                 1 + distance);
1702     target = GNUNET_new (struct Target);
1703     target->peer = rm->sender;
1704     target->distance = htonl (distance);
1705     if (NULL == neighbor->neighbor_table)
1706       neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1707     if (GNUNET_YES !=
1708         GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table,
1709                                            &target->peer,
1710                                            target,
1711                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1712     {
1713       GNUNET_break_op (0);
1714       GNUNET_free (target);
1715       return;
1716     }
1717     add_new_route (target, neighbor);
1718   }
1719
1720   route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1721                                              &rm->target);
1722   if (NULL == route)
1723   {
1724     nneighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1725                                                   &rm->target);
1726     if (NULL == nneighbor)
1727     {
1728       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1729                   "No route to %s, not routing %u bytes!\n",
1730                   GNUNET_i2s (&rm->target),
1731                   ntohs (payload->size));
1732       GNUNET_STATISTICS_update (stats,
1733                                 "# messages discarded (no route)",
1734                                 1, GNUNET_NO);
1735       return;
1736     }
1737   }
1738   else
1739   {
1740     nneighbor = route->next_hop;
1741   }
1742   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1743               "Forwarding message to %s\n",
1744               GNUNET_i2s (&nneighbor->peer));
1745   forward_payload (nneighbor,
1746                    distance + 1,
1747                    &rm->sender,
1748                    &rm->target,
1749                    payload);
1750 }
1751
1752
1753 /**
1754  * Check that @a msg is well-formed
1755  *
1756  * @param cls identification of the client
1757  * @param message the actual message
1758  * @return #GNUNET_OK if @a msg is well-formed
1759  */
1760 static int
1761 check_dv_send_message (void *cls,
1762                        const struct GNUNET_DV_SendMessage *msg)
1763 {
1764   const struct GNUNET_MessageHeader *payload;
1765
1766   if (ntohs (msg->header.size) < sizeof (struct GNUNET_DV_SendMessage) +
1767       sizeof (struct GNUNET_MessageHeader))
1768   {
1769     GNUNET_break (0);
1770     return GNUNET_SYSERR;
1771   }
1772   payload = (const struct GNUNET_MessageHeader *) &msg[1];
1773   if (ntohs (msg->header.size) != sizeof (struct GNUNET_DV_SendMessage) + ntohs (payload->size))
1774   {
1775     GNUNET_break (0);
1776     return GNUNET_SYSERR;
1777   }
1778   return GNUNET_OK;
1779 }
1780
1781
1782 /**
1783  * Service server's handler for message send requests (which come
1784  * bubbling up to us through the DV plugin).
1785  *
1786  * @param cls identification of the client
1787  * @param message the actual message
1788  */
1789 static void
1790 handle_dv_send_message (void *cls,
1791                         const struct GNUNET_DV_SendMessage *msg)
1792 {
1793   struct GNUNET_SERVICE_Client *client = cls;
1794   struct Route *route;
1795   const struct GNUNET_MessageHeader *payload;
1796
1797   payload = (const struct GNUNET_MessageHeader *) &msg[1];
1798   route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1799                                              &msg->target);
1800   if (NULL == route)
1801   {
1802     /* got disconnected */
1803     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1804                 "No route to %s, dropping local message of type %u\n",
1805                 GNUNET_i2s (&msg->target),
1806                 ntohs (payload->type));
1807     GNUNET_STATISTICS_update (stats,
1808                               "# local messages discarded (no route)",
1809                               1, GNUNET_NO);
1810     GNUNET_SERVICE_client_continue (client);
1811     return;
1812   }
1813   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1814               "Forwarding %u bytes of type %u to %s\n",
1815               ntohs (payload->size),
1816               ntohs (payload->type),
1817               GNUNET_i2s (&msg->target));
1818
1819   forward_payload (route->next_hop,
1820                    0 /* first hop, distance is zero */,
1821                    &my_identity,
1822                    &msg->target,
1823                    payload);
1824   GNUNET_SERVICE_client_continue (client);
1825 }
1826
1827
1828 /**
1829  * Cleanup all of the data structures associated with a given neighbor.
1830  *
1831  * @param neighbor neighbor to clean up
1832  */
1833 static void
1834 cleanup_neighbor (struct DirectNeighbor *neighbor)
1835 {
1836   handle_direct_disconnect (neighbor);
1837   GNUNET_assert (GNUNET_YES ==
1838                  GNUNET_CONTAINER_multipeermap_remove (direct_neighbors,
1839                                                        &neighbor->peer,
1840                                                        neighbor));
1841   GNUNET_free (neighbor);
1842 }
1843
1844
1845 /**
1846  * Method called whenever a given peer disconnects.
1847  *
1848  * @param cls closure
1849  * @param peer peer identity this notification is about
1850  * @param internal_cls the corresponding `struct DirectNeighbor`
1851  */
1852 static void
1853 handle_core_disconnect (void *cls,
1854                         const struct GNUNET_PeerIdentity *peer,
1855                         void *internal_cls)
1856 {
1857   struct DirectNeighbor *neighbor = internal_cls;
1858
1859   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860               "Received core peer disconnect message for peer `%s'!\n",
1861               GNUNET_i2s (peer));
1862   /* Check for disconnect from self message */
1863   if (NULL == neighbor)
1864     return;
1865   GNUNET_break (GNUNET_YES == neighbor->connected);
1866   neighbor->connected = GNUNET_NO;
1867   if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1868   {
1869     GNUNET_STATISTICS_update (stats,
1870                               "# peers connected (1-hop)",
1871                               -1,
1872                               GNUNET_NO);
1873   }
1874   cleanup_neighbor (neighbor);
1875   if (GNUNET_YES == in_shutdown)
1876     return;
1877   schedule_refresh_routes ();
1878 }
1879
1880
1881 /**
1882  * Multipeermap iterator for freeing routes.  Should never be called.
1883  *
1884  * @param cls NULL
1885  * @param key key value stored under
1886  * @param value the route to be freed
1887  * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1888  */
1889 static int
1890 free_route (void *cls,
1891             const struct GNUNET_PeerIdentity *key,
1892             void *value)
1893 {
1894   struct Route *route = value;
1895
1896   GNUNET_break (0);
1897   GNUNET_assert (GNUNET_YES ==
1898                  GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value));
1899   release_route (route);
1900   send_disconnect_to_plugin (&route->target.peer);
1901   GNUNET_free (route);
1902   return GNUNET_YES;
1903 }
1904
1905
1906 /**
1907  * Multipeermap iterator for freeing direct neighbors. Should never be called.
1908  *
1909  * @param cls NULL
1910  * @param key key value stored under
1911  * @param value the direct neighbor to be freed
1912  * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1913  */
1914 static int
1915 free_direct_neighbors (void *cls,
1916                        const struct GNUNET_PeerIdentity *key,
1917                        void *value)
1918 {
1919   struct DirectNeighbor *neighbor = value;
1920
1921   cleanup_neighbor (neighbor);
1922   return GNUNET_YES;
1923 }
1924
1925
1926 /**
1927  * Task run during shutdown.
1928  *
1929  * @param cls unused
1930  */
1931 static void
1932 shutdown_task (void *cls)
1933 {
1934   unsigned int i;
1935
1936   in_shutdown = GNUNET_YES;
1937   GNUNET_assert (NULL != core_api);
1938   GNUNET_CORE_disconnect (core_api);
1939   core_api = NULL;
1940   GNUNET_ATS_performance_done (ats);
1941   ats = NULL;
1942   GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors,
1943                                          &free_direct_neighbors,
1944                                          NULL);
1945   GNUNET_CONTAINER_multipeermap_iterate (all_routes,
1946                                          &free_route,
1947                                          NULL);
1948   GNUNET_CONTAINER_multipeermap_destroy (direct_neighbors);
1949   GNUNET_CONTAINER_multipeermap_destroy (all_routes);
1950   GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1951   stats = NULL;
1952   GNUNET_notification_context_destroy (nc);
1953   nc = NULL;
1954   for (i=0;i<DEFAULT_FISHEYE_DEPTH;i++)
1955   {
1956     GNUNET_array_grow (consensi[i].targets,
1957                        consensi[i].array_length,
1958                        0);
1959   }
1960   if (NULL != rr_task)
1961   {
1962     GNUNET_SCHEDULER_cancel (rr_task);
1963     rr_task = NULL;
1964   }
1965 }
1966
1967
1968 /**
1969  * Notify newly connected client about an existing route.
1970  *
1971  * @param cls the `struct GNUNET_SERVICE_Client *`
1972  * @param key peer identity
1973  * @param value the `struct Route *`
1974  * @return #GNUNET_OK (continue to iterate)
1975  */
1976 static int
1977 notify_client_about_route (void *cls,
1978                            const struct GNUNET_PeerIdentity *key,
1979                            void *value)
1980 {
1981   struct GNUNET_SERVICE_Client *client = cls;
1982   struct Route *route = value;
1983   struct GNUNET_MQ_Envelope *env;
1984   struct GNUNET_DV_ConnectMessage *cm;
1985
1986   env = GNUNET_MQ_msg (cm,
1987                        GNUNET_MESSAGE_TYPE_DV_CONNECT);
1988   cm->distance = htonl (route->target.distance);
1989   cm->peer = route->target.peer;
1990   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1991                   env);
1992   return GNUNET_OK;
1993 }
1994
1995
1996 /**
1997  * Handle START-message.  This is the first message sent to us
1998  * by the client (can only be one!).
1999  *
2000  * @param cls closure (always NULL)
2001  * @param client identification of the client
2002  * @param message the actual message
2003  */
2004 static void
2005 handle_start (void *cls,
2006               const struct GNUNET_MessageHeader *message)
2007 {
2008   struct GNUNET_SERVICE_Client *client = cls;
2009
2010   GNUNET_notification_context_add (nc,
2011                                    GNUNET_SERVICE_client_get_mq (client));
2012   GNUNET_SERVICE_client_continue (client);
2013   GNUNET_CONTAINER_multipeermap_iterate (all_routes,
2014                                          &notify_client_about_route,
2015                                          client);
2016 }
2017
2018
2019 /**
2020  * Called on core init.
2021  *
2022  * @param cls unused
2023  * @param identity this peer's identity
2024  */
2025 static void
2026 core_init (void *cls,
2027            const struct GNUNET_PeerIdentity *identity)
2028 {
2029   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2030               "I am peer: %s\n",
2031               GNUNET_i2s (identity));
2032   my_identity = *identity;
2033 }
2034
2035
2036 /**
2037  * Process dv requests.
2038  *
2039  * @param cls closure
2040  * @param c configuration to use
2041  * @param service the initialized service
2042  */
2043 static void
2044 run (void *cls,
2045      const struct GNUNET_CONFIGURATION_Handle *c,
2046      struct GNUNET_SERVICE_Handle *service)
2047 {
2048   struct GNUNET_MQ_MessageHandler core_handlers[] = {
2049     GNUNET_MQ_hd_var_size (dv_route_message,
2050                            GNUNET_MESSAGE_TYPE_DV_ROUTE,
2051                            struct RouteMessage,
2052                            NULL),
2053     GNUNET_MQ_handler_end ()
2054   };
2055   in_shutdown = GNUNET_NO;
2056   cfg = c;
2057   direct_neighbors = GNUNET_CONTAINER_multipeermap_create (128,
2058                                                            GNUNET_NO);
2059   all_routes = GNUNET_CONTAINER_multipeermap_create (65536,
2060                                                      GNUNET_NO);
2061   core_api = GNUNET_CORE_connect (cfg,
2062                                   NULL,
2063                                   &core_init,
2064                                   &handle_core_connect,
2065                                   &handle_core_disconnect,
2066                                   core_handlers);
2067
2068   if (NULL == core_api)
2069     return;
2070   ats = GNUNET_ATS_performance_init (cfg,
2071                                      &handle_ats_update,
2072                                      NULL);
2073   if (NULL == ats)
2074   {
2075     GNUNET_CORE_disconnect (core_api);
2076     core_api = NULL;
2077     return;
2078   }
2079   nc = GNUNET_notification_context_create (MAX_QUEUE_SIZE_PLUGIN);
2080   stats = GNUNET_STATISTICS_create ("dv",
2081                                     cfg);
2082   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2083                                  NULL);
2084 }
2085
2086
2087 /**
2088  * Callback called when a client connects to the service.
2089  *
2090  * @param cls closure for the service
2091  * @param c the new client that connected to the service
2092  * @param mq the message queue used to send messages to the client
2093  * @return @a c
2094  */
2095 static void *
2096 client_connect_cb (void *cls,
2097                    struct GNUNET_SERVICE_Client *c,
2098                    struct GNUNET_MQ_Handle *mq)
2099 {
2100   return c;
2101 }
2102
2103
2104 /**
2105  * Callback called when a client disconnected from the service
2106  *
2107  * @param cls closure for the service
2108  * @param c the client that disconnected
2109  * @param internal_cls should be equal to @a c
2110  */
2111 static void
2112 client_disconnect_cb (void *cls,
2113                       struct GNUNET_SERVICE_Client *c,
2114                       void *internal_cls)
2115 {
2116   GNUNET_assert (c == internal_cls);
2117 }
2118
2119
2120 /**
2121  * Define "main" method using service macro.
2122  */
2123 GNUNET_SERVICE_MAIN
2124 ("dv",
2125  GNUNET_SERVICE_OPTION_NONE,
2126  &run,
2127  &client_connect_cb,
2128  &client_disconnect_cb,
2129  NULL,
2130  GNUNET_MQ_hd_fixed_size (start,
2131                           GNUNET_MESSAGE_TYPE_DV_START,
2132                           struct GNUNET_MessageHeader,
2133                           NULL),
2134  GNUNET_MQ_hd_var_size (dv_send_message,
2135                         GNUNET_MESSAGE_TYPE_DV_SEND,
2136                         struct GNUNET_DV_SendMessage,
2137                         NULL),
2138  GNUNET_MQ_handler_end ());
2139
2140
2141 /* end of gnunet-service-dv.c */