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