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