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