2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file transport/plugin_transport_http.c
23 * @brief http transport service plugin
24 * @author Matthias Wachs
27 #include "plugin_transport_http.h"
30 * After how long do we expire an address that we
31 * learned from another peer if it is not reconfirmed
34 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
38 * Wrapper to manage addresses
40 struct HttpAddressWrapper
45 struct HttpAddressWrapper *next;
48 * Linked list previous
50 struct HttpAddressWrapper *prev;
52 struct HttpAddress *addr;
56 * Context for address to string conversion.
58 struct PrettyPrinterContext
61 * Function to call with the result.
63 GNUNET_TRANSPORT_AddressStringCallback asc;
68 struct Plugin *plugin;
76 * Port to add after the IP address.
87 * Encapsulation of all of the state of the plugin.
92 * Start session timeout
95 start_session_timeout (struct Session *s);
98 * Increment session timeout due to activity
101 reschedule_session_timeout (struct Session *s);
107 stop_session_timeout (struct Session *s);
110 * Convert the transports address to a nice, human-readable
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
124 http_plugin_address_pretty_printer (void *cls, const char *type,
125 const void *addr, size_t addrlen,
127 struct GNUNET_TIME_Relative timeout,
128 GNUNET_TRANSPORT_AddressStringCallback asc,
131 GNUNET_assert (cls != NULL);
132 struct HttpAddress *haddr = (struct HttpAddress *) addr;
134 if (addrlen < (sizeof (struct HttpAddress)))
136 /* invalid address */
141 asc (asc_cls, haddr->addr);
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
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
159 http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
161 struct Plugin *plugin = cls;
162 struct HttpAddressWrapper *w = plugin->addr_head;
163 struct HttpAddress *haddr = (struct HttpAddress *) addr;
165 GNUNET_assert (cls != NULL);
167 if (addrlen <= sizeof (struct HttpAddress))
168 return GNUNET_SYSERR;
170 if (0 == (strcmp (plugin->ext_addr->addr, haddr->addr)))
175 if (0 == (strcmp (w->addr->addr, haddr->addr)))
179 return GNUNET_SYSERR;
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)
188 struct Session *s = cls;
189 struct Plugin *plugin = s->plugin;
190 struct GNUNET_TIME_Relative delay;
191 struct GNUNET_ATS_Information atsi;
193 atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE);
194 atsi.value = session->ats_address_network_type;
195 GNUNET_break (session->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED));
197 reschedule_session_timeout (session);
200 plugin->env->receive (plugin->env->cls, &s->target, message,
202 1, s, s->addr, s->addrlen);
208 * Function called to convert a string address to
211 * @param cls closure ('struct Plugin*')
212 * @param addr string address
213 * @param addrlen length of the address
214 * @param buf location to store the buffer
215 * If the function returns GNUNET_SYSERR, its contents are undefined.
216 * @param added length of created address
217 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
220 http_string_to_address (void *cls,
228 char *protocol = "http";
230 char *protocol = "https";
232 char *addr_str = NULL;
233 struct sockaddr_in addr_4;
234 struct sockaddr_in6 addr_6;
235 struct IPv4HttpAddress * http_4addr;
236 struct IPv6HttpAddress * http_6addr;
238 if ((NULL == addr) || (addrlen == 0))
241 return GNUNET_SYSERR;
244 if ('\0' != addr[addrlen - 1])
247 return GNUNET_SYSERR;
250 if (strlen (addr) != addrlen - 1)
253 return GNUNET_SYSERR;
256 /* protocoll + "://" + ":" */
257 if (addrlen <= (strlen (protocol) + 4))
259 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
260 "Invalid address string `%s' to convert to address\n",
263 return GNUNET_SYSERR;
266 if (NULL == (addr_str = strstr(addr, "://")))
268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
269 "Invalid address string `%s' to convert to address\n",
272 return GNUNET_SYSERR;
274 addr_str = &addr_str[3];
276 if (addr_str[strlen(addr_str)-1] == '/')
277 addr_str[strlen(addr_str)-1] = '\0';
279 if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv4(addr_str, strlen(addr_str), &addr_4))
281 http_4addr = GNUNET_malloc (sizeof (struct IPv4HttpAddress));
282 http_4addr->u4_port = addr_4.sin_port;
283 http_4addr->ipv4_addr = (uint32_t) addr_4.sin_addr.s_addr;
285 (*added) = sizeof (struct IPv4HttpAddress);
288 if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv6(addr_str, strlen(addr_str), &addr_6))
290 http_6addr = GNUNET_malloc (sizeof (struct IPv6HttpAddress));
291 http_6addr->u6_port = addr_6.sin6_port;
292 http_6addr->ipv6_addr = addr_6.sin6_addr;
294 (*added) = sizeof (struct IPv6HttpAddress);
297 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
298 "Invalid address string `%s' to convert to address\n",
301 return GNUNET_SYSERR;
307 * Function called for a quick conversion of the binary address to
308 * a numeric address. Note that the caller must not free the
309 * address and that the next call to this function is allowed
310 * to override the address again.
313 * @param addr binary address
314 * @param addrlen length of the address
315 * @return string representing the same address
318 http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
320 struct HttpAddress *haddr;
321 if (addrlen < sizeof (struct HttpAddress))
323 /* invalid address */
329 haddr = (struct HttpAddress *) addr;
330 GNUNET_assert (NULL != haddr->addr);
331 return (const char *) haddr->addr;
337 lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
338 struct Session *session, const void *addr, size_t addrlen,
345 for (t = plugin->head; NULL != t; t = t->next)
348 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
349 "Comparing peer `%s' address `%s' len %i session %p to \n",
350 GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen,
352 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
353 "peer `%s' address `%s' len %i session %p \n\n",
354 GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen),
356 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n",
357 memcmp (addr, t->addr, addrlen));
361 if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity)))
364 if ( (addrlen == t->addrlen) &&
365 (0 == memcmp (addr, t->addr, addrlen)) )
367 if ( (t == session) &&
368 (t->addrlen == session->addrlen) &&
369 (0 == memcmp (session->addr, t->addr, t->addrlen)) )
373 if ( ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) ||
374 ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) ||
375 ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) )
383 lookup_session (struct Plugin *plugin,
384 const struct GNUNET_HELLO_Address *address)
388 for (pos = plugin->head; NULL != pos; pos = pos->next)
389 if ( (0 == memcmp (&address->peer, &pos->target, sizeof (struct GNUNET_PeerIdentity))) &&
390 (address->address_length == pos->addrlen) &&
391 (0 == memcmp (address->address, pos->addr, pos->addrlen)) )
398 exist_session (struct Plugin *plugin, struct Session *s)
400 struct Session * head;
402 GNUNET_assert (NULL != plugin);
403 GNUNET_assert (NULL != s);
405 for (head = plugin->head; head != NULL; head = head->next)
414 * Deleting the session
415 * Must not be used afterwards
419 delete_session (struct Session *s)
421 struct Plugin *plugin = s->plugin;
422 stop_session_timeout(s);
424 GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
425 struct HTTP_Message *msg = s->msg_head;
426 struct HTTP_Message *tmp = NULL;
432 GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
433 if (msg->transmit_cont != NULL)
435 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
441 if (s->msg_tk != NULL)
443 GNUNET_SERVER_mst_destroy (s->msg_tk);
446 GNUNET_free (s->addr);
447 GNUNET_free_non_null (s->server_recv);
448 GNUNET_free_non_null (s->server_send);
454 create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
455 const void *addr, size_t addrlen)
457 struct Session *s = NULL;
458 struct GNUNET_ATS_Information ats;
461 * ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6));
463 if (addrlen < sizeof (struct HttpAddress))
471 s = GNUNET_malloc (sizeof (struct Session));
472 memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity));
474 s->addr = GNUNET_malloc (addrlen);
475 memcpy (s->addr, addr, addrlen);
476 s->addrlen = addrlen;
477 s->ats_address_network_type = ats.value;
480 start_session_timeout(s);
486 notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
489 struct Plugin *plugin = cls;
491 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
492 "Notifying transport about ending session %p (`%s')\n",
494 http_plugin_address_to_string(NULL, s->addr,s->addrlen));
496 plugin->env->session_end (plugin->env->cls, peer, s);
502 * Creates a new outbound session the transport service will use to send data to the
505 * @param cls the plugin
506 * @param address the address
507 * @return the session or NULL of max connections exceeded
509 static struct Session *
510 http_get_session (void *cls,
511 const struct GNUNET_HELLO_Address *address)
513 struct Plugin *plugin = cls;
514 struct Session * s = NULL;
517 GNUNET_assert (plugin != NULL);
518 GNUNET_assert (address != NULL);
519 GNUNET_assert (address->address != NULL);
521 /* find existing session */
522 s = lookup_session (plugin, address);
526 if (plugin->max_connections <= plugin->cur_connections)
528 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
529 "Maximum number of connections reached, "
530 "cannot connect to peer `%s'\n", GNUNET_i2s (&address->peer));
534 /* create new session */
535 addrlen = address->address_length;
537 GNUNET_assert (addrlen > sizeof (struct HttpAddress));
539 s = create_session (plugin, &address->peer, address->address, address->address_length);
541 /* add new session */
542 GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
543 /* initiate new connection */
544 if (GNUNET_SYSERR == client_connect (s))
546 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
547 "Cannot connect to peer `%s' address `%s''\n",
548 http_plugin_address_to_string(NULL, s->addr, s->addrlen),
549 GNUNET_i2s (&s->target));
550 GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
560 * Function that can be used by the transport service to transmit
561 * a message using the plugin. Note that in the case of a
562 * peer disconnecting, the continuation MUST be called
563 * prior to the disconnect notification itself. This function
564 * will be called with this peer's HELLO message to initiate
565 * a fresh connection to another peer.
568 * @param session which session must be used
569 * @param msgbuf the message to transmit
570 * @param msgbuf_size number of bytes in 'msgbuf'
571 * @param priority how important is the message (most plugins will
572 * ignore message priority and just FIFO)
573 * @param to how long to wait at most for the transmission (does not
574 * require plugins to discard the message after the timeout,
575 * just advisory for the desired delay; most plugins will ignore
577 * @param cont continuation to call once the message has
578 * been transmitted (or if the transport is ready
579 * for the next transmission call; or if the
580 * peer disconnected...); can be NULL
581 * @param cont_cls closure for cont
582 * @return number of bytes used (on the physical network, with overheads);
583 * -1 on hard errors (i.e. address invalid); 0 is a legal value
584 * and does NOT mean that the message was not transmitted (DV)
587 http_plugin_send (void *cls,
588 struct Session *session,
589 const char *msgbuf, size_t msgbuf_size,
590 unsigned int priority,
591 struct GNUNET_TIME_Relative to,
592 GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
594 struct Plugin *plugin = cls;
595 struct HTTP_Message *msg;
599 GNUNET_assert (plugin != NULL);
600 GNUNET_assert (session != NULL);
602 /* lookup if session is really existing */
606 if ((tmp == session) &&
607 (0 == memcmp (&session->target, &tmp->target, sizeof (struct GNUNET_PeerIdentity))) &&
608 (session->addrlen == tmp->addrlen) &&
609 (0 == memcmp (session->addr, tmp->addr, tmp->addrlen)))
619 /* create new message and schedule */
620 msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
622 msg->size = msgbuf_size;
624 msg->buf = (char *) &msg[1];
625 msg->transmit_cont = cont;
626 msg->transmit_cont_cls = cont_cls;
627 memcpy (msg->buf, msgbuf, msgbuf_size);
629 reschedule_session_timeout (session);
631 if (session->inbound == GNUNET_NO)
633 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
634 "Using outbound client session %p to send to `%s'\n", session,
635 GNUNET_i2s (&session->target));
636 client_send (session, msg);
639 if (session->inbound == GNUNET_YES)
641 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
642 "Using inbound server %p session to send to `%s'\n", session,
643 GNUNET_i2s (&session->target));
644 server_send (session, msg);
653 * Function that can be used to force the plugin to disconnect
654 * from the given peer and cancel all previous transmissions
655 * (and their continuationc).
658 * @param target peer from which to disconnect
661 http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
663 struct Plugin *plugin = cls;
664 struct Session *next = NULL;
665 struct Session *s = plugin->head;
667 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
668 "Transport tells me to disconnect `%s'\n",
669 GNUNET_i2s (target));
673 if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity)))
675 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
676 "Disconnecting %s session %p to `%s'\n",
677 (s->inbound == GNUNET_NO) ? "outbound" : "inbound",
678 s, GNUNET_i2s (target));
680 if (s->inbound == GNUNET_NO)
681 GNUNET_assert (GNUNET_OK == client_disconnect (s));
683 GNUNET_assert (GNUNET_OK == server_disconnect (s));
691 find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen)
693 struct HttpAddressWrapper *w = NULL;
696 GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen));
697 w = plugin->addr_head;
700 if (0 == strcmp (saddr, w->addr->addr))
713 nat_add_address (void *cls, int add_remove, const struct sockaddr *addr,
716 struct Plugin *plugin = cls;
717 struct HttpAddressWrapper *w = NULL;
721 GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen));
723 haddrlen = sizeof (struct HttpAddress) + strlen(saddr) + 1;
724 w = GNUNET_malloc (sizeof (struct HttpAddressWrapper));
725 w->addr = GNUNET_malloc (haddrlen);
726 w->addr->addr = &w->addr[1];
727 w->addr->addr_len = htonl (strlen(saddr) + 1);
728 memcpy (w->addr->addr, saddr, strlen(saddr) + 1);
731 GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w);
732 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
733 "Notifying transport to add address `%s'\n", w->addr->addr);
735 plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, haddrlen, "http");
740 nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
743 struct Plugin *plugin = cls;
744 struct HttpAddressWrapper *w = NULL;
747 w = find_address (plugin, addr, addrlen);
751 haddrlen = sizeof (struct HttpAddress) + ntohl (w->addr->addr_len);
752 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
753 "Notifying transport to remove address `%s'\n", http_plugin_address_to_string(NULL, w->addr, haddrlen));
756 GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
757 plugin->env->notify_address (plugin->env->cls, add_remove, w->addr,
758 sizeof (struct HttpAddress) + ntohl (w->addr->addr_len), "http");
759 GNUNET_free (w->addr);
765 * Our external IP address/port mapping has changed.
767 * @param cls closure, the 'struct LocalAddrList'
768 * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
769 * the previous (now invalid) one
770 * @param addr either the previous or the new public IP address
771 * @param addrlen actual lenght of the address
774 nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
777 GNUNET_assert (cls != NULL);
778 struct Plugin *plugin = cls;
780 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
781 "NPMC called %s to address `%s'\n",
782 (add_remove == GNUNET_NO) ? "remove" : "add",
783 GNUNET_a2s (addr, addrlen));
788 nat_add_address (cls, add_remove, addr, addrlen);
791 nat_remove_address (cls, add_remove, addr, addrlen);
798 http_check_ipv6 (struct Plugin *plugin)
800 struct GNUNET_NETWORK_Handle *desc = NULL;
802 if (plugin->ipv6 == GNUNET_YES)
804 /* probe IPv6 support */
805 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
808 if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
811 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
813 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
815 ("Disabling IPv6 since it is not supported on this system!\n"));
816 plugin->ipv6 = GNUNET_NO;
820 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
824 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
825 "Testing IPv6 on this system: %s\n",
826 (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed");
832 http_get_addresses (struct Plugin *plugin, const char *service_name,
833 const struct GNUNET_CONFIGURATION_Handle *cfg,
834 struct sockaddr ***addrs, socklen_t ** addr_lens)
837 unsigned long long port;
838 struct addrinfo hints;
839 struct addrinfo *res;
840 struct addrinfo *pos;
841 struct addrinfo *next;
845 struct sockaddr **saddrs;
846 socklen_t *saddrlens;
852 disablev6 = !plugin->ipv6;
855 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
857 GNUNET_break (GNUNET_OK ==
858 GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
862 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
864 ("Require valid port number for service in configuration!\n"));
865 return GNUNET_SYSERR;
870 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, plugin->name,
871 "Starting in listen only mode\n");
872 return -1; /* listen only */
876 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
878 GNUNET_break (GNUNET_OK ==
879 GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
880 "BINDTO", &hostname));
885 if (hostname != NULL)
887 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
888 "Resolving `%s' since that is where `%s' will bind to.\n",
889 hostname, service_name);
890 memset (&hints, 0, sizeof (struct addrinfo));
892 hints.ai_family = AF_INET;
893 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
896 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
897 hostname, gai_strerror (ret));
898 GNUNET_free (hostname);
899 return GNUNET_SYSERR;
903 while (NULL != (pos = next))
906 if ((disablev6) && (pos->ai_family == AF_INET6))
912 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
913 _("Failed to find %saddress for `%s'.\n"),
914 disablev6 ? "IPv4 " : "", hostname);
916 GNUNET_free (hostname);
917 return GNUNET_SYSERR;
920 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
921 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
924 while (NULL != (pos = next))
927 if ((disablev6) && (pos->ai_family == AF_INET6))
929 if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
930 continue; /* not TCP */
931 if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
933 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
934 "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr,
936 if (pos->ai_family == AF_INET)
938 GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
939 saddrlens[i] = pos->ai_addrlen;
940 saddrs[i] = GNUNET_malloc (saddrlens[i]);
941 memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
942 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
946 GNUNET_assert (pos->ai_family == AF_INET6);
947 GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
948 saddrlens[i] = pos->ai_addrlen;
949 saddrs[i] = GNUNET_malloc (saddrlens[i]);
950 memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
951 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
955 GNUNET_free (hostname);
961 /* will bind against everything, just set port */
967 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
968 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
970 saddrlens[i] = sizeof (struct sockaddr_in);
971 saddrs[i] = GNUNET_malloc (saddrlens[i]);
972 #if HAVE_SOCKADDR_IN_SIN_LEN
973 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
975 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
976 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
982 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
983 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
985 saddrlens[i] = sizeof (struct sockaddr_in6);
986 saddrs[i] = GNUNET_malloc (saddrlens[i]);
987 #if HAVE_SOCKADDR_IN_SIN_LEN
988 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
990 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
991 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
993 saddrlens[i] = sizeof (struct sockaddr_in);
994 saddrs[i] = GNUNET_malloc (saddrlens[i]);
995 #if HAVE_SOCKADDR_IN_SIN_LEN
996 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
998 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
999 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1003 *addr_lens = saddrlens;
1008 start_report_addresses (struct Plugin *plugin)
1010 int res = GNUNET_OK;
1011 struct sockaddr **addrs;
1012 socklen_t *addrlens;
1015 http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs,
1017 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1018 _("Found %u addresses to report to NAT service\n"), res);
1020 if (GNUNET_SYSERR == res)
1027 GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
1029 (const struct sockaddr **) addrs, addrlens,
1030 &nat_port_map_callback, NULL, plugin);
1034 GNUNET_assert (addrs[res] != NULL);
1035 GNUNET_free (addrs[res]);
1037 GNUNET_free_non_null (addrs);
1038 GNUNET_free_non_null (addrlens);
1043 stop_report_addresses (struct Plugin *plugin)
1046 /* Stop NAT handle */
1047 if (NULL != plugin->nat)
1048 GNUNET_NAT_unregister (plugin->nat);
1050 /* Clean up addresses */
1051 struct HttpAddressWrapper *w;
1053 while (plugin->addr_head != NULL)
1055 w = plugin->addr_head;
1056 GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
1057 GNUNET_free (w->addr);
1063 * Function called when the service shuts down. Unloads our plugins
1064 * and cancels pending validations.
1066 * @param cls closure, unused
1067 * @param tc task context (unused)
1070 notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1072 struct Plugin *plugin = cls;
1073 struct HttpAddress *eaddr;
1078 plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
1080 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1083 GNUNET_asprintf(&addr, "%s://%s", plugin->protocol, plugin->external_hostname);
1084 uri_len = strlen (addr) + 1;
1085 eaddr_len = sizeof (struct HttpAddress) + uri_len;
1086 eaddr = GNUNET_malloc (eaddr_len);
1087 eaddr->addr_len = htonl (uri_len);
1088 eaddr->addr = (void *) &eaddr[1];
1089 memcpy (&eaddr->addr, addr, uri_len);
1090 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1091 "Notifying transport about external hostname address `%s'\n", addr);
1094 plugin->env->notify_address (plugin->env->cls, GNUNET_YES, eaddr, eaddr_len, "http");
1095 plugin->ext_addr = eaddr;
1096 plugin->ext_addr_len = eaddr_len;
1101 configure_plugin (struct Plugin *plugin)
1103 int res = GNUNET_OK;
1106 if (GNUNET_CONFIGURATION_have_value
1107 (plugin->env->cfg, plugin->name, "USE_IPv4"))
1110 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1114 plugin->ipv4 = GNUNET_YES;
1117 if (GNUNET_CONFIGURATION_have_value
1118 (plugin->env->cfg, plugin->name, "USE_IPv6"))
1121 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1125 plugin->ipv6 = GNUNET_YES;
1127 if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO))
1129 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1131 ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
1133 res = GNUNET_SYSERR;
1136 /* Reading port number from config file */
1137 unsigned long long port;
1140 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1141 "PORT", &port)) || (port > 65535))
1143 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1144 _("Port is required! Fix in configuration\n"),
1146 res = GNUNET_SYSERR;
1149 plugin->port = port;
1151 plugin->client_only = GNUNET_NO;
1152 if (plugin->port == 0)
1154 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1155 _("Port 0, client only mode\n"));
1156 plugin->client_only = GNUNET_YES;
1159 char *bind4_address = NULL;
1161 if ((plugin->ipv4 == GNUNET_YES) &&
1163 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1164 "BINDTO", &bind4_address)))
1166 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1167 "Binding %s plugin to specific IPv4 address: `%s'\n",
1168 plugin->protocol, bind4_address);
1169 plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
1171 inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr))
1173 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1175 ("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
1176 bind4_address, plugin->protocol);
1177 GNUNET_free (plugin->server_addr_v4);
1178 plugin->server_addr_v4 = NULL;
1182 plugin->server_addr_v4->sin_family = AF_INET;
1183 plugin->server_addr_v4->sin_port = htons (plugin->port);
1185 GNUNET_free (bind4_address);
1188 char *bind6_address = NULL;
1190 if ((plugin->ipv6 == GNUNET_YES) &&
1192 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1193 "BINDTO6", &bind6_address)))
1195 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1196 "Binding %s plugin to specific IPv6 address: `%s'\n",
1197 plugin->protocol, bind6_address);
1198 plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
1200 inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
1202 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1204 ("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
1205 bind6_address, plugin->protocol);
1206 GNUNET_free (plugin->server_addr_v6);
1207 plugin->server_addr_v6 = NULL;
1211 plugin->server_addr_v6->sin6_family = AF_INET6;
1212 plugin->server_addr_v6->sin6_port = htons (plugin->port);
1214 GNUNET_free (bind6_address);
1217 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1218 "EXTERNAL_HOSTNAME", &plugin->external_hostname))
1220 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1221 _("Using external hostname `%s'\n"), plugin->external_hostname);
1222 plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (¬ify_external_hostname, plugin);
1225 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1226 _("No external hostname configured\n"));
1229 /* Optional parameters */
1230 unsigned long long maxneigh;
1233 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1234 "MAX_CONNECTIONS", &maxneigh))
1236 plugin->max_connections = maxneigh;
1242 #define TESTING GNUNET_NO
1245 #define TIMEOUT_LOG GNUNET_ERROR_TYPE_ERROR
1246 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
1248 #define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG
1249 #define TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
1254 * Session was idle, so disconnect it
1257 session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1259 GNUNET_assert (NULL != cls);
1260 struct Session *s = cls;
1262 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1263 GNUNET_log (TIMEOUT_LOG,
1264 "Session %p was idle for %s, disconnecting\n",
1266 GNUNET_STRINGS_relative_time_to_string (TIMEOUT,
1269 /* call session destroy function */
1270 if (s->inbound == GNUNET_NO)
1271 GNUNET_assert (GNUNET_OK == client_disconnect (s));
1273 GNUNET_assert (GNUNET_OK == server_disconnect (s));
1278 * Start session timeout
1281 start_session_timeout (struct Session *s)
1283 GNUNET_assert (NULL != s);
1284 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
1285 s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
1288 GNUNET_log (TIMEOUT_LOG,
1289 "Timeout for session %p set to %s\n",
1291 GNUNET_STRINGS_relative_time_to_string (TIMEOUT,
1297 * Increment session timeout due to activity
1300 reschedule_session_timeout (struct Session *s)
1302 GNUNET_assert (NULL != s);
1303 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
1305 GNUNET_SCHEDULER_cancel (s->timeout_task);
1306 s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
1309 GNUNET_log (TIMEOUT_LOG,
1310 "Timeout rescheduled for session %p set to %s\n",
1312 GNUNET_STRINGS_relative_time_to_String (TIMEOUT,
1321 stop_session_timeout (struct Session *s)
1323 GNUNET_assert (NULL != s);
1325 if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
1327 GNUNET_SCHEDULER_cancel (s->timeout_task);
1328 s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1329 GNUNET_log (TIMEOUT_LOG,
1330 "Timeout stopped for session %p\n",
1336 * Entry point for the plugin.
1339 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
1341 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1342 struct GNUNET_TRANSPORT_PluginFunctions *api;
1343 struct Plugin *plugin;
1346 if (NULL == env->receive)
1348 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
1349 initialze the plugin or the API */
1350 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1352 api->address_pretty_printer = &http_plugin_address_pretty_printer;
1353 api->address_to_string = &http_plugin_address_to_string;
1354 api->string_to_address = &http_string_to_address;
1358 plugin = GNUNET_malloc (sizeof (struct Plugin));
1360 plugin->outbound_sessions = 0;
1361 plugin->inbound_sessions = 0;
1362 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1364 api->disconnect = &http_plugin_disconnect;
1365 api->address_pretty_printer = &http_plugin_address_pretty_printer;
1366 api->check_address = &http_plugin_address_suggested;
1367 api->address_to_string = &http_plugin_address_to_string;
1368 api->string_to_address = &http_string_to_address;
1369 api->get_session = &http_get_session;
1370 api->send = &http_plugin_send;
1373 plugin->name = "transport-https";
1374 plugin->protocol = "https";
1376 plugin->name = "transport-http";
1377 plugin->protocol = "http";
1379 /* Configure plugin from configuration */
1380 res = configure_plugin (plugin);
1381 if (res == GNUNET_SYSERR)
1383 GNUNET_free_non_null (plugin->server_addr_v4);
1384 GNUNET_free_non_null (plugin->server_addr_v6);
1385 GNUNET_free (plugin);
1390 /* checking IPv6 support */
1391 http_check_ipv6 (plugin);
1394 res = client_start (plugin);
1395 if (res == GNUNET_SYSERR)
1397 GNUNET_free_non_null (plugin->server_addr_v4);
1398 GNUNET_free_non_null (plugin->server_addr_v6);
1399 GNUNET_free (plugin);
1405 if (plugin->client_only == GNUNET_NO)
1407 res = server_start (plugin);
1408 if (res == GNUNET_SYSERR)
1410 server_stop (plugin);
1411 client_stop (plugin);
1413 GNUNET_free_non_null (plugin->server_addr_v4);
1414 GNUNET_free_non_null (plugin->server_addr_v6);
1415 GNUNET_free (plugin);
1420 /* Report addresses to transport service */
1421 start_report_addresses (plugin);
1423 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1424 "Plugin `%s' loaded\n", plugin->name);
1430 * Exit point from the plugin.
1433 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
1435 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1436 struct Plugin *plugin = api->cls;
1438 struct Session *next;
1446 if (GNUNET_SCHEDULER_NO_TASK != plugin->notify_ext_task)
1448 GNUNET_SCHEDULER_cancel (plugin->notify_ext_task);
1449 plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
1452 if (NULL != plugin->ext_addr)
1454 plugin->env->notify_address (plugin->env->cls, GNUNET_NO, plugin->ext_addr, plugin->ext_addr_len, "http");
1455 GNUNET_free (plugin->ext_addr);
1458 /* Stop reporting addresses to transport service */
1459 stop_report_addresses (plugin);
1461 /* cleaning up sessions */
1466 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1467 "Disconnecting `%s' \n", GNUNET_i2s (&s->target));
1468 if (s->inbound == GNUNET_NO)
1469 GNUNET_assert (GNUNET_OK == client_disconnect (s));
1471 GNUNET_assert (GNUNET_OK == server_disconnect (s));
1475 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n");
1477 server_stop (plugin);
1479 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n");
1481 client_stop (plugin);
1483 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1484 "Plugin `%s' unloaded\n", plugin->name);
1485 GNUNET_free_non_null (plugin->server_addr_v4);
1486 GNUNET_free_non_null (plugin->server_addr_v6);
1487 GNUNET_free_non_null (plugin->external_hostname);
1488 GNUNET_free (plugin);
1493 /* end of plugin_transport_http.c */