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