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