ca4908e95b239016e047a1d443c23ff97bab69cd
[oweals/gnunet.git] / src / dv / plugin_transport_dv.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2002--2014 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero 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      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file dv/plugin_transport_dv.c
21  * @brief DV transport service, takes incoming DV requests and deals with
22  * the DV service
23  * @author Nathan Evans
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_statistics_service.h"
30 #include "gnunet_dv_service.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_transport_plugin.h"
33 #include "dv.h"
34
35
36 #define LOG(kind,...) GNUNET_log_from (kind, "transport-dv",__VA_ARGS__)
37
38
39 /**
40  * Encapsulation of all of the state of the plugin.
41  */
42 struct Plugin;
43
44
45 /**
46  * Session handle for connections.
47  */
48 struct GNUNET_ATS_Session
49 {
50   /**
51    * Pointer to the global plugin struct.
52    */
53   struct Plugin *plugin;
54
55   /**
56    * Address we use for the other peer.
57    */
58   struct GNUNET_HELLO_Address *address;
59
60   /**
61    * To whom are we talking to.
62    */
63   struct GNUNET_PeerIdentity sender;
64
65   /**
66    * Number of bytes waiting for transmission to this peer.
67    * FIXME: not set yet.
68    */
69   unsigned long long bytes_in_queue;
70
71   /**
72    * Number of messages waiting for transmission to this peer.
73    * FIXME: not set yet.
74    */
75   unsigned int msgs_in_queue;
76
77   /**
78    * Current distance to the given peer.
79    */
80   uint32_t distance;
81
82   /**
83    * Current network the next hop peer is located in
84    */
85   enum GNUNET_NetworkType network;
86
87   /**
88    * Does the transport service know about this session (and we thus
89    * need to call `session_end` when it is released?)
90    */
91   int active;
92
93 };
94
95
96 /**
97  * Encapsulation of all of the state of the plugin.
98  */
99 struct Plugin
100 {
101   /**
102    * Our environment.
103    */
104   struct GNUNET_TRANSPORT_PluginEnvironment *env;
105
106   /**
107    * Hash map of sessions (active and inactive).
108    */
109   struct GNUNET_CONTAINER_MultiPeerMap *sessions;
110
111   /**
112    * Copy of the handler array where the closures are
113    * set to this struct's instance.
114    */
115   struct GNUNET_SERVER_MessageHandler *handlers;
116
117   /**
118    * Handle to the DV service
119    */
120   struct GNUNET_DV_ServiceHandle *dvh;
121
122   /**
123    * Tokenizer for boxed messages.
124    */
125   struct GNUNET_SERVER_MessageStreamTokenizer *mst;
126
127   /**
128    * Function to call about session status changes.
129    */
130   GNUNET_TRANSPORT_SessionInfoCallback sic;
131
132   /**
133    * Closure for @e sic.
134    */
135   void *sic_cls;
136 };
137
138
139 /**
140  * If a session monitor is attached, notify it about the new
141  * session state.
142  *
143  * @param plugin our plugin
144  * @param session session that changed state
145  * @param state new state of the session
146  */
147 static void
148 notify_session_monitor (struct Plugin *plugin,
149                         struct GNUNET_ATS_Session *session,
150                         enum GNUNET_TRANSPORT_SessionState state)
151 {
152   struct GNUNET_TRANSPORT_SessionInfo info;
153
154   if (NULL == plugin->sic)
155     return;
156   memset (&info, 0, sizeof (info));
157   info.state = state;
158   info.is_inbound = GNUNET_SYSERR; /* hard to say */
159   info.num_msg_pending = session->msgs_in_queue;
160   info.num_bytes_pending = session->bytes_in_queue;
161   /* info.receive_delay remains zero as this is not supported by DV
162      (cannot selectively not receive from 'core') */
163   info.session_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
164   info.address = session->address;
165   plugin->sic (plugin->sic_cls,
166                session,
167                &info);
168 }
169
170
171 /**
172  * Notify transport service about the change in distance.
173  *
174  * @param session session where the distance changed
175  */
176 static void
177 notify_distance_change (struct GNUNET_ATS_Session *session)
178 {
179   struct Plugin *plugin = session->plugin;
180
181   if (GNUNET_YES != session->active)
182     return;
183   plugin->env->update_address_distance (plugin->env->cls,
184                                         session->address,
185                                         session->distance);
186 }
187
188
189 /**
190  * Function called by MST on each message from the box.
191  *
192  * @param cls closure with the `struct Plugin *`
193  * @param client identification of the client (with the 'struct GNUNET_ATS_Session')
194  * @param message the actual message
195  * @return #GNUNET_OK on success
196  */
197 static int
198 unbox_cb (void *cls,
199           void *client,
200           const struct GNUNET_MessageHeader *message)
201 {
202   struct Plugin *plugin = cls;
203   struct GNUNET_ATS_Session *session = client;
204
205   session->active = GNUNET_YES;
206   LOG (GNUNET_ERROR_TYPE_DEBUG,
207        "Delivering message of type %u with %u bytes from peer `%s'\n",
208        ntohs (message->type),
209        ntohs (message->size),
210        GNUNET_i2s (&session->sender));
211   plugin->env->receive (plugin->env->cls,
212                         session->address,
213                         session,
214                         message);
215   plugin->env->update_address_distance (plugin->env->cls,
216                                         session->address,
217                                         session->distance);
218   return GNUNET_OK;
219 }
220
221
222 /**
223  * Handler for messages received from the DV service.
224  *
225  * @param cls closure with the plugin
226  * @param sender sender of the message
227  * @param distance how far did the message travel
228  * @param msg actual message payload
229  */
230 static void
231 handle_dv_message_received (void *cls,
232                             const struct GNUNET_PeerIdentity *sender,
233                             uint32_t distance,
234                             const struct GNUNET_MessageHeader *msg)
235 {
236   struct Plugin *plugin = cls;
237   struct GNUNET_ATS_Session *session;
238
239   LOG (GNUNET_ERROR_TYPE_DEBUG,
240        "Received DV_MESSAGE_RECEIVED message for peer `%s': new distance %u\n",
241        GNUNET_i2s (sender),
242        distance);
243   session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
244                                                sender);
245   if (NULL == session)
246   {
247     GNUNET_break (0);
248     return;
249   }
250   if (GNUNET_MESSAGE_TYPE_DV_BOX == ntohs (msg->type))
251   {
252     /* need to unbox using MST */
253     LOG (GNUNET_ERROR_TYPE_DEBUG,
254          "Unboxing DV message using MST\n");
255     GNUNET_SERVER_mst_receive (plugin->mst,
256                                session,
257                                (const char *) &msg[1],
258                                ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader),
259                                GNUNET_YES,
260                                GNUNET_NO);
261     return;
262   }
263   session->active = GNUNET_YES;
264   LOG (GNUNET_ERROR_TYPE_DEBUG,
265        "Delivering message of type %u with %u bytes from peer `%s'\n",
266        ntohs (msg->type),
267        ntohs (msg->size),
268        GNUNET_i2s (sender));
269   plugin->env->receive (plugin->env->cls,
270                         session->address,
271                         session,
272                         msg);
273   plugin->env->update_address_distance (plugin->env->cls,
274                                         session->address,
275                                         session->distance);
276 }
277
278
279 /**
280  * Function called if DV starts to be able to talk to a peer.
281  *
282  * @param cls closure with `struct Plugin *`
283  * @param peer newly connected peer
284  * @param distance distance to the peer
285  * @param network the network the next hop is located in
286  */
287 static void
288 handle_dv_connect (void *cls,
289                    const struct GNUNET_PeerIdentity *peer,
290                    uint32_t distance,
291                    enum GNUNET_NetworkType network)
292 {
293   struct Plugin *plugin = cls;
294   struct GNUNET_ATS_Session *session;
295
296   GNUNET_break (GNUNET_NT_UNSPECIFIED != network);
297   /**
298    * This requires transport plugin to be linked to libgnunetats.
299    * If you remove it, also remove libgnunetats linkage from Makefile.am
300    */
301   LOG (GNUNET_ERROR_TYPE_DEBUG,
302        "Received DV_CONNECT message for peer `%s' with next hop in network %s\n",
303        GNUNET_i2s (peer),
304        GNUNET_NT_to_string (network));
305
306   session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
307                                                peer);
308   if (NULL != session)
309   {
310     GNUNET_break (0);
311     session->distance = distance;
312     notify_distance_change (session);
313     return; /* nothing to do */
314   }
315
316   session = GNUNET_new (struct GNUNET_ATS_Session);
317   session->address = GNUNET_HELLO_address_allocate (peer, "dv",
318                                                     NULL, 0,
319                                                     GNUNET_HELLO_ADDRESS_INFO_NONE);
320   session->sender = *peer;
321   session->plugin = plugin;
322   session->distance = distance;
323   session->network = network;
324   GNUNET_assert(GNUNET_YES ==
325                 GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
326                                                    &session->sender, session,
327                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
328
329   LOG (GNUNET_ERROR_TYPE_DEBUG,
330        "Creating new DV session %p for peer `%s' at distance %u\n",
331        session,
332        GNUNET_i2s (peer),
333        distance);
334
335   session->active = GNUNET_YES;
336   plugin->env->session_start (plugin->env->cls,
337                               session->address,
338                               session,
339                               network);
340   plugin->env->update_address_distance (plugin->env->cls,
341                                         session->address,
342                                         session->distance);
343
344   notify_session_monitor (session->plugin,
345                           session,
346                           GNUNET_TRANSPORT_SS_UP);
347 }
348
349
350 /**
351  * Function called if DV distance to a peer is changed.
352  *
353  * @param cls closure with `struct Plugin *`
354  * @param peer connected peer
355  * @param distance new distance to the peer
356  * @param network network type used for the connection
357  */
358 static void
359 handle_dv_distance_changed (void *cls,
360                             const struct GNUNET_PeerIdentity *peer,
361                             uint32_t distance,
362                             enum GNUNET_NetworkType network)
363 {
364   struct Plugin *plugin = cls;
365   struct GNUNET_ATS_Session *session;
366
367   GNUNET_break (GNUNET_NT_UNSPECIFIED != network);
368   LOG (GNUNET_ERROR_TYPE_DEBUG,
369        "Received `%s' message for peer `%s': new distance %u\n",
370        "DV_DISTANCE_CHANGED",
371        GNUNET_i2s (peer),
372        distance);
373   session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
374                                                peer);
375   if (NULL == session)
376   {
377     GNUNET_break (0);
378     handle_dv_connect (plugin, peer, distance, network);
379     return;
380   }
381   session->distance = distance;
382   notify_distance_change (session);
383 }
384
385
386 /**
387  * Release session object and clean up associated resources.
388  *
389  * @param session session to clean up
390  */
391 static void
392 free_session (struct GNUNET_ATS_Session *session)
393 {
394   struct Plugin *plugin = session->plugin;
395
396   GNUNET_assert (GNUNET_YES ==
397                  GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
398                                                        &session->sender,
399                                                        session));
400
401   LOG (GNUNET_ERROR_TYPE_DEBUG,
402        "Freeing session %p for peer `%s'\n",
403        session,
404        GNUNET_i2s (&session->sender));
405   if (GNUNET_YES == session->active)
406   {
407     notify_session_monitor (session->plugin,
408                             session,
409                             GNUNET_TRANSPORT_SS_DONE);
410     plugin->env->session_end (plugin->env->cls,
411                               session->address,
412                               session);
413     session->active = GNUNET_NO;
414   }
415   GNUNET_HELLO_address_free (session->address);
416   GNUNET_free (session);
417 }
418
419
420 /**
421  * Function called if DV is no longer able to talk to a peer.
422  *
423  * @param cls closure with `struct Plugin *`
424  * @param peer peer that disconnected
425  */
426 static void
427 handle_dv_disconnect (void *cls,
428                       const struct GNUNET_PeerIdentity *peer)
429 {
430   struct Plugin *plugin = cls;
431   struct GNUNET_ATS_Session *session;
432
433   LOG (GNUNET_ERROR_TYPE_DEBUG,
434        "Received `%s' message for peer `%s'\n",
435        "DV_DISCONNECT",
436        GNUNET_i2s (peer));
437   session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
438                                                peer);
439   if (NULL == session)
440     return; /* nothing to do */
441   free_session (session);
442 }
443
444
445 /**
446  * Function that can be used by the transport service to transmit
447  * a message using the plugin.
448  *
449  * @param cls closure
450  * @param session the session used
451  * @param priority how important is the message
452  * @param msgbuf the message to transmit
453  * @param msgbuf_size number of bytes in 'msgbuf'
454  * @param timeout when should we time out
455  * @param cont continuation to call once the message has
456  *        been transmitted (or if the transport is ready
457  *        for the next transmission call; or if the
458  *        peer disconnected...)
459  * @param cont_cls closure for @a cont
460  * @return number of bytes used (on the physical network, with overheads);
461  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
462  *         and does NOT mean that the message was not transmitted (DV)
463  */
464 static ssize_t
465 dv_plugin_send (void *cls,
466                 struct GNUNET_ATS_Session *session,
467                 const char *msgbuf,
468                 size_t msgbuf_size,
469                 unsigned int priority,
470                 struct GNUNET_TIME_Relative timeout,
471                 GNUNET_TRANSPORT_TransmitContinuation cont,
472                 void *cont_cls)
473 {
474   struct Plugin *plugin = cls;
475   const struct GNUNET_MessageHeader *msg;
476   struct GNUNET_MessageHeader *box;
477
478   box = NULL;
479   msg = (const struct GNUNET_MessageHeader *) msgbuf;
480   if (ntohs (msg->size) != msgbuf_size)
481   {
482     /* need to box */
483     LOG (GNUNET_ERROR_TYPE_DEBUG,
484          "Boxing DV message\n");
485     box = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + msgbuf_size);
486     box->type = htons (GNUNET_MESSAGE_TYPE_DV_BOX);
487     box->size = htons (sizeof (struct GNUNET_MessageHeader) + msgbuf_size);
488     GNUNET_memcpy (&box[1], msgbuf, msgbuf_size);
489     msg = box;
490   }
491   GNUNET_DV_send (plugin->dvh,
492                   &session->sender,
493                   msg);
494   cont (cont_cls,
495         &session->sender,
496         GNUNET_OK,
497         msgbuf_size, 0);
498   GNUNET_free_non_null (box);
499   return 0; /* DV */
500 }
501
502
503 /**
504  * Function that can be used to force the plugin to disconnect
505  * from the given peer and cancel all previous transmissions
506  * (and their continuations).
507  *
508  * @param cls closure with the `struct Plugin *`
509  * @param target peer from which to disconnect
510  */
511 static void
512 dv_plugin_disconnect_peer (void *cls,
513                            const struct GNUNET_PeerIdentity *target)
514 {
515   struct Plugin *plugin = cls;
516   struct GNUNET_ATS_Session *session;
517
518   session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
519                                                target);
520   if (NULL == session)
521     return; /* nothing to do */
522   session->active = GNUNET_NO;
523 }
524
525
526 /**
527  * Function that can be used to force the plugin to disconnect
528  * from the given peer and cancel all previous transmissions
529  * (and their continuations).
530  *
531  * @param cls closure with the `struct Plugin *`
532  * @param session which session to disconnect
533  * @return #GNUNET_OK
534  */
535 static int
536 dv_plugin_disconnect_session (void *cls,
537                               struct GNUNET_ATS_Session *session)
538 {
539   session->active = GNUNET_NO;
540   return GNUNET_OK;
541 }
542
543
544 /**
545  * Convert the transports address to a nice, human-readable
546  * format.
547  *
548  * @param cls closure
549  * @param type name of the transport that generated the address
550  * @param addr one of the addresses of the host, NULL for the last address
551  *        the specific address format depends on the transport
552  * @param addrlen length of the address
553  * @param numeric should (IP) addresses be displayed in numeric form?
554  * @param timeout after how long should we give up?
555  * @param asc function to call on each string
556  * @param asc_cls closure for @a asc
557  */
558 static void
559 dv_plugin_address_pretty_printer (void *cls,
560                                   const char *type,
561                                   const void *addr,
562                                   size_t addrlen,
563                                   int numeric,
564                                   struct GNUNET_TIME_Relative timeout,
565                                   GNUNET_TRANSPORT_AddressStringCallback asc,
566                                   void *asc_cls)
567 {
568   if ( (0 == addrlen) &&
569        (0 == strcmp (type, "dv")) )
570     asc (asc_cls,
571          "dv",
572          GNUNET_OK);
573   else
574     asc (asc_cls,
575          NULL,
576          GNUNET_SYSERR);
577   asc (asc_cls,
578        NULL,
579        GNUNET_OK);
580 }
581
582
583 /**
584  * Convert the DV address to a pretty string.
585  *
586  * @param cls closure
587  * @param addr the (hopefully) DV address
588  * @param addrlen the length of the @a addr
589  * @return string representing the DV address
590  */
591 static const char *
592 dv_plugin_address_to_string (void *cls,
593                              const void *addr,
594                              size_t addrlen)
595 {
596   if (0 != addrlen)
597   {
598     GNUNET_break (0); /* malformed */
599     return NULL;
600   }
601   return "dv";
602 }
603
604
605 /**
606  * Another peer has suggested an address for this peer and transport
607  * plugin.  Check that this could be a valid address.  This function
608  * is not expected to 'validate' the address in the sense of trying to
609  * connect to it but simply to see if the binary format is technically
610  * legal for establishing a connection to this peer (and make sure that
611  * the address really corresponds to our network connection/settings
612  * and not some potential man-in-the-middle).
613  *
614  * @param cls closure
615  * @param addr pointer to the address
616  * @param addrlen length of @a addr
617  * @return #GNUNET_OK if this is a plausible address for this peer
618  *         and transport, #GNUNET_SYSERR if not
619  *
620  */
621 static int
622 dv_plugin_check_address (void *cls,
623                          const void *addr,
624                          size_t addrlen)
625 {
626   if (0 != addrlen)
627     return GNUNET_SYSERR;
628   return GNUNET_OK;
629 }
630
631
632 /**
633  * Create a new session to transmit data to the target
634  * This session will used to send data to this peer and the plugin will
635  * notify us by calling the env->session_end function
636  *
637  * @param cls the plugin
638  * @param address the address
639  * @return the session if the address is valid, NULL otherwise
640  */
641 static struct GNUNET_ATS_Session *
642 dv_get_session (void *cls,
643                 const struct GNUNET_HELLO_Address *address)
644 {
645   struct Plugin *plugin = cls;
646   struct GNUNET_ATS_Session *session;
647
648   if (0 != address->address_length)
649     return NULL;
650   session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
651                                                &address->peer);
652   if (NULL == session)
653     return NULL; /* not valid right now */
654   session->active = GNUNET_YES;
655   return session;
656 }
657
658
659 /**
660  * Function called to convert a string address to
661  * a binary address.
662  *
663  * @param cls closure ('struct Plugin*')
664  * @param addr string address
665  * @param addrlen length of the @a addr including \0 termination
666  * @param buf location to store the buffer
667  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
668  * @param added length of created address
669  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
670  */
671 static int
672 dv_plugin_string_to_address (void *cls,
673                              const char *addr,
674                              uint16_t addrlen,
675                              void **buf,
676                              size_t *added)
677 {
678   if ( (addrlen == 3) &&
679        (0 == strcmp ("dv", addr)) )
680   {
681     *added = 0;
682     return GNUNET_OK;
683   }
684   return GNUNET_SYSERR;
685 }
686
687
688 /**
689  * Function that will be called whenever the transport service wants to
690  * notify the plugin that a session is still active and in use and
691  * therefore the session timeout for this session has to be updated
692  *
693  * @param cls closure (`struct Plugin *`)
694  * @param peer which peer was the session for
695  * @param session which session is being updated
696  */
697 static void
698 dv_plugin_update_session_timeout (void *cls,
699                                   const struct GNUNET_PeerIdentity *peer,
700                                   struct GNUNET_ATS_Session *session)
701 {
702   /* DV currently doesn't time out like "normal" plugins,
703      so it should be safe to do nothing, right?
704      (or should we add an internal timeout?) */
705 }
706
707
708 /**
709  * Function to obtain the network type for a session
710  * FIXME: we should probably look at the network type
711  * used by the next hop here.  Or find some other way
712  * to properly allow ATS-DV resource allocation.
713  *
714  * @param cls closure (`struct Plugin *`)
715  * @param session the session
716  * @return the network type
717  */
718 static enum GNUNET_NetworkType
719 dv_get_network (void *cls,
720                 struct GNUNET_ATS_Session *session)
721 {
722   GNUNET_assert (NULL != session);
723   return session->network;
724 }
725
726
727 /**
728  * Function obtain the network type for an address.
729  *
730  * @param cls closure (`struct Plugin *`)
731  * @param address the address
732  * @return the network type
733  */
734 static enum GNUNET_NetworkType
735 dv_plugin_get_network_for_address (void *cls,
736                                    const struct GNUNET_HELLO_Address *address)
737 {
738   return GNUNET_NT_WAN; /* FOR NOW */
739 }
740
741
742 /**
743  * Function that is called to get the keepalive factor.
744  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
745  * calculate the interval between keepalive packets.
746  *
747  * @param cls closure with the `struct Plugin`
748  * @return keepalive factor
749  */
750 static unsigned int
751 dv_plugin_query_keepalive_factor (void *cls)
752 {
753   return 3;
754 }
755
756
757 /**
758  * Return information about the given session to the
759  * monitor callback.
760  *
761  * @param cls the `struct Plugin` with the monitor callback (`sic`)
762  * @param peer peer we send information about
763  * @param value our `struct GNUNET_ATS_Session` to send information about
764  * @return #GNUNET_OK (continue to iterate)
765  */
766 static int
767 send_session_info_iter (void *cls,
768                         const struct GNUNET_PeerIdentity *peer,
769                         void *value)
770 {
771   struct Plugin *plugin = cls;
772   struct GNUNET_ATS_Session *session = value;
773
774   if (GNUNET_YES != session->active)
775     return GNUNET_OK;
776   notify_session_monitor (plugin,
777                           session,
778                           GNUNET_TRANSPORT_SS_UP);
779   return GNUNET_OK;
780 }
781
782
783 /**
784  * Begin monitoring sessions of a plugin.  There can only
785  * be one active monitor per plugin (i.e. if there are
786  * multiple monitors, the transport service needs to
787  * multiplex the generated events over all of them).
788  *
789  * @param cls closure of the plugin
790  * @param sic callback to invoke, NULL to disable monitor;
791  *            plugin will being by iterating over all active
792  *            sessions immediately and then enter monitor mode
793  * @param sic_cls closure for @a sic
794  */
795 static void
796 dv_plugin_setup_monitor (void *cls,
797                           GNUNET_TRANSPORT_SessionInfoCallback sic,
798                           void *sic_cls)
799 {
800   struct Plugin *plugin = cls;
801
802   plugin->sic = sic;
803   plugin->sic_cls = sic_cls;
804   if (NULL != sic)
805   {
806     GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
807                                            &send_session_info_iter,
808                                            plugin);
809     /* signal end of first iteration */
810     sic (sic_cls, NULL, NULL);
811   }
812 }
813
814
815 /**
816  * Entry point for the plugin.
817  *
818  * @param cls closure with the plugin environment
819  * @return plugin API
820  */
821 void *
822 libgnunet_plugin_transport_dv_init (void *cls)
823 {
824   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
825   struct GNUNET_TRANSPORT_PluginFunctions *api;
826   struct Plugin *plugin;
827
828   plugin = GNUNET_new (struct Plugin);
829   plugin->env = env;
830   plugin->sessions = GNUNET_CONTAINER_multipeermap_create (1024 * 8, GNUNET_YES);
831   plugin->mst = GNUNET_SERVER_mst_create (&unbox_cb,
832                                           plugin);
833   plugin->dvh = GNUNET_DV_service_connect (env->cfg,
834                                            plugin,
835                                            &handle_dv_connect,
836                                            &handle_dv_distance_changed,
837                                            &handle_dv_disconnect,
838                                            &handle_dv_message_received);
839   if (NULL == plugin->dvh)
840   {
841     GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
842     GNUNET_SERVER_mst_destroy (plugin->mst);
843     GNUNET_free (plugin);
844     return NULL;
845   }
846   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
847   api->cls = plugin;
848   api->send = &dv_plugin_send;
849   api->disconnect_peer = &dv_plugin_disconnect_peer;
850   api->disconnect_session = &dv_plugin_disconnect_session;
851   api->address_pretty_printer = &dv_plugin_address_pretty_printer;
852   api->check_address = &dv_plugin_check_address;
853   api->address_to_string = &dv_plugin_address_to_string;
854   api->string_to_address = &dv_plugin_string_to_address;
855   api->query_keepalive_factor = &dv_plugin_query_keepalive_factor;
856   api->get_session = &dv_get_session;
857   api->get_network = &dv_get_network;
858   api->get_network_for_address = &dv_plugin_get_network_for_address;
859   api->update_session_timeout = &dv_plugin_update_session_timeout;
860   api->setup_monitor = &dv_plugin_setup_monitor;
861   return api;
862 }
863
864
865 /**
866  * Function called to free a session.
867  *
868  * @param cls NULL
869  * @param key unused
870  * @param value session to free
871  * @return #GNUNET_OK (continue to iterate)
872  */
873 static int
874 free_session_iterator (void *cls,
875                        const struct GNUNET_PeerIdentity *key,
876                        void *value)
877 {
878   struct GNUNET_ATS_Session *session = value;
879
880   free_session (session);
881   return GNUNET_OK;
882 }
883
884
885 /**
886  * Exit point from the plugin.
887  *
888  * @param cls plugin API
889  * @return NULL
890  */
891 void *
892 libgnunet_plugin_transport_dv_done (void *cls)
893 {
894   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
895   struct Plugin *plugin = api->cls;
896
897   GNUNET_DV_service_disconnect (plugin->dvh);
898   GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
899                                          &free_session_iterator,
900                                          NULL);
901   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
902   GNUNET_SERVER_mst_destroy (plugin->mst);
903   GNUNET_free (plugin);
904   GNUNET_free (api);
905   return NULL;
906 }
907
908 /* end of plugin_transport_dv.c */