fixing mantis #1825
[oweals/gnunet.git] / src / transport / plugin_transport_http.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 transport/plugin_transport_http.c
23  * @brief http transport service plugin
24  * @author Matthias Wachs
25  */
26
27 #include "plugin_transport_http.h"
28
29 /**
30  * After how long do we expire an address that we
31  * learned from another peer if it is not reconfirmed
32  * by anyone?
33  */
34 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
35
36 /**
37  * IPv4 addresses
38  */
39 struct IPv4HttpAddress
40 {
41   /**
42    * IPv4 address, in network byte order.
43    */
44   uint32_t ipv4_addr GNUNET_PACKED;
45
46   /**
47    * Port number, in network byte order.
48    */
49   uint16_t u4_port GNUNET_PACKED;
50 };
51
52 /**
53  * IPv4 addresses
54  */
55 struct IPv6HttpAddress
56 {
57   /**
58    * IPv6 address.
59    */
60   struct in6_addr ipv6_addr GNUNET_PACKED;
61
62   /**
63    * Port number, in network byte order.
64    */
65   uint16_t u6_port GNUNET_PACKED;
66 };
67
68 /**
69  * Wrapper to manage IPv4 addresses
70  */
71 struct IPv4HttpAddressWrapper
72 {
73   /**
74    * Linked list next
75    */
76   struct IPv4HttpAddressWrapper *next;
77
78   /**
79    * Linked list previous
80    */
81   struct IPv4HttpAddressWrapper *prev;
82
83   struct IPv4HttpAddress addr;
84 };
85
86 /**
87  * Wrapper for IPv4 addresses.
88  */
89 struct IPv6HttpAddressWrapper
90 {
91   /**
92    * Linked list next
93    */
94   struct IPv6HttpAddressWrapper *next;
95
96   /**
97    * Linked list previous
98    */
99   struct IPv6HttpAddressWrapper *prev;
100
101   struct IPv6HttpAddress addr6;
102 };
103
104
105 /**
106  * Context for address to string conversion.
107  */
108 struct PrettyPrinterContext
109 {
110   /**
111    * Function to call with the result.
112    */
113   GNUNET_TRANSPORT_AddressStringCallback asc;
114
115   /**
116    * Plugin
117    */
118   struct Plugin *plugin;
119
120   /**
121    * Clsoure for 'asc'.
122    */
123   void *asc_cls;
124
125   /**
126    * Port to add after the IP address.
127    */
128   uint16_t port;
129 };
130
131
132 /**
133  * Encapsulation of all of the state of the plugin.
134  */
135 struct Plugin;
136
137
138
139 /**
140  * Append our port and forward the result.
141  *
142  * @param cls the 'struct PrettyPrinterContext*'
143  * @param hostname hostname part of the address
144  */
145 static void
146 append_port (void *cls, const char *hostname)
147 {
148   struct PrettyPrinterContext *ppc = cls;
149   char *ret;
150
151   if (hostname == NULL)
152   {
153     ppc->asc (ppc->asc_cls, NULL);
154     GNUNET_free (ppc);
155     return;
156   }
157   GNUNET_asprintf (&ret, "%s://%s:%d", ppc->plugin->protocol, hostname,
158                    ppc->plugin->port);
159   ppc->asc (ppc->asc_cls, ret);
160   GNUNET_free (ret);
161 }
162
163
164 /**
165  * Convert the transports address to a nice, human-readable
166  * format.
167  *
168  * @param cls closure
169  * @param type name of the transport that generated the address
170  * @param addr one of the addresses of the host, NULL for the last address
171  *        the specific address format depends on the transport
172  * @param addrlen length of the address
173  * @param numeric should (IP) addresses be displayed in numeric form?
174  * @param timeout after how long should we give up?
175  * @param asc function to call on each string
176  * @param asc_cls closure for asc
177  */
178 static void
179 http_plugin_address_pretty_printer (void *cls, const char *type,
180                                     const void *addr, size_t addrlen,
181                                     int numeric,
182                                     struct GNUNET_TIME_Relative timeout,
183                                     GNUNET_TRANSPORT_AddressStringCallback asc,
184                                     void *asc_cls)
185 {
186   GNUNET_assert (cls != NULL);
187   struct PrettyPrinterContext *ppc;
188   const void *sb;
189   size_t sbs;
190   uint16_t port = 0 ;
191
192   // BUG! Transport addrs over the network must NOT be 'struct sockaddr*'s!
193   if (addrlen == sizeof (struct IPv6HttpAddress))
194   {
195     struct IPv6HttpAddress * a6 = (struct IPv6HttpAddress *) addr;
196     sb = &a6->ipv6_addr;
197     sbs = sizeof (struct in6_addr);
198     port = ntohs (a6->u6_port);
199   }
200   else if (addrlen == sizeof (struct IPv4HttpAddress))
201   {
202     struct IPv4HttpAddress * a4 = (struct IPv4HttpAddress *) addr;
203     sb = &a4->ipv4_addr;
204     sbs = sizeof (struct in_addr);
205     port = ntohs (a4->u4_port);
206   }
207   else
208   {
209     /* invalid address */
210     GNUNET_break_op (0);
211     asc (asc_cls, NULL);
212     return;
213   }
214   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
215   ppc->asc = asc;
216   ppc->asc_cls = asc_cls;
217   ppc->port = port;
218   ppc->plugin = cls;
219   GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
220 }
221
222
223
224 /**
225  * Another peer has suggested an address for this
226  * peer and transport plugin.  Check that this could be a valid
227  * address.  If so, consider adding it to the list
228  * of addresses.
229  *
230  * @param cls closure
231  * @param addr pointer to the address
232  * @param addrlen length of addr
233  * @return GNUNET_OK if this is a plausible address for this peer
234  *         and transport
235  */
236 static int
237 http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
238 {
239
240   struct Plugin *plugin = cls;
241   struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head;
242   struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head;
243
244
245
246   GNUNET_assert (cls != NULL);
247   if ((addrlen != sizeof (struct sockaddr_in)) ||
248       (addrlen != sizeof (struct sockaddr_in6)))
249     return GNUNET_SYSERR;
250
251   if (addrlen == sizeof (struct IPv4HttpAddress))
252   {
253     struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr;
254     while (w_tv4 != NULL)
255     {
256       if ((0 == memcmp (&w_tv4->addr.ipv4_addr, &a4->ipv4_addr, sizeof (struct in_addr))) &&
257           (w_tv4->addr.u4_port == a4->u4_port))
258         break;
259       w_tv4 = w_tv4->next;
260     }
261     if (w_tv4 != NULL)
262       return GNUNET_OK;
263     else
264       return GNUNET_SYSERR;
265   }
266   if (addrlen == sizeof (struct sockaddr_in6))
267   {
268     struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr;
269     while (w_tv6 != NULL)
270     {
271       if ((0 == memcmp (&w_tv6->addr6.ipv6_addr, &a6->ipv6_addr, sizeof (struct in6_addr))) &&
272           (w_tv6->addr6.u6_port == a6->u6_port))
273         break;
274       w_tv6 = w_tv6->next;
275     }
276     if (w_tv6 != NULL)
277       return GNUNET_OK;
278     else
279       return GNUNET_SYSERR;
280   }
281   return GNUNET_OK;
282 }
283
284 struct GNUNET_TIME_Relative
285 http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity * peer,
286     const struct  GNUNET_MessageHeader * message,
287     struct Session * session,
288     const char *sender_address,
289     uint16_t sender_address_len)
290 {
291   struct Session *s = cls;
292   struct Plugin *plugin = s->plugin;
293   struct GNUNET_TRANSPORT_ATS_Information distance[2];
294   struct GNUNET_TIME_Relative delay;
295
296   distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
297   distance[0].value = htonl (1);
298   distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
299   distance[1].value = htonl (0);
300
301   delay = plugin->env->receive (plugin->env->cls, &s->target, message, (const struct GNUNET_TRANSPORT_ATS_Information*) &distance, 2, s, s->addr, s->addrlen);
302   return delay;
303 }
304
305 /**
306  * Function called for a quick conversion of the binary address to
307  * a numeric address.  Note that the caller must not free the
308  * address and that the next call to this function is allowed
309  * to override the address again.
310  *
311  * @param cls closure
312  * @param addr binary address
313  * @param addrlen length of the address
314  * @return string representing the same address
315  */
316 const char *
317 http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
318 {
319
320   struct IPv4HttpAddress *a4;
321   struct IPv6HttpAddress *a6;
322   char *address;
323   static char rbuf[INET6_ADDRSTRLEN + 13];
324   uint16_t port;
325   int res = 0;
326
327   if (addrlen == sizeof (struct IPv6HttpAddress))
328   {
329     a6 = (struct IPv6HttpAddress *) addr;
330     address = GNUNET_malloc (INET6_ADDRSTRLEN);
331     GNUNET_assert(NULL != inet_ntop (AF_INET6, &a6->ipv6_addr, address, INET6_ADDRSTRLEN));
332     port = ntohs (a6->u6_port);
333   }
334   else if (addrlen == sizeof (struct IPv4HttpAddress))
335   {
336     a4 = (struct IPv4HttpAddress *) addr;
337     address = GNUNET_malloc (INET_ADDRSTRLEN);
338     GNUNET_assert(NULL != inet_ntop (AF_INET, &(a4->ipv4_addr), address, INET_ADDRSTRLEN));
339     port = ntohs (a4->u4_port);
340   }
341   else
342   {
343     /* invalid address */
344     return NULL;
345   }
346 #if !BUILD_HTTPS  
347   char * protocol = "http";
348 #else
349   char * protocol = "https";
350 #endif
351
352   GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13));
353   if (addrlen == sizeof (struct IPv6HttpAddress))
354     res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, address, port);
355   else if (addrlen == sizeof (struct IPv4HttpAddress))
356     res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, address, port);
357
358   GNUNET_free (address);
359   GNUNET_assert (res != 0);
360   return rbuf;
361 }
362
363 struct Session *
364 lookup_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
365                 struct Session * session,
366                 const void *addr, size_t addrlen, int force_address)
367 {
368   struct Session *s = NULL;
369   struct Session *t = NULL;
370   int e_peer;
371   int e_addr;
372
373   t = plugin->head;
374   if (t == NULL)
375     return NULL;
376   while (t != NULL)
377   {
378 #if 0
379     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
380                      "Comparing peer `%s' address `%s' len %i session %X to \n", GNUNET_i2s(target), GNUNET_a2s(addr,addrlen), addrlen, session);
381     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,"peer `%s' address `%s' len %i session %X \n\n", GNUNET_i2s(&t->target), GNUNET_a2s(t->addr,t->addrlen), t->addrlen, t);
382     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,"memcmp %i \n", memcmp (addr, t->addr, addrlen));
383 #endif
384     e_peer = GNUNET_NO;
385     e_addr = GNUNET_NO;
386
387     if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity)))
388     {
389       e_peer = GNUNET_YES;
390       if (addrlen == t->addrlen)
391       {
392         if (0 == memcmp (addr, t->addr, addrlen))
393         {
394           e_addr = GNUNET_YES;
395         }
396       }
397       if ((t == session))
398       {
399        if(t->addrlen == session->addrlen)
400        {
401         if (0 == memcmp (session->addr, t->addr, t->addrlen))
402         {
403           e_addr = GNUNET_YES;
404         }
405        }
406       }
407     }
408
409     if ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO))
410     {
411       s = t;
412       break;
413     }
414     if ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES))
415     {
416       s = t;
417       break;
418     }
419     if ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR))
420     {
421       s = t;
422       break;
423     }
424     if (s != NULL)
425       break;
426     t = t->next;
427   }
428
429
430   return s;
431 }
432
433 void
434 delete_session (struct Session *s)
435 {
436   if (s->msg_tk != NULL)
437   {
438     GNUNET_SERVER_mst_destroy (s->msg_tk);
439     s->msg_tk = NULL;
440   }
441   GNUNET_free (s->addr);
442   GNUNET_free_non_null(s->server_recv);
443   GNUNET_free_non_null(s->server_send);
444   GNUNET_free (s);
445 }
446
447 struct Session *
448 create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
449                 const void *addr, size_t addrlen,
450                 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
451 {
452   struct Session *s = NULL;
453
454   s = GNUNET_malloc (sizeof (struct Session));
455   memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity));
456   s->plugin = plugin;
457   s->addr = GNUNET_malloc (addrlen);
458   memcpy (s->addr, addr, addrlen);
459   s->addrlen = addrlen;
460   s->next = NULL;
461   s->next_receive = GNUNET_TIME_absolute_get_zero();
462   return s;
463 }
464
465 void
466 notify_session_end (void *cls,
467                     const struct GNUNET_PeerIdentity *
468                     peer, struct Session * s)
469 {
470   struct Plugin *plugin = cls;
471
472   plugin->env->session_end (NULL, peer, s);
473   GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
474   delete_session (s);
475 }
476
477
478 /**
479  * Function that can be used by the transport service to transmit
480  * a message using the plugin.   Note that in the case of a
481  * peer disconnecting, the continuation MUST be called
482  * prior to the disconnect notification itself.  This function
483  * will be called with this peer's HELLO message to initiate
484  * a fresh connection to another peer.
485  *
486  * @param cls closure
487  * @param target who should receive this message
488  * @param msgbuf the message to transmit
489  * @param msgbuf_size number of bytes in 'msgbuf'
490  * @param priority how important is the message (most plugins will
491  *                 ignore message priority and just FIFO)
492  * @param to how long to wait at most for the transmission (does not
493  *                require plugins to discard the message after the timeout,
494  *                just advisory for the desired delay; most plugins will ignore
495  *                this as well)
496  * @param session which session must be used (or NULL for "any")
497  * @param addr the address to use (can be NULL if the plugin
498  *                is "on its own" (i.e. re-use existing TCP connection))
499  * @param addrlen length of the address in bytes
500  * @param force_address GNUNET_YES if the plugin MUST use the given address,
501  *                GNUNET_NO means the plugin may use any other address and
502  *                GNUNET_SYSERR means that only reliable existing
503  *                bi-directional connections should be used (regardless
504  *                of address)
505  * @param cont continuation to call once the message has
506  *        been transmitted (or if the transport is ready
507  *        for the next transmission call; or if the
508  *        peer disconnected...); can be NULL
509  * @param cont_cls closure for cont
510  * @return number of bytes used (on the physical network, with overheads);
511  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
512  *         and does NOT mean that the message was not transmitted (DV)
513  */
514 static ssize_t
515 http_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target,
516                   const char *msgbuf, size_t msgbuf_size, unsigned int priority,
517                   struct GNUNET_TIME_Relative to, struct Session *session,
518                   const void *addr, size_t addrlen, int force_address,
519                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
520 {
521   struct Plugin *plugin = cls;
522   struct HTTP_Message *msg;
523   GNUNET_assert (plugin != NULL);
524
525   int res = GNUNET_SYSERR;
526
527 #if DEBUG_HTTP
528   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
529                    "Sending %u bytes to peer `%s' on address `%s' %X %i\n", msgbuf_size,
530                    GNUNET_i2s (target), ((addr != NULL) && (addrlen != 0)) ? http_plugin_address_to_string(plugin, addr, addrlen) : "<inbound>", session, force_address);
531 #endif
532
533   struct Session *s = NULL;
534
535   /* look for existing connection */
536   s = lookup_session (plugin, target, session, addr, addrlen, 1);
537 #if DEBUG_HTTP
538   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
539                    "%s existing session: %s\n", (s!=NULL) ? "Found" : "NOT Found", ((s != NULL) && (s->inbound == GNUNET_YES)) ? "inbound" : "outbound");
540 #endif
541
542   /* create new outbound connection */
543   if (s == NULL)
544   {
545     if (plugin->max_connections <= plugin->cur_connections)
546     {
547       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
548                        "Maximum number of connections reached, "
549                        "cannot connect to peer `%s'\n",
550                        GNUNET_i2s (target));
551       return res;
552     }
553
554 #if DEBUG_HTTP
555     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
556                      "Initiiating new connection to peer `%s'\n",
557                      GNUNET_i2s (target));
558 #endif
559     s = create_session (plugin, target, addr, addrlen, cont, cont_cls);
560     GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
561     // initiate new connection
562     if (GNUNET_SYSERR == (res = client_connect (s)))
563     {
564       GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
565       delete_session (s);
566       return GNUNET_SYSERR;
567     }
568   }
569
570   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
571   msg->next = NULL;
572   msg->size = msgbuf_size;
573   msg->pos = 0;
574   msg->buf = (char *) &msg[1];
575   msg->transmit_cont = cont;
576   msg->transmit_cont_cls = cont_cls;
577   memcpy (msg->buf, msgbuf, msgbuf_size);
578
579   if (s->inbound == GNUNET_NO)
580   {
581 #if DEBUG_HTTP
582     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
583                      "Using outbound client session to send to `%s'\n",
584                      GNUNET_i2s (target));
585 #endif
586      client_send (s, msg);
587      res = msgbuf_size;
588   }
589   if (s->inbound == GNUNET_YES)
590   {
591     server_send (s, msg);
592     res = msgbuf_size;
593 #if DEBUG_HTTP
594     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
595                      "Using inbound server session to send to `%s'\n",
596                      GNUNET_i2s (target));
597 #endif
598
599   }
600   return res;
601 }
602
603
604 /**
605  * Function that can be used to force the plugin to disconnect
606  * from the given peer and cancel all previous transmissions
607  * (and their continuationc).
608  *
609  * @param cls closure
610  * @param target peer from which to disconnect
611  */
612 static void
613 http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
614 {
615   struct Plugin *plugin = cls;
616   struct Session *next = NULL;
617   struct Session *s = plugin->head;
618
619   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
620                    "Transport tells me to disconnect `%s'\n",
621                    GNUNET_i2s (target));
622   while (s != NULL)
623   {
624     next = s->next;
625     if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity)))
626     {
627       if (s->inbound == GNUNET_NO)
628         GNUNET_assert (GNUNET_OK == client_disconnect (s));
629       else
630         GNUNET_assert (GNUNET_OK == server_disconnect (s));
631       GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
632       delete_session (s);
633     }
634     s = next;
635   }
636 }
637
638 static void
639 nat_add_address (void *cls, int add_remove, const struct sockaddr *addr,
640                  socklen_t addrlen)
641 {
642   struct Plugin *plugin = cls;
643   struct IPv4HttpAddressWrapper *w_t4 = NULL;
644   struct IPv6HttpAddressWrapper *w_t6 = NULL;
645   int af;
646
647   af = addr->sa_family;
648   switch (af)
649   {
650   case AF_INET:
651     w_t4 = plugin->ipv4_addr_head;
652     struct sockaddr_in *a4 = (struct sockaddr_in *) addr;
653     while (w_t4 != NULL)
654     {
655       int res = memcmp (&w_t4->addr.ipv4_addr,
656                         &a4->sin_addr,
657                         sizeof (struct in_addr));
658       if (res == 0)
659       {
660         if (a4->sin_port!= w_t4->addr.u4_port)
661           res = -1;
662       }
663
664       if (0 == res)
665         break;
666       w_t4 = w_t4->next;
667     }
668     if (w_t4 == NULL)
669     {
670       w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper));
671       memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr,
672               sizeof (struct in_addr));
673       w_t4->addr.u4_port = a4->sin_port;
674
675       GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head,
676                                    plugin->ipv4_addr_tail, w_t4);
677     }
678 #if DEBUG_HTTP
679     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
680                      "Notifying transport to add IPv4 address `%s'\n",
681                      http_plugin_address_to_string(NULL, &w_t4->addr, sizeof (struct IPv4HttpAddress)));
682 #endif
683     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, sizeof (struct IPv4HttpAddress));
684
685     break;
686   case AF_INET6:
687     w_t6 = plugin->ipv6_addr_head;
688     struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr;
689     while (w_t6)
690     {
691       int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
692                         sizeof (struct in6_addr));
693       if (res == 0)
694       {
695         if (a6->sin6_port != w_t6->addr6.u6_port)
696           res = -1;
697       }
698       if (0 == res)
699         break;
700       w_t6 = w_t6->next;
701     }
702     if (w_t6 == NULL)
703     {
704       w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper));
705
706       memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
707               sizeof (struct in6_addr));
708       w_t6->addr6.u6_port = a6->sin6_port;
709
710       GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head,
711                                    plugin->ipv6_addr_tail, w_t6);
712     }
713 #if DEBUG_HTTP
714     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
715                      "Notifying transport to add IPv6 address `%s'\n",
716                      http_plugin_address_to_string(NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress)));
717 #endif
718     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, sizeof (struct IPv6HttpAddress));
719     break;
720   default:
721     return;
722   }
723
724 }
725
726 static void
727 nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
728                     socklen_t addrlen)
729 {
730   struct Plugin *plugin = cls;
731   struct IPv4HttpAddressWrapper *w_t4 = NULL;
732   struct IPv6HttpAddressWrapper *w_t6 = NULL;
733   int af;
734
735   af = addr->sa_family;
736   switch (af)
737   {
738   case AF_INET:
739     w_t4 = plugin->ipv4_addr_head;
740     struct sockaddr_in *a4 = (struct sockaddr_in *) addr;
741     while (w_t4 != NULL)
742     {
743       int res = memcmp (&w_t4->addr.ipv4_addr,
744                         &a4->sin_addr,
745                         sizeof (struct in_addr));
746       if (res == 0)
747       {
748         if (a4->sin_port!= w_t4->addr.u4_port)
749           res = -1;
750       }
751
752       if (0 == res)
753         break;
754       w_t4 = w_t4->next;
755     }
756     if (w_t4 == NULL)
757       return;
758
759 #if DEBUG_HTTP
760     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
761                      "Notifying transport to remove IPv4 address `%s'\n",
762                      http_plugin_address_to_string(NULL, &w_t4->addr, sizeof (struct IPv4HttpAddress)));
763 #endif
764     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr,
765                                  sizeof (struct IPv4HttpAddress));
766
767     GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail,
768                                  w_t4);
769     GNUNET_free (w_t4);
770     break;
771   case AF_INET6:
772     w_t6 = plugin->ipv6_addr_head;
773     struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr;
774     while (w_t6)
775     {
776       int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
777                         sizeof (struct in6_addr));
778       if (res == 0)
779       {
780         if (a6->sin6_port != w_t6->addr6.u6_port)
781           res = -1;
782       }
783       if (0 == res)
784         break;
785       w_t6 = w_t6->next;
786     }
787     if (w_t6 == NULL)
788       return;
789 #if DEBUG_HTTP
790     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
791                      "Notifying transport to remove IPv6 address `%s'\n",
792                      http_plugin_address_to_string(NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress)));
793 #endif
794     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6,
795                                  sizeof (struct IPv6HttpAddress));
796
797     GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail,
798                                  w_t6);
799     GNUNET_free (w_t6);
800     break;
801   default:
802     return;
803   }
804
805 }
806
807 /**
808  * Our external IP address/port mapping has changed.
809  *
810  * @param cls closure, the 'struct LocalAddrList'
811  * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
812  *     the previous (now invalid) one
813  * @param addr either the previous or the new public IP address
814  * @param addrlen actual lenght of the address
815  */
816 static void
817 nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
818                        socklen_t addrlen)
819 {
820   GNUNET_assert (cls != NULL);
821 #if DEBUG_HTTP
822   struct Plugin *plugin = cls;
823 #endif
824 #if DEBUG_HTTP
825   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
826                    "NPMC called %s to address `%s'\n",
827                    (add_remove == GNUNET_NO) ? "remove" : "add",
828                    GNUNET_a2s (addr, addrlen));
829 #endif
830   switch (add_remove)
831   {
832   case GNUNET_YES:
833       nat_add_address (cls, add_remove, addr, addrlen);
834     break;
835   case GNUNET_NO:
836     nat_remove_address (cls, add_remove, addr, addrlen);
837     break;
838   }
839 }
840
841 void
842 http_check_ipv6 (struct Plugin *plugin)
843 {
844   struct GNUNET_NETWORK_Handle *desc = NULL;
845   if (plugin->ipv6 == GNUNET_YES)
846   {
847     /* probe IPv6 support */
848     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
849     if (NULL == desc)
850     {
851       if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
852           (errno == EACCES))
853       {
854         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
855       }
856       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
857                   _
858                   ("Disabling IPv6 since it is not supported on this system!\n"));
859       plugin->ipv6 = GNUNET_NO;
860     }
861     else
862     {
863       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
864       desc = NULL;
865     }
866
867   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
868               "Testing IPv6 on this system: %s\n", (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed");
869   }
870 }
871
872 int
873 http_get_addresses (struct Plugin *plugin,
874                     const char *serviceName,
875                     const struct GNUNET_CONFIGURATION_Handle
876                     *cfg, struct sockaddr ***addrs,
877                     socklen_t ** addr_lens)
878 {
879   int disablev6;
880   unsigned long long port;
881   struct addrinfo hints;
882   struct addrinfo *res;
883   struct addrinfo *pos;
884   struct addrinfo *next;
885   unsigned int i;
886   int resi;
887   int ret;
888   struct sockaddr **saddrs;
889   socklen_t *saddrlens;
890   char *hostname;
891
892   *addrs = NULL;
893   *addr_lens = NULL;
894
895   disablev6 = !plugin->ipv6;
896
897   port = 0;
898   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
899   {
900     GNUNET_break (GNUNET_OK ==
901                   GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
902                                                          "PORT", &port));
903     if (port > 65535)
904     {
905       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
906                   _
907                   ("Require valid port number for service in configuration!\n"));
908       return GNUNET_SYSERR;
909     }
910   }
911
912   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
913   {
914     GNUNET_break (GNUNET_OK ==
915                   GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
916                                                          "BINDTO", &hostname));
917   }
918   else
919     hostname = NULL;
920
921   if (hostname != NULL)
922   {
923     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
924                 "Resolving `%s' since that is where `%s' will bind to.\n",
925                 hostname, serviceName);
926     memset (&hints, 0, sizeof (struct addrinfo));
927     if (disablev6)
928       hints.ai_family = AF_INET;
929     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
930         (res == NULL))
931     {
932       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
933                   hostname, gai_strerror (ret));
934       GNUNET_free (hostname);
935       return GNUNET_SYSERR;
936     }
937     next = res;
938     i = 0;
939     while (NULL != (pos = next))
940     {
941       next = pos->ai_next;
942       if ((disablev6) && (pos->ai_family == AF_INET6))
943         continue;
944       i++;
945     }
946     if (0 == i)
947     {
948       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
949                   _("Failed to find %saddress for `%s'.\n"),
950                   disablev6 ? "IPv4 " : "", hostname);
951       freeaddrinfo (res);
952       GNUNET_free (hostname);
953       return GNUNET_SYSERR;
954     }
955     resi = i;
956     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
957     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
958     i = 0;
959     next = res;
960     while (NULL != (pos = next))
961     {
962       next = pos->ai_next;
963       if ((disablev6) && (pos->ai_family == AF_INET6))
964         continue;
965       if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
966         continue;               /* not TCP */
967       if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
968         continue;               /* huh? */
969       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
970                   "Service will bind to `%s'\n",
971                   GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
972       if (pos->ai_family == AF_INET)
973       {
974         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
975         saddrlens[i] = pos->ai_addrlen;
976         saddrs[i] = GNUNET_malloc (saddrlens[i]);
977         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
978         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
979       }
980       else
981       {
982         GNUNET_assert (pos->ai_family == AF_INET6);
983         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
984         saddrlens[i] = pos->ai_addrlen;
985         saddrs[i] = GNUNET_malloc (saddrlens[i]);
986         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
987         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
988       }
989       i++;
990     }
991     GNUNET_free (hostname);
992     freeaddrinfo (res);
993     resi = i;
994   }
995   else
996   {
997     /* will bind against everything, just set port */
998     if (disablev6)
999     {
1000       /* V4-only */
1001       resi = 1;
1002       i = 0;
1003       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1004       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1005
1006       saddrlens[i] = sizeof (struct sockaddr_in);
1007       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1008 #if HAVE_SOCKADDR_IN_SIN_LEN
1009       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1010 #endif
1011       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1012       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1013     }
1014     else
1015     {
1016       /* dual stack */
1017       resi = 2;
1018       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1019       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1020       i = 0;
1021       saddrlens[i] = sizeof (struct sockaddr_in6);
1022       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1023 #if HAVE_SOCKADDR_IN_SIN_LEN
1024       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1025 #endif
1026       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1027       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1028       i++;
1029       saddrlens[i] = sizeof (struct sockaddr_in);
1030       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1031 #if HAVE_SOCKADDR_IN_SIN_LEN
1032       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1033 #endif
1034       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1035       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1036     }
1037   }
1038   *addrs = saddrs;
1039   *addr_lens = saddrlens;
1040   return resi;
1041 }
1042
1043 static void
1044 start_report_addresses (struct Plugin *plugin)
1045 {
1046   int res = GNUNET_OK;
1047   struct sockaddr **addrs;
1048   socklen_t *addrlens;
1049
1050   res =
1051       http_get_addresses (plugin, plugin->name, plugin->env->cfg,
1052                                            &addrs, &addrlens);
1053   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1054                    _("Found %u addresses to report to NAT service\n"),res);
1055
1056   if (res != GNUNET_SYSERR)
1057   {
1058     plugin->nat =
1059         GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
1060                              (unsigned int) res,
1061                              (const struct sockaddr **) addrs, addrlens,
1062                              &nat_port_map_callback, NULL,
1063                              plugin);
1064     while (res > 0)
1065     {
1066       res--;
1067 #if 0
1068       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1069                        _("FREEING %s\n"),
1070                        GNUNET_a2s (addrs[res], addrlens[res]));
1071 #endif
1072       GNUNET_assert (addrs[res] != NULL);
1073       GNUNET_free (addrs[res]);
1074     }
1075     GNUNET_free_non_null (addrs);
1076     GNUNET_free_non_null (addrlens);
1077   }
1078   else
1079   {
1080     plugin->nat =
1081         GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL,
1082                              NULL, NULL, plugin);
1083   }
1084 }
1085
1086 static void
1087 stop_report_addresses (struct Plugin *plugin)
1088 {
1089   /* Stop NAT handle */
1090   GNUNET_NAT_unregister (plugin->nat);
1091
1092   /* Clean up addresses */
1093   struct IPv4HttpAddressWrapper *w_t4;
1094   struct IPv6HttpAddressWrapper *w_t6;
1095
1096   while (plugin->ipv4_addr_head != NULL)
1097   {
1098     w_t4 = plugin->ipv4_addr_head;
1099     GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail,
1100                                  w_t4);
1101     GNUNET_free (w_t4);
1102   }
1103
1104   while (plugin->ipv6_addr_head != NULL)
1105   {
1106     w_t6 = plugin->ipv6_addr_head;
1107     GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail,
1108                                  w_t6);
1109     GNUNET_free (w_t6);
1110   }
1111 }
1112
1113 static int
1114 configure_plugin (struct Plugin *plugin)
1115 {
1116   int res = GNUNET_OK;
1117
1118   /* Use IPv4? */
1119   if (GNUNET_CONFIGURATION_have_value
1120       (plugin->env->cfg, plugin->name, "USE_IPv4"))
1121   {
1122     plugin->ipv4 =
1123         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1124                                               "USE_IPv4");
1125   }
1126   else
1127     plugin->ipv4 = GNUNET_YES;
1128
1129   /* Use IPv6? */
1130   if (GNUNET_CONFIGURATION_have_value
1131       (plugin->env->cfg, plugin->name, "USE_IPv6"))
1132   {
1133     plugin->ipv6 =
1134         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1135                                               "USE_IPv6");
1136   }
1137   else
1138     plugin->ipv6 = GNUNET_YES;
1139
1140   if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO))
1141   {
1142     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1143                      _
1144                      ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
1145                      plugin->name);
1146     res = GNUNET_SYSERR;
1147   }
1148
1149   /* Reading port number from config file */
1150   unsigned long long port;
1151
1152   if ((GNUNET_OK !=
1153        GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1154                                               "PORT", &port)) || (port > 65535))
1155   {
1156     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1157                      _("Port is required! Fix in configuration\n"),
1158                      plugin->name);
1159     res = GNUNET_SYSERR;
1160     goto fail;
1161   }
1162   plugin->port = port;
1163
1164   plugin->client_only = GNUNET_NO;
1165   if (plugin->port == 0)
1166   {
1167     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1168                    _("Port 0, client only mode\n"));
1169     plugin->client_only = GNUNET_YES;
1170   }
1171
1172   char * bind4_address = NULL;
1173   if ((plugin->ipv4 == GNUNET_YES) && (GNUNET_YES ==
1174       GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1175                                              "BINDTO", &bind4_address)))
1176   {
1177     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1178                 "Binding %s plugin to specific IPv4 address: `%s'\n",
1179                 plugin->protocol, bind4_address);
1180     plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
1181     if (1 != inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr))
1182     {
1183       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1184                   _("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
1185                   bind4_address, plugin->protocol);
1186       GNUNET_free (plugin->server_addr_v4);
1187       plugin->server_addr_v4 = NULL;
1188     }
1189     else
1190     {
1191       plugin->server_addr_v4->sin_family = AF_INET;
1192       plugin->server_addr_v4->sin_port = htons (plugin->port);
1193     }
1194     GNUNET_free (bind4_address);
1195   }
1196
1197
1198   char * bind6_address = NULL;
1199   if ((plugin->ipv6 == GNUNET_YES) && (GNUNET_YES ==
1200       GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1201                                              "BINDTO6", &bind6_address)))
1202   {
1203     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1204                 "Binding %s plugin to specific IPv6 address: `%s'\n",
1205                 plugin->protocol, bind6_address);
1206     plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
1207     if (1 != inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
1208     {
1209       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1210                   _("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
1211                   bind6_address, plugin->protocol);
1212       GNUNET_free (plugin->server_addr_v6);
1213       plugin->server_addr_v6 = NULL;
1214     }
1215     else
1216     {
1217       plugin->server_addr_v6->sin6_family = AF_INET6;
1218       plugin->server_addr_v6->sin6_port = htons (plugin->port);
1219     }
1220     GNUNET_free (bind6_address);
1221   }
1222
1223
1224   /* Optional parameters */
1225   unsigned long long maxneigh;
1226   if (GNUNET_OK !=
1227       GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1228                                              "MAX_CONNECTIONS", &maxneigh))
1229     maxneigh = 128;
1230   plugin->max_connections = maxneigh;
1231
1232 fail:
1233   return res;
1234 }
1235
1236 /**
1237  * Entry point for the plugin.
1238  */
1239 void *
1240 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
1241 {
1242   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1243   struct GNUNET_TRANSPORT_PluginFunctions *api;
1244   struct Plugin *plugin;
1245   int res;
1246
1247   plugin = GNUNET_malloc (sizeof (struct Plugin));
1248   plugin->env = env;
1249   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1250   api->cls = plugin;
1251   api->send = &http_plugin_send;
1252   api->disconnect = &http_plugin_disconnect;
1253   api->address_pretty_printer = &http_plugin_address_pretty_printer;
1254   api->check_address = &http_plugin_address_suggested;
1255   api->address_to_string = &http_plugin_address_to_string;
1256
1257 #if BUILD_HTTPS
1258   plugin->name = "transport-https";
1259   plugin->protocol = "https";
1260 #else
1261   plugin->name = "transport-http";
1262   plugin->protocol = "http";
1263 #endif
1264   /* Configure plugin from configuration */
1265   res = configure_plugin (plugin);
1266   if (res == GNUNET_SYSERR)
1267   {
1268     GNUNET_free_non_null (plugin->server_addr_v4);
1269     GNUNET_free_non_null (plugin->server_addr_v6);
1270     GNUNET_free (plugin);
1271     GNUNET_free (api);
1272     return NULL;
1273   }
1274
1275   /* checking IPv6 support */
1276   http_check_ipv6 (plugin);
1277
1278   /* Start client */
1279   res = client_start (plugin);
1280   if (res == GNUNET_SYSERR)
1281   {
1282     GNUNET_free_non_null (plugin->server_addr_v4);
1283     GNUNET_free_non_null (plugin->server_addr_v6);
1284     GNUNET_free (plugin);
1285     GNUNET_free (api);
1286     return NULL;
1287   }
1288
1289   /* Start server */
1290   if (plugin->client_only == GNUNET_NO)
1291   {
1292     res = server_start (plugin);
1293     if (res == GNUNET_SYSERR)
1294     {
1295       server_stop (plugin);
1296       client_stop (plugin);
1297
1298       GNUNET_free_non_null (plugin->server_addr_v4);
1299       GNUNET_free_non_null (plugin->server_addr_v6);
1300       GNUNET_free (plugin);
1301       GNUNET_free (api);
1302       return NULL;
1303     }
1304   }
1305   /* Report addresses to transport service */
1306   start_report_addresses (plugin);
1307
1308 #if DEBUG_HTTP
1309   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1310                    "Plugin `%s' loaded\n", plugin->name);
1311 #endif
1312
1313   return api;
1314 }
1315
1316
1317 /**
1318  * Exit point from the plugin.
1319  */
1320 void *
1321 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
1322 {
1323   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1324   struct Plugin *plugin = api->cls;
1325   struct Session *s = NULL;
1326
1327   /* Stop reporting addresses to transport service */
1328   stop_report_addresses (plugin);
1329
1330   /* cleaning up sessions */
1331   s = plugin->head;
1332   while (s != NULL)
1333   {
1334 #if DEBUG_HTTP
1335   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1336                    "Disconnecting `%s' \n", GNUNET_i2s (&s->target));
1337 #endif
1338     if (s->inbound == GNUNET_NO)
1339       GNUNET_assert (GNUNET_OK == client_disconnect (s));
1340     else
1341       GNUNET_assert (GNUNET_OK == server_disconnect (s));
1342     s = s->next;
1343   }
1344
1345 #if DEBUG_HTTP
1346   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1347                    "Stopping server\n");
1348 #endif
1349   /* Stop server */
1350   server_stop (plugin);
1351
1352 #if DEBUG_HTTP
1353   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1354                    "Stopping client\n");
1355 #endif
1356   /* Stop client */
1357   client_stop (plugin);
1358
1359   /* deleting up sessions */
1360   s = plugin->head;
1361   while (s != NULL)
1362   {
1363     struct Session *t = s->next;
1364     GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
1365     delete_session (s);
1366     s = t;
1367   }
1368
1369
1370 #if DEBUG_HTTP
1371   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1372                    "Plugin `%s' unloaded\n", plugin->name);
1373 #endif
1374
1375   GNUNET_free_non_null (plugin->server_addr_v4);
1376   GNUNET_free_non_null (plugin->server_addr_v6);
1377   GNUNET_free (plugin);
1378   GNUNET_free (api);
1379
1380   return NULL;
1381 }
1382
1383 /* end of plugin_transport_http.c */