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