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[2];
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));
199 reschedule_session_timeout (session);
202 plugin->env->receive (plugin->env->cls, &s->target, message,
203 (const struct GNUNET_ATS_Information *) &atsi,
204 2, s, s->addr, s->addrlen);
210 * Function called to convert a string address to
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
222 http_string_to_address (void *cls,
230 char *protocol = "http";
232 char *protocol = "https";
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;
240 if ((NULL == addr) || (addrlen == 0))
243 return GNUNET_SYSERR;
246 if ('\0' != addr[addrlen - 1])
249 return GNUNET_SYSERR;
252 if (strlen (addr) != addrlen - 1)
255 return GNUNET_SYSERR;
258 /* protocoll + "://" + ":" */
259 if (addrlen <= (strlen (protocol) + 4))
261 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
262 "Invalid address string `%s' to convert to address\n",
265 return GNUNET_SYSERR;
268 if (NULL == (addr_str = strstr(addr, "://")))
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
271 "Invalid address string `%s' to convert to address\n",
274 return GNUNET_SYSERR;
276 addr_str = &addr_str[3];
278 if (addr_str[strlen(addr_str)-1] == '/')
279 addr_str[strlen(addr_str)-1] = '\0';
281 if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv4(addr_str, strlen(addr_str), &addr_4))
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;
287 (*added) = sizeof (struct IPv4HttpAddress);
290 if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv6(addr_str, strlen(addr_str), &addr_6))
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;
296 (*added) = sizeof (struct IPv6HttpAddress);
299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
300 "Invalid address string `%s' to convert to address\n",
303 return GNUNET_SYSERR;
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.
315 * @param addr binary address
316 * @param addrlen length of the address
317 * @return string representing the same address
320 http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
322 struct HttpAddress *haddr;
323 if (addrlen < sizeof (struct HttpAddress))
325 /* invalid address */
331 haddr = (struct HttpAddress *) addr;
332 GNUNET_assert (NULL != haddr->addr);
333 return (const char *) haddr->addr;
339 lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
340 struct Session *session, const void *addr, size_t addrlen,
347 for (t = plugin->head; NULL != t; t = t->next)
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,
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),
358 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n",
359 memcmp (addr, t->addr, addrlen));
363 if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity)))
366 if ( (addrlen == t->addrlen) &&
367 (0 == memcmp (addr, t->addr, addrlen)) )
369 if ( (t == session) &&
370 (t->addrlen == session->addrlen) &&
371 (0 == memcmp (session->addr, t->addr, t->addrlen)) )
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)) )
385 lookup_session (struct Plugin *plugin,
386 const struct GNUNET_HELLO_Address *address)
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)) )
400 exist_session (struct Plugin *plugin, struct Session *s)
402 struct Session * head;
404 GNUNET_assert (NULL != plugin);
405 GNUNET_assert (NULL != s);
407 for (head = plugin->head; head != NULL; head = head->next)
416 * Deleting the session
417 * Must not be used afterwards
421 delete_session (struct Session *s)
423 struct Plugin *plugin = s->plugin;
424 stop_session_timeout(s);
426 GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
427 struct HTTP_Message *msg = s->msg_head;
428 struct HTTP_Message *tmp = NULL;
434 GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
435 if (msg->transmit_cont != NULL)
437 msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
443 if (s->msg_tk != NULL)
445 GNUNET_SERVER_mst_destroy (s->msg_tk);
448 GNUNET_free (s->addr);
449 GNUNET_free_non_null (s->server_recv);
450 GNUNET_free_non_null (s->server_send);
456 create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
457 const void *addr, size_t addrlen)
459 struct Session *s = NULL;
460 struct GNUNET_ATS_Information ats;
463 * ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6));
465 if (addrlen < sizeof (struct HttpAddress))
473 s = GNUNET_malloc (sizeof (struct Session));
474 memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity));
476 s->addr = GNUNET_malloc (addrlen);
477 memcpy (s->addr, addr, addrlen);
478 s->addrlen = addrlen;
479 s->ats_address_network_type = ats.value;
482 start_session_timeout(s);
488 notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
491 struct Plugin *plugin = cls;
493 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
494 "Notifying transport about ending session %p (`%s')\n",
496 http_plugin_address_to_string(NULL, s->addr,s->addrlen));
498 plugin->env->session_end (plugin->env->cls, peer, s);
504 * Creates a new outbound session the transport service will use to send data to the
507 * @param cls the plugin
508 * @param address the address
509 * @return the session or NULL of max connections exceeded
511 static struct Session *
512 http_get_session (void *cls,
513 const struct GNUNET_HELLO_Address *address)
515 struct Plugin *plugin = cls;
516 struct Session * s = NULL;
519 GNUNET_assert (plugin != NULL);
520 GNUNET_assert (address != NULL);
521 GNUNET_assert (address->address != NULL);
523 /* find existing session */
524 s = lookup_session (plugin, address);
528 if (plugin->max_connections <= plugin->cur_connections)
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));
536 /* create new session */
537 addrlen = address->address_length;
539 GNUNET_assert (addrlen > sizeof (struct HttpAddress));
541 s = create_session (plugin, &address->peer, address->address, address->address_length);
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))
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);
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.
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
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)
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)
596 struct Plugin *plugin = cls;
597 struct HTTP_Message *msg;
601 GNUNET_assert (plugin != NULL);
602 GNUNET_assert (session != NULL);
604 /* lookup if session is really existing */
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)))
621 /* create new message and schedule */
622 msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
624 msg->size = msgbuf_size;
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);
631 reschedule_session_timeout (session);
633 if (session->inbound == GNUNET_NO)
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);
641 if (session->inbound == GNUNET_YES)
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);
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).
660 * @param target peer from which to disconnect
663 http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
665 struct Plugin *plugin = cls;
666 struct Session *next = NULL;
667 struct Session *s = plugin->head;
669 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
670 "Transport tells me to disconnect `%s'\n",
671 GNUNET_i2s (target));
675 if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity)))
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));
682 if (s->inbound == GNUNET_NO)
683 GNUNET_assert (GNUNET_OK == client_disconnect (s));
685 GNUNET_assert (GNUNET_OK == server_disconnect (s));
693 find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen)
695 struct HttpAddressWrapper *w = NULL;
698 GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen));
699 w = plugin->addr_head;
702 if (0 == strcmp (saddr, w->addr->addr))
715 nat_add_address (void *cls, int add_remove, const struct sockaddr *addr,
718 struct Plugin *plugin = cls;
719 struct HttpAddressWrapper *w = NULL;
723 GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen));
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);
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);
737 plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, haddrlen, "http");
742 nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
745 struct Plugin *plugin = cls;
746 struct HttpAddressWrapper *w = NULL;
749 w = find_address (plugin, addr, addrlen);
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));
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);
767 * Our external IP address/port mapping has changed.
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
776 nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
779 GNUNET_assert (cls != NULL);
780 struct Plugin *plugin = cls;
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));
790 nat_add_address (cls, add_remove, addr, addrlen);
793 nat_remove_address (cls, add_remove, addr, addrlen);
800 http_check_ipv6 (struct Plugin *plugin)
802 struct GNUNET_NETWORK_Handle *desc = NULL;
804 if (plugin->ipv6 == GNUNET_YES)
806 /* probe IPv6 support */
807 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
810 if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
813 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
815 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
817 ("Disabling IPv6 since it is not supported on this system!\n"));
818 plugin->ipv6 = GNUNET_NO;
822 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
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");
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)
839 unsigned long long port;
840 struct addrinfo hints;
841 struct addrinfo *res;
842 struct addrinfo *pos;
843 struct addrinfo *next;
847 struct sockaddr **saddrs;
848 socklen_t *saddrlens;
854 disablev6 = !plugin->ipv6;
857 if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
859 GNUNET_break (GNUNET_OK ==
860 GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
864 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866 ("Require valid port number for service in configuration!\n"));
867 return GNUNET_SYSERR;
872 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, plugin->name,
873 "Starting in listen only mode\n");
874 return -1; /* listen only */
878 if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
880 GNUNET_break (GNUNET_OK ==
881 GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
882 "BINDTO", &hostname));
887 if (hostname != NULL)
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));
894 hints.ai_family = AF_INET;
895 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
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;
905 while (NULL != (pos = next))
908 if ((disablev6) && (pos->ai_family == AF_INET6))
914 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915 _("Failed to find %saddress for `%s'.\n"),
916 disablev6 ? "IPv4 " : "", hostname);
918 GNUNET_free (hostname);
919 return GNUNET_SYSERR;
922 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
923 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
926 while (NULL != (pos = next))
929 if ((disablev6) && (pos->ai_family == AF_INET6))
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))
935 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
936 "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr,
938 if (pos->ai_family == AF_INET)
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);
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);
957 GNUNET_free (hostname);
963 /* will bind against everything, just set port */
969 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
970 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
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];
977 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
978 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
984 saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
985 saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
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];
992 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
993 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
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];
1000 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1001 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1005 *addr_lens = saddrlens;
1010 start_report_addresses (struct Plugin *plugin)
1012 int res = GNUNET_OK;
1013 struct sockaddr **addrs;
1014 socklen_t *addrlens;
1017 http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs,
1019 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1020 _("Found %u addresses to report to NAT service\n"), res);
1022 if (GNUNET_SYSERR == res)
1029 GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
1031 (const struct sockaddr **) addrs, addrlens,
1032 &nat_port_map_callback, NULL, plugin);
1036 GNUNET_assert (addrs[res] != NULL);
1037 GNUNET_free (addrs[res]);
1039 GNUNET_free_non_null (addrs);
1040 GNUNET_free_non_null (addrlens);
1045 stop_report_addresses (struct Plugin *plugin)
1048 /* Stop NAT handle */
1049 if (NULL != plugin->nat)
1050 GNUNET_NAT_unregister (plugin->nat);
1052 /* Clean up addresses */
1053 struct HttpAddressWrapper *w;
1055 while (plugin->addr_head != NULL)
1057 w = plugin->addr_head;
1058 GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
1059 GNUNET_free (w->addr);
1065 * Function called when the service shuts down. Unloads our plugins
1066 * and cancels pending validations.
1068 * @param cls closure, unused
1069 * @param tc task context (unused)
1072 notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1074 struct Plugin *plugin = cls;
1075 struct HttpAddress *eaddr;
1080 plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
1082 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
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);
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;
1103 configure_plugin (struct Plugin *plugin)
1105 int res = GNUNET_OK;
1108 if (GNUNET_CONFIGURATION_have_value
1109 (plugin->env->cfg, plugin->name, "USE_IPv4"))
1112 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1116 plugin->ipv4 = GNUNET_YES;
1119 if (GNUNET_CONFIGURATION_have_value
1120 (plugin->env->cfg, plugin->name, "USE_IPv6"))
1123 GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
1127 plugin->ipv6 = GNUNET_YES;
1129 if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO))
1131 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1133 ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
1135 res = GNUNET_SYSERR;
1138 /* Reading port number from config file */
1139 unsigned long long port;
1142 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1143 "PORT", &port)) || (port > 65535))
1145 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1146 _("Port is required! Fix in configuration\n"),
1148 res = GNUNET_SYSERR;
1151 plugin->port = port;
1153 plugin->client_only = GNUNET_NO;
1154 if (plugin->port == 0)
1156 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1157 _("Port 0, client only mode\n"));
1158 plugin->client_only = GNUNET_YES;
1161 char *bind4_address = NULL;
1163 if ((plugin->ipv4 == GNUNET_YES) &&
1165 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1166 "BINDTO", &bind4_address)))
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));
1173 inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr))
1175 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
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;
1184 plugin->server_addr_v4->sin_family = AF_INET;
1185 plugin->server_addr_v4->sin_port = htons (plugin->port);
1187 GNUNET_free (bind4_address);
1190 char *bind6_address = NULL;
1192 if ((plugin->ipv6 == GNUNET_YES) &&
1194 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1195 "BINDTO6", &bind6_address)))
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));
1202 inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
1204 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
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;
1213 plugin->server_addr_v6->sin6_family = AF_INET6;
1214 plugin->server_addr_v6->sin6_port = htons (plugin->port);
1216 GNUNET_free (bind6_address);
1219 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
1220 "EXTERNAL_HOSTNAME", &plugin->external_hostname))
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 (¬ify_external_hostname, plugin);
1227 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1228 _("No external hostname configured\n"));
1231 /* Optional parameters */
1232 unsigned long long maxneigh;
1235 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
1236 "MAX_CONNECTIONS", &maxneigh))
1238 plugin->max_connections = maxneigh;
1244 #define TESTING GNUNET_NO
1247 #define TIMEOUT_LOG GNUNET_ERROR_TYPE_ERROR
1248 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
1250 #define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG
1251 #define TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
1256 * Session was idle, so disconnect it
1259 session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1261 GNUNET_assert (NULL != cls);
1262 struct Session *s = cls;
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);
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 %llu ms\n",
1290 s, (unsigned long long) TIMEOUT.rel_value);
1295 * Increment session timeout due to activity
1298 reschedule_session_timeout (struct Session *s)
1300 GNUNET_assert (NULL != s);
1301 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
1303 GNUNET_SCHEDULER_cancel (s->timeout_task);
1304 s->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
1307 GNUNET_log (TIMEOUT_LOG,
1308 "Timeout rescheduled for session %p set to %llu ms\n",
1309 s, (unsigned long long) TIMEOUT.rel_value);
1317 stop_session_timeout (struct Session *s)
1319 GNUNET_assert (NULL != s);
1321 if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
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",
1332 * Entry point for the plugin.
1335 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
1337 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1338 struct GNUNET_TRANSPORT_PluginFunctions *api;
1339 struct Plugin *plugin;
1342 if (NULL == env->receive)
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));
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;
1354 plugin = GNUNET_malloc (sizeof (struct Plugin));
1356 plugin->outbound_sessions = 0;
1357 plugin->inbound_sessions = 0;
1358 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
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;
1369 plugin->name = "transport-https";
1370 plugin->protocol = "https";
1372 plugin->name = "transport-http";
1373 plugin->protocol = "http";
1375 /* Configure plugin from configuration */
1376 res = configure_plugin (plugin);
1377 if (res == GNUNET_SYSERR)
1379 GNUNET_free_non_null (plugin->server_addr_v4);
1380 GNUNET_free_non_null (plugin->server_addr_v6);
1381 GNUNET_free (plugin);
1386 /* checking IPv6 support */
1387 http_check_ipv6 (plugin);
1390 res = client_start (plugin);
1391 if (res == GNUNET_SYSERR)
1393 GNUNET_free_non_null (plugin->server_addr_v4);
1394 GNUNET_free_non_null (plugin->server_addr_v6);
1395 GNUNET_free (plugin);
1401 if (plugin->client_only == GNUNET_NO)
1403 res = server_start (plugin);
1404 if (res == GNUNET_SYSERR)
1406 server_stop (plugin);
1407 client_stop (plugin);
1409 GNUNET_free_non_null (plugin->server_addr_v4);
1410 GNUNET_free_non_null (plugin->server_addr_v6);
1411 GNUNET_free (plugin);
1416 /* Report addresses to transport service */
1417 start_report_addresses (plugin);
1419 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1420 "Plugin `%s' loaded\n", plugin->name);
1426 * Exit point from the plugin.
1429 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
1431 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1432 struct Plugin *plugin = api->cls;
1434 struct Session *next;
1442 if (GNUNET_SCHEDULER_NO_TASK != plugin->notify_ext_task)
1444 GNUNET_SCHEDULER_cancel (plugin->notify_ext_task);
1445 plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
1448 if (NULL != plugin->ext_addr)
1450 plugin->env->notify_address (plugin->env->cls, GNUNET_NO, plugin->ext_addr, plugin->ext_addr_len, "http");
1451 GNUNET_free (plugin->ext_addr);
1454 /* Stop reporting addresses to transport service */
1455 stop_report_addresses (plugin);
1457 /* cleaning up sessions */
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));
1467 GNUNET_assert (GNUNET_OK == server_disconnect (s));
1471 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n");
1473 server_stop (plugin);
1475 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n");
1477 client_stop (plugin);
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);
1489 /* end of plugin_transport_http.c */