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