implemented session based sending in transport service (coexisting with old code)
[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 outbound 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 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   s->inbound = GNUNET_NO;
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     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
620                      "Cannot connect to peer `%s' address `%s''\n",
621                      http_plugin_address_to_string(NULL, s->addr, s->addrlen),
622                      GNUNET_i2s (&s->target));
623     GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
624     delete_session (s);
625     return NULL;
626   }
627
628   return s;
629 }
630
631 /**
632  * Function that can be used by the transport service to transmit
633  * a message using the plugin.   Note that in the case of a
634  * peer disconnecting, the continuation MUST be called
635  * prior to the disconnect notification itself.  This function
636  * will be called with this peer's HELLO message to initiate
637  * a fresh connection to another peer.
638  *
639  * @param cls closure
640  * @param session which session must be used
641  * @param msgbuf the message to transmit
642  * @param msgbuf_size number of bytes in 'msgbuf'
643  * @param priority how important is the message (most plugins will
644  *                 ignore message priority and just FIFO)
645  * @param to how long to wait at most for the transmission (does not
646  *                require plugins to discard the message after the timeout,
647  *                just advisory for the desired delay; most plugins will ignore
648  *                this as well)
649  * @param cont continuation to call once the message has
650  *        been transmitted (or if the transport is ready
651  *        for the next transmission call; or if the
652  *        peer disconnected...); can be NULL
653  * @param cont_cls closure for cont
654  * @return number of bytes used (on the physical network, with overheads);
655  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
656  *         and does NOT mean that the message was not transmitted (DV)
657  */
658 static ssize_t
659 http_plugin_send (void *cls,
660                   struct Session *session,
661                   const char *msgbuf, size_t msgbuf_size,
662                   unsigned int priority,
663                   struct GNUNET_TIME_Relative to,
664                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
665 {
666   struct Plugin *plugin = cls;
667   struct HTTP_Message *msg;
668   struct Session *tmp;
669   size_t res = -1;
670
671   GNUNET_assert (plugin != NULL);
672   GNUNET_assert (session != NULL);
673
674   /* lookup if session is really existing */
675   tmp = plugin->head;
676   while (tmp != NULL)
677   {
678     if ((tmp == session) &&
679        (0 == memcmp (&session->target, &tmp->target, sizeof (struct GNUNET_PeerIdentity))) &&
680        (session->addrlen == tmp->addrlen) &&
681        (0 == memcmp (session->addr, tmp->addr, tmp->addrlen)))
682       break;
683     tmp = tmp->next;
684   }
685   if (tmp == NULL)
686   {
687     GNUNET_break_op (0);
688     return res;
689   }
690
691   /* create new message and schedule */
692
693   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
694   msg->next = NULL;
695   msg->size = msgbuf_size;
696   msg->pos = 0;
697   msg->buf = (char *) &msg[1];
698   msg->transmit_cont = cont;
699   msg->transmit_cont_cls = cont_cls;
700   memcpy (msg->buf, msgbuf, msgbuf_size);
701
702   if (session->inbound == GNUNET_NO)
703   {
704 #if DEBUG_HTTP
705     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
706                      "Using outbound client session %p to send to `%session'\n", session,
707                      GNUNET_i2s (&session->target));
708 #endif
709
710     client_send (session, msg);
711     res = msgbuf_size;
712   }
713   if (session->inbound == GNUNET_YES)
714   {
715 #if DEBUG_HTTP
716     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
717                      "Using inbound server %p session to send to `%session'\n", session,
718                      GNUNET_i2s (&session->target));
719 #endif
720
721     server_send (session, msg);
722     res = msgbuf_size;
723   }
724   return res;
725
726 }
727
728 /**
729  * Function that can be used by the transport service to transmit
730  * a message using the plugin.   Note that in the case of a
731  * peer disconnecting, the continuation MUST be called
732  * prior to the disconnect notification itself.  This function
733  * will be called with this peer's HELLO message to initiate
734  * a fresh connection to another peer.
735  *
736  * @param cls closure
737  * @param target who should receive this message
738  * @param msgbuf the message to transmit
739  * @param msgbuf_size number of bytes in 'msgbuf'
740  * @param priority how important is the message (most plugins will
741  *                 ignore message priority and just FIFO)
742  * @param to how long to wait at most for the transmission (does not
743  *                require plugins to discard the message after the timeout,
744  *                just advisory for the desired delay; most plugins will ignore
745  *                this as well)
746  * @param session which session must be used (or NULL for "any")
747  * @param addr the address to use (can be NULL if the plugin
748  *                is "on its own" (i.e. re-use existing TCP connection))
749  * @param addrlen length of the address in bytes
750  * @param force_address GNUNET_YES if the plugin MUST use the given address,
751  *                GNUNET_NO means the plugin may use any other address and
752  *                GNUNET_SYSERR means that only reliable existing
753  *                bi-directional connections should be used (regardless
754  *                of address)
755  * @param cont continuation to call once the message has
756  *        been transmitted (or if the transport is ready
757  *        for the next transmission call; or if the
758  *        peer disconnected...); can be NULL
759  * @param cont_cls closure for cont
760  * @return number of bytes used (on the physical network, with overheads);
761  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
762  *         and does NOT mean that the message was not transmitted (DV)
763  */
764 static ssize_t
765 http_plugin_send_old (void *cls, const struct GNUNET_PeerIdentity *target,
766                   const char *msgbuf, size_t msgbuf_size, unsigned int priority,
767                   struct GNUNET_TIME_Relative to, struct Session *session,
768                   const void *addr, size_t addrlen, int force_address,
769                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
770 {
771   struct Plugin *plugin = cls;
772   struct HTTP_Message *msg;
773   struct Session *s;
774
775   GNUNET_assert (plugin != NULL);
776
777   int res = GNUNET_SYSERR;
778
779 #if DEBUG_HTTP
780   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
781                    "Sending %u bytes to peer `%s' on address `%s' %X %i\n",
782                    msgbuf_size, GNUNET_i2s (target), ((addr != NULL) &&
783                                                       (addrlen !=
784                                                        0)) ?
785                    http_plugin_address_to_string (plugin, addr,
786                                                   addrlen) : "<inbound>",
787                    session, force_address);
788 #endif
789
790
791
792   if (addrlen != 0)
793     GNUNET_assert ((addrlen == sizeof (struct IPv4HttpAddress)) ||
794                    (addrlen == sizeof (struct IPv6HttpAddress)));
795   /* look for existing connection */
796   s = lookup_session_old (plugin, target, session, addr, addrlen, 1);
797 #if DEBUG_HTTP
798   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
799                    "%s existing session: %s\n",
800                    (s != NULL) ? "Found" : "NOT Found", ((s != NULL) &&
801                                                          (s->inbound ==
802                                                           GNUNET_YES)) ?
803                    "inbound" : "outbound");
804 #endif
805   /* create new outbound connection */
806   if (s == NULL)
807   {
808     if (plugin->max_connections <= plugin->cur_connections)
809     {
810       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
811                        "Maximum number of connections reached, "
812                        "cannot connect to peer `%s'\n", GNUNET_i2s (target));
813       return res;
814     }
815
816 #if DEBUG_HTTP
817     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
818                      "Initiiating new connection to peer `%s'\n",
819                      GNUNET_i2s (target));
820 #endif
821 /* AAAAAAAAAAAAAAAAAAA */
822     int res = GNUNET_OK;
823     struct GNUNET_ATS_Information ats;
824     if ((addrlen == sizeof (struct IPv4HttpAddress)) && (addr != NULL))
825     {
826       struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr;
827       struct sockaddr_in s4;
828
829       s4.sin_family = AF_INET;
830       s4.sin_addr.s_addr = a4->ipv4_addr;
831       s4.sin_port = a4->u4_port;
832 #if HAVE_SOCKADDR_IN_SIN_LEN
833       s4.sin_len = sizeof (struct sockaddr_in);
834 #endif
835       ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in));
836
837       if ((ntohs (a4->u4_port) == 0) || (plugin->ipv4 == GNUNET_NO))
838         res = GNUNET_SYSERR;
839     }
840     if ((addrlen == sizeof (struct IPv6HttpAddress)) && (addr != NULL))
841     {
842       struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr;
843       struct sockaddr_in6 s6;
844
845       s6.sin6_family = AF_INET6;
846       s6.sin6_addr = a6->ipv6_addr;
847       s6.sin6_port = a6->u6_port;
848 #if HAVE_SOCKADDR_IN_SIN_LEN
849       s6.sin6_len = sizeof (struct sockaddr_in6);
850 #endif
851       ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6));
852
853       if ((ntohs (a6->u6_port) == 0) || (plugin->ipv6 == GNUNET_NO))
854         res = GNUNET_SYSERR;
855     }
856     if (res == GNUNET_OK)
857     {
858       s = create_session (plugin, target, addr, addrlen, cont, cont_cls);
859       s->ats_address_network_type = ats.value;
860       GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
861       // initiate new connection
862       res = client_connect (s);
863     }
864     if (res == GNUNET_SYSERR)
865     {
866       if (s != NULL)
867       {
868         GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
869         delete_session (s);
870       }
871       return GNUNET_SYSERR;
872     }
873   }
874
875   /* real sending */
876
877   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
878   msg->next = NULL;
879   msg->size = msgbuf_size;
880   msg->pos = 0;
881   msg->buf = (char *) &msg[1];
882   msg->transmit_cont = cont;
883   msg->transmit_cont_cls = cont_cls;
884   memcpy (msg->buf, msgbuf, msgbuf_size);
885
886   if (s->inbound == GNUNET_NO)
887   {
888 #if DEBUG_HTTP
889     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
890                      "Using outbound client session %p to send to `%s'\n", s,
891                      GNUNET_i2s (target));
892 #endif
893
894     client_send (s, msg);
895     res = msgbuf_size;
896   }
897   if (s->inbound == GNUNET_YES)
898   {
899 #if DEBUG_HTTP
900     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
901                      "Using inbound server %p session to send to `%s'\n", s,
902                      GNUNET_i2s (target));
903 #endif
904
905     server_send (s, msg);
906     res = msgbuf_size;
907   }
908   return res;
909 }
910
911
912 /**
913  * Function that can be used to force the plugin to disconnect
914  * from the given peer and cancel all previous transmissions
915  * (and their continuationc).
916  *
917  * @param cls closure
918  * @param target peer from which to disconnect
919  */
920 static void
921 http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
922 {
923   struct Plugin *plugin = cls;
924   struct Session *next = NULL;
925   struct Session *s = plugin->head;
926
927   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
928                    "Transport tells me to disconnect `%s'\n",
929                    GNUNET_i2s (target));
930   while (s != NULL)
931   {
932     next = s->next;
933     if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity)))
934     {
935       if (s->inbound == GNUNET_NO)
936         GNUNET_assert (GNUNET_OK == client_disconnect (s));
937       else
938         GNUNET_assert (GNUNET_OK == server_disconnect (s));
939       GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
940
941       struct HTTP_Message *msg = s->msg_head;
942       struct HTTP_Message *tmp = NULL;
943
944       while (msg != NULL)
945       {
946         tmp = msg->next;
947
948         GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
949         if (msg->transmit_cont != NULL)
950         {
951           msg->transmit_cont (msg->transmit_cont_cls, target, GNUNET_SYSERR);
952         }
953         GNUNET_free (msg);
954         msg = tmp;
955       }
956
957       delete_session (s);
958     }
959     s = next;
960   }
961 }
962
963 static void
964 nat_add_address (void *cls, int add_remove, const struct sockaddr *addr,
965                  socklen_t addrlen)
966 {
967   struct Plugin *plugin = cls;
968   struct IPv4HttpAddressWrapper *w_t4 = NULL;
969   struct IPv6HttpAddressWrapper *w_t6 = NULL;
970   int af;
971
972   af = addr->sa_family;
973   switch (af)
974   {
975   case AF_INET:
976     w_t4 = plugin->ipv4_addr_head;
977     struct sockaddr_in *a4 = (struct sockaddr_in *) addr;
978
979     while (w_t4 != NULL)
980     {
981       int res = memcmp (&w_t4->addr.ipv4_addr,
982                         &a4->sin_addr,
983                         sizeof (struct in_addr));
984
985       if (res == 0)
986       {
987         if (a4->sin_port != w_t4->addr.u4_port)
988           res = -1;
989       }
990
991       if (0 == res)
992         break;
993       w_t4 = w_t4->next;
994     }
995     if (w_t4 == NULL)
996     {
997       w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper));
998       memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr));
999       w_t4->addr.u4_port = a4->sin_port;
1000
1001       GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head,
1002                                    plugin->ipv4_addr_tail, w_t4);
1003     }
1004 #if DEBUG_HTTP
1005     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1006                      "Notifying transport to add IPv4 address `%s'\n",
1007                      http_plugin_address_to_string (NULL, &w_t4->addr,
1008                                                     sizeof (struct
1009                                                             IPv4HttpAddress)));
1010 #endif
1011     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr,
1012                                  sizeof (struct IPv4HttpAddress));
1013
1014     break;
1015   case AF_INET6:
1016     w_t6 = plugin->ipv6_addr_head;
1017     struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr;
1018
1019     while (w_t6)
1020     {
1021       int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
1022                         sizeof (struct in6_addr));
1023
1024       if (res == 0)
1025       {
1026         if (a6->sin6_port != w_t6->addr6.u6_port)
1027           res = -1;
1028       }
1029       if (0 == res)
1030         break;
1031       w_t6 = w_t6->next;
1032     }
1033     if (w_t6 == NULL)
1034     {
1035       w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper));
1036
1037       memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr));
1038       w_t6->addr6.u6_port = a6->sin6_port;
1039
1040       GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head,
1041                                    plugin->ipv6_addr_tail, w_t6);
1042     }
1043 #if DEBUG_HTTP
1044     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1045                      "Notifying transport to add IPv6 address `%s'\n",
1046                      http_plugin_address_to_string (NULL, &w_t6->addr6,
1047                                                     sizeof (struct
1048                                                             IPv6HttpAddress)));
1049 #endif
1050     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6,
1051                                  sizeof (struct IPv6HttpAddress));
1052     break;
1053   default:
1054     return;
1055   }
1056
1057 }
1058
1059 static void
1060 nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
1061                     socklen_t addrlen)
1062 {
1063   struct Plugin *plugin = cls;
1064   struct IPv4HttpAddressWrapper *w_t4 = NULL;
1065   struct IPv6HttpAddressWrapper *w_t6 = NULL;
1066   int af;
1067
1068   af = addr->sa_family;
1069   switch (af)
1070   {
1071   case AF_INET:
1072     w_t4 = plugin->ipv4_addr_head;
1073     struct sockaddr_in *a4 = (struct sockaddr_in *) addr;
1074
1075     while (w_t4 != NULL)
1076     {
1077       int res = memcmp (&w_t4->addr.ipv4_addr,
1078                         &a4->sin_addr,
1079                         sizeof (struct in_addr));
1080
1081       if (res == 0)
1082       {
1083         if (a4->sin_port != w_t4->addr.u4_port)
1084           res = -1;
1085       }
1086
1087       if (0 == res)
1088         break;
1089       w_t4 = w_t4->next;
1090     }
1091     if (w_t4 == NULL)
1092       return;
1093
1094 #if DEBUG_HTTP
1095     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1096                      "Notifying transport to remove IPv4 address `%s'\n",
1097                      http_plugin_address_to_string (NULL, &w_t4->addr,
1098                                                     sizeof (struct
1099                                                             IPv4HttpAddress)));
1100 #endif
1101     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr,
1102                                  sizeof (struct IPv4HttpAddress));
1103
1104     GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail,
1105                                  w_t4);
1106     GNUNET_free (w_t4);
1107     break;
1108   case AF_INET6:
1109     w_t6 = plugin->ipv6_addr_head;
1110     struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr;
1111
1112     while (w_t6)
1113     {
1114       int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
1115                         sizeof (struct in6_addr));
1116
1117       if (res == 0)
1118       {
1119         if (a6->sin6_port != w_t6->addr6.u6_port)
1120           res = -1;
1121       }
1122       if (0 == res)
1123         break;
1124       w_t6 = w_t6->next;
1125     }
1126     if (w_t6 == NULL)
1127       return;
1128 #if DEBUG_HTTP
1129     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1130                      "Notifying transport to remove IPv6 address `%s'\n",
1131                      http_plugin_address_to_string (NULL, &w_t6->addr6,
1132                                                     sizeof (struct
1133                                                             IPv6HttpAddress)));
1134 #endif
1135     plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6,
1136                                  sizeof (struct IPv6HttpAddress));
1137
1138     GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail,
1139                                  w_t6);
1140     GNUNET_free (w_t6);
1141     break;
1142   default:
1143     return;
1144   }
1145
1146 }
1147
1148 /**
1149  * Our external IP address/port mapping has changed.
1150  *
1151  * @param cls closure, the 'struct LocalAddrList'
1152  * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
1153  *     the previous (now invalid) one
1154  * @param addr either the previous or the new public IP address
1155  * @param addrlen actual lenght of the address
1156  */
1157 static void
1158 nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
1159                        socklen_t addrlen)
1160 {
1161   GNUNET_assert (cls != NULL);
1162 #if DEBUG_HTTP
1163   struct Plugin *plugin = cls;
1164 #endif
1165 #if DEBUG_HTTP
1166   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1167                    "NPMC called %s to address `%s'\n",
1168                    (add_remove == GNUNET_NO) ? "remove" : "add",
1169                    GNUNET_a2s (addr, addrlen));
1170 #endif
1171   switch (add_remove)
1172   {
1173   case GNUNET_YES:
1174     nat_add_address (cls, add_remove, addr, addrlen);
1175     break;
1176   case GNUNET_NO:
1177     nat_remove_address (cls, add_remove, addr, addrlen);
1178     break;
1179   }
1180 }
1181
1182 void
1183 http_check_ipv6 (struct Plugin *plugin)
1184 {
1185   struct GNUNET_NETWORK_Handle *desc = NULL;
1186
1187   if (plugin->ipv6 == GNUNET_YES)
1188   {
1189     /* probe IPv6 support */
1190     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
1191     if (NULL == desc)
1192     {
1193       if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
1194           (errno == EACCES))
1195       {
1196         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1197       }
1198       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
1199                        _
1200                        ("Disabling IPv6 since it is not supported on this system!\n"));
1201       plugin->ipv6 = GNUNET_NO;
1202     }
1203     else
1204     {
1205       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1206       desc = NULL;
1207     }
1208
1209     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1210                      "Testing IPv6 on this system: %s\n",
1211                      (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed");
1212   }
1213 }
1214
1215 int
1216 http_get_addresses (struct Plugin *plugin, const char *serviceName,
1217                     const struct GNUNET_CONFIGURATION_Handle *cfg,
1218                     struct sockaddr ***addrs, socklen_t ** addr_lens)
1219 {
1220   int disablev6;
1221   unsigned long long port;
1222   struct addrinfo hints;
1223   struct addrinfo *res;
1224   struct addrinfo *pos;
1225   struct addrinfo *next;
1226   unsigned int i;
1227   int resi;
1228   int ret;
1229   struct sockaddr **saddrs;
1230   socklen_t *saddrlens;
1231   char *hostname;
1232
1233   *addrs = NULL;
1234   *addr_lens = NULL;
1235
1236   disablev6 = !plugin->ipv6;
1237
1238   port = 0;
1239   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
1240   {
1241     GNUNET_break (GNUNET_OK ==
1242                   GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
1243                                                          "PORT", &port));
1244     if (port > 65535)
1245     {
1246       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1247                   _
1248                   ("Require valid port number for service in configuration!\n"));
1249       return GNUNET_SYSERR;
1250     }
1251   }
1252
1253   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
1254   {
1255     GNUNET_break (GNUNET_OK ==
1256                   GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
1257                                                          "BINDTO", &hostname));
1258   }
1259   else
1260     hostname = NULL;
1261
1262   if (hostname != NULL)
1263   {
1264     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1265                      "Resolving `%s' since that is where `%s' will bind to.\n",
1266                      hostname, serviceName);
1267     memset (&hints, 0, sizeof (struct addrinfo));
1268     if (disablev6)
1269       hints.ai_family = AF_INET;
1270     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1271         (res == NULL))
1272     {
1273       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
1274                   hostname, gai_strerror (ret));
1275       GNUNET_free (hostname);
1276       return GNUNET_SYSERR;
1277     }
1278     next = res;
1279     i = 0;
1280     while (NULL != (pos = next))
1281     {
1282       next = pos->ai_next;
1283       if ((disablev6) && (pos->ai_family == AF_INET6))
1284         continue;
1285       i++;
1286     }
1287     if (0 == i)
1288     {
1289       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1290                   _("Failed to find %saddress for `%s'.\n"),
1291                   disablev6 ? "IPv4 " : "", hostname);
1292       freeaddrinfo (res);
1293       GNUNET_free (hostname);
1294       return GNUNET_SYSERR;
1295     }
1296     resi = i;
1297     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1298     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1299     i = 0;
1300     next = res;
1301     while (NULL != (pos = next))
1302     {
1303       next = pos->ai_next;
1304       if ((disablev6) && (pos->ai_family == AF_INET6))
1305         continue;
1306       if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
1307         continue;               /* not TCP */
1308       if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
1309         continue;               /* huh? */
1310       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1311                        "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr,
1312                                                                   pos->ai_addrlen));
1313       if (pos->ai_family == AF_INET)
1314       {
1315         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
1316         saddrlens[i] = pos->ai_addrlen;
1317         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1318         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1319         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1320       }
1321       else
1322       {
1323         GNUNET_assert (pos->ai_family == AF_INET6);
1324         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
1325         saddrlens[i] = pos->ai_addrlen;
1326         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1327         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1328         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1329       }
1330       i++;
1331     }
1332     GNUNET_free (hostname);
1333     freeaddrinfo (res);
1334     resi = i;
1335   }
1336   else
1337   {
1338     /* will bind against everything, just set port */
1339     if (disablev6)
1340     {
1341       /* V4-only */
1342       resi = 1;
1343       i = 0;
1344       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1345       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1346
1347       saddrlens[i] = sizeof (struct sockaddr_in);
1348       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1349 #if HAVE_SOCKADDR_IN_SIN_LEN
1350       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1351 #endif
1352       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1353       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1354     }
1355     else
1356     {
1357       /* dual stack */
1358       resi = 2;
1359       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1360       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1361       i = 0;
1362       saddrlens[i] = sizeof (struct sockaddr_in6);
1363       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1364 #if HAVE_SOCKADDR_IN_SIN_LEN
1365       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1366 #endif
1367       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1368       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1369       i++;
1370       saddrlens[i] = sizeof (struct sockaddr_in);
1371       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1372 #if HAVE_SOCKADDR_IN_SIN_LEN
1373       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1374 #endif
1375       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1376       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1377     }
1378   }
1379   *addrs = saddrs;
1380   *addr_lens = saddrlens;
1381   return resi;
1382 }
1383
1384 static void
1385 start_report_addresses (struct Plugin *plugin)
1386 {
1387   int res = GNUNET_OK;
1388   struct sockaddr **addrs;
1389   socklen_t *addrlens;
1390
1391   res =
1392       http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs,
1393                           &addrlens);
1394   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1395                    _("Found %u addresses to report to NAT service\n"), res);
1396
1397   if (res != GNUNET_SYSERR)
1398   {
1399     plugin->nat =
1400         GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
1401                              (unsigned int) res,
1402                              (const struct sockaddr **) addrs, addrlens,
1403                              &nat_port_map_callback, NULL, plugin);
1404     while (res > 0)
1405     {
1406       res--;
1407 #if 0
1408       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("FREEING %s\n"),
1409                        GNUNET_a2s (addrs[res], addrlens[res]));
1410 #endif
1411       GNUNET_assert (addrs[res] != NULL);
1412       GNUNET_free (addrs[res]);
1413     }
1414     GNUNET_free_non_null (addrs);
1415     GNUNET_free_non_null (addrlens);
1416   }
1417   else
1418   {
1419     plugin->nat =
1420         GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL,
1421                              NULL, NULL, plugin);
1422   }
1423 }
1424
1425 static void
1426 stop_report_addresses (struct Plugin *plugin)
1427 {
1428   /* Stop NAT handle */
1429   GNUNET_NAT_unregister (plugin->nat);
1430
1431   /* Clean up addresses */
1432   struct IPv4HttpAddressWrapper *w_t4;
1433   struct IPv6HttpAddressWrapper *w_t6;
1434
1435   while (plugin->ipv4_addr_head != NULL)
1436   {
1437     w_t4 = plugin->ipv4_addr_head;
1438     GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail,
1439                                  w_t4);
1440     GNUNET_free (w_t4);
1441   }
1442
1443   while (plugin->ipv6_addr_head != NULL)
1444   {
1445     w_t6 = plugin->ipv6_addr_head;
1446     GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail,
1447                                  w_t6);
1448     GNUNET_free (w_t6);
1449   }
1450 }
1451
1452 static int
1453 configure_plugin (struct Plugin *plugin)
1454 {
1455   int res = GNUNET_OK;
1456
1457   /* Use IPv4? */
1458   if (GNUNET_CONFIGURATION_have_value
1459       (plugin->env->cfg, plugin->name, "USE_IPv4"))
1460   {
1461     plugin->ipv4 =
1462         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1463                                               "USE_IPv4");
1464   }
1465   else
1466     plugin->ipv4 = GNUNET_YES;
1467
1468   /* Use IPv6? */
1469   if (GNUNET_CONFIGURATION_have_value
1470       (plugin->env->cfg, plugin->name, "USE_IPv6"))
1471   {
1472     plugin->ipv6 =
1473         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1474                                               "USE_IPv6");
1475   }
1476   else
1477     plugin->ipv6 = GNUNET_YES;
1478
1479   if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO))
1480   {
1481     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1482                      _
1483                      ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
1484                      plugin->name);
1485     res = GNUNET_SYSERR;
1486   }
1487
1488   /* Reading port number from config file */
1489   unsigned long long port;
1490
1491   if ((GNUNET_OK !=
1492        GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1493                                               "PORT", &port)) || (port > 65535))
1494   {
1495     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1496                      _("Port is required! Fix in configuration\n"),
1497                      plugin->name);
1498     res = GNUNET_SYSERR;
1499     goto fail;
1500   }
1501   plugin->port = port;
1502
1503   plugin->client_only = GNUNET_NO;
1504   if (plugin->port == 0)
1505   {
1506     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1507                      _("Port 0, client only mode\n"));
1508     plugin->client_only = GNUNET_YES;
1509   }
1510
1511   char *bind4_address = NULL;
1512
1513   if ((plugin->ipv4 == GNUNET_YES) &&
1514       (GNUNET_YES ==
1515        GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1516                                               "BINDTO", &bind4_address)))
1517   {
1518     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1519                      "Binding %s plugin to specific IPv4 address: `%s'\n",
1520                      plugin->protocol, bind4_address);
1521     plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
1522     if (1 !=
1523         inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr))
1524     {
1525       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1526                        _
1527                        ("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
1528                        bind4_address, plugin->protocol);
1529       GNUNET_free (plugin->server_addr_v4);
1530       plugin->server_addr_v4 = NULL;
1531     }
1532     else
1533     {
1534       plugin->server_addr_v4->sin_family = AF_INET;
1535       plugin->server_addr_v4->sin_port = htons (plugin->port);
1536     }
1537     GNUNET_free (bind4_address);
1538   }
1539
1540
1541   char *bind6_address = NULL;
1542
1543   if ((plugin->ipv6 == GNUNET_YES) &&
1544       (GNUNET_YES ==
1545        GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1546                                               "BINDTO6", &bind6_address)))
1547   {
1548     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1549                      "Binding %s plugin to specific IPv6 address: `%s'\n",
1550                      plugin->protocol, bind6_address);
1551     plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
1552     if (1 !=
1553         inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
1554     {
1555       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1556                        _
1557                        ("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
1558                        bind6_address, plugin->protocol);
1559       GNUNET_free (plugin->server_addr_v6);
1560       plugin->server_addr_v6 = NULL;
1561     }
1562     else
1563     {
1564       plugin->server_addr_v6->sin6_family = AF_INET6;
1565       plugin->server_addr_v6->sin6_port = htons (plugin->port);
1566     }
1567     GNUNET_free (bind6_address);
1568   }
1569
1570
1571   /* Optional parameters */
1572   unsigned long long maxneigh;
1573
1574   if (GNUNET_OK !=
1575       GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1576                                              "MAX_CONNECTIONS", &maxneigh))
1577     maxneigh = 128;
1578   plugin->max_connections = maxneigh;
1579
1580 fail:
1581   return res;
1582 }
1583
1584 /**
1585  * Entry point for the plugin.
1586  */
1587 void *
1588 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
1589 {
1590   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1591   struct GNUNET_TRANSPORT_PluginFunctions *api;
1592   struct Plugin *plugin;
1593   int res;
1594
1595   plugin = GNUNET_malloc (sizeof (struct Plugin));
1596   plugin->env = env;
1597   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1598   api->cls = plugin;
1599   api->send = &http_plugin_send_old;
1600   api->disconnect = &http_plugin_disconnect;
1601   api->address_pretty_printer = &http_plugin_address_pretty_printer;
1602   api->check_address = &http_plugin_address_suggested;
1603   api->address_to_string = &http_plugin_address_to_string;
1604   api->get_session = &http_get_session;
1605   api->send_with_session =   &http_plugin_send;
1606
1607 #if BUILD_HTTPS
1608   plugin->name = "transport-https";
1609   plugin->protocol = "https";
1610 #else
1611   plugin->name = "transport-http";
1612   plugin->protocol = "http";
1613 #endif
1614   /* Configure plugin from configuration */
1615   res = configure_plugin (plugin);
1616   if (res == GNUNET_SYSERR)
1617   {
1618     GNUNET_free_non_null (plugin->server_addr_v4);
1619     GNUNET_free_non_null (plugin->server_addr_v6);
1620     GNUNET_free (plugin);
1621     GNUNET_free (api);
1622     return NULL;
1623   }
1624
1625   /* checking IPv6 support */
1626   http_check_ipv6 (plugin);
1627
1628   /* Start client */
1629   res = client_start (plugin);
1630   if (res == GNUNET_SYSERR)
1631   {
1632     GNUNET_free_non_null (plugin->server_addr_v4);
1633     GNUNET_free_non_null (plugin->server_addr_v6);
1634     GNUNET_free (plugin);
1635     GNUNET_free (api);
1636     return NULL;
1637   }
1638
1639   /* Start server */
1640   if (plugin->client_only == GNUNET_NO)
1641   {
1642     res = server_start (plugin);
1643     if (res == GNUNET_SYSERR)
1644     {
1645       server_stop (plugin);
1646       client_stop (plugin);
1647
1648       GNUNET_free_non_null (plugin->server_addr_v4);
1649       GNUNET_free_non_null (plugin->server_addr_v6);
1650       GNUNET_free (plugin);
1651       GNUNET_free (api);
1652       return NULL;
1653     }
1654   }
1655   /* Report addresses to transport service */
1656   start_report_addresses (plugin);
1657
1658 #if DEBUG_HTTP
1659   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1660                    "Plugin `%s' loaded\n", plugin->name);
1661 #endif
1662
1663   return api;
1664 }
1665
1666
1667 /**
1668  * Exit point from the plugin.
1669  */
1670 void *
1671 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
1672 {
1673   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1674   struct Plugin *plugin = api->cls;
1675   struct Session *s = NULL;
1676
1677   /* Stop reporting addresses to transport service */
1678   stop_report_addresses (plugin);
1679
1680   /* cleaning up sessions */
1681   s = plugin->head;
1682   while (s != NULL)
1683   {
1684 #if DEBUG_HTTP
1685     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1686                      "Disconnecting `%s' \n", GNUNET_i2s (&s->target));
1687 #endif
1688     if (s->inbound == GNUNET_NO)
1689       GNUNET_assert (GNUNET_OK == client_disconnect (s));
1690     else
1691       GNUNET_assert (GNUNET_OK == server_disconnect (s));
1692     s = s->next;
1693   }
1694
1695 #if DEBUG_HTTP
1696   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n");
1697 #endif
1698   /* Stop server */
1699   server_stop (plugin);
1700
1701 #if DEBUG_HTTP
1702   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n");
1703 #endif
1704   /* Stop client */
1705   client_stop (plugin);
1706
1707   /* deleting up sessions */
1708   s = plugin->head;
1709   while (s != NULL)
1710   {
1711     struct Session *t = s->next;
1712
1713     GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
1714
1715     struct HTTP_Message *msg = s->msg_head;
1716     struct HTTP_Message *tmp = NULL;
1717
1718     while (msg != NULL)
1719     {
1720       tmp = msg->next;
1721
1722       GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
1723       if (msg->transmit_cont != NULL)
1724       {
1725         msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
1726       }
1727       GNUNET_free (msg);
1728       msg = tmp;
1729     }
1730
1731     delete_session (s);
1732     s = t;
1733   }
1734
1735
1736 #if DEBUG_HTTP
1737   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1738                    "Plugin `%s' unloaded\n", plugin->name);
1739 #endif
1740
1741   GNUNET_free_non_null (plugin->server_addr_v4);
1742   GNUNET_free_non_null (plugin->server_addr_v6);
1743   GNUNET_free (plugin);
1744   GNUNET_free (api);
1745
1746   return NULL;
1747 }
1748
1749 /* end of plugin_transport_http.c */