From f078bf6f9b737e52d3fb7f944be0d0b600686e64 Mon Sep 17 00:00:00 2001 From: Matthias Wachs Date: Wed, 14 Sep 2011 16:46:38 +0000 Subject: [PATCH] http plugin revisited --- src/transport/plugin_transport_http.h | 245 +++++ src/transport/plugin_transport_http_client.c | 236 +++++ src/transport/plugin_transport_http_new.c | 963 +++++++++++++++++++ src/transport/plugin_transport_http_server.c | 374 +++++++ 4 files changed, 1818 insertions(+) create mode 100644 src/transport/plugin_transport_http.h create mode 100644 src/transport/plugin_transport_http_client.c create mode 100644 src/transport/plugin_transport_http_new.c create mode 100644 src/transport/plugin_transport_http_server.c diff --git a/src/transport/plugin_transport_http.h b/src/transport/plugin_transport_http.h new file mode 100644 index 000000000..84af33a59 --- /dev/null +++ b/src/transport/plugin_transport_http.h @@ -0,0 +1,245 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http.h + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_connection_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet_resolver_service.h" +#include "gnunet_server_lib.h" +#include "gnunet_container_lib.h" +#include "gnunet_transport_plugin.h" +#include "gnunet_os_lib.h" +#include "gnunet_nat_lib.h" +#include "microhttpd.h" +#include + + +#define DEBUG_HTTP GNUNET_YES +#define VERBOSE_SERVER GNUNET_YES +#define VERBOSE_CLIENT GNUNET_YES + +#if BUILD_HTTPS +#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init +#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done +#else +#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init +#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done +#endif + + +#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * List of open sessions. + */ + struct Session *head; + + struct Session *tail; + + /** + * NAT handle & address management + */ + struct GNUNET_NAT_Handle *nat; + + /** + * ipv4 DLL head + */ + struct IPv4HttpAddressWrapper *ipv4_addr_head; + + /** + * ipv4 DLL tail + */ + struct IPv4HttpAddressWrapper *ipv4_addr_tail; + + /** + * ipv6 DLL head + */ + struct IPv6HttpAddressWrapper *ipv6_addr_head; + + /** + * ipv6 DLL tail + */ + struct IPv6HttpAddressWrapper *ipv6_addr_tail; + + + /* Plugin configuration */ + + char *name; + + char *protocol; + + int ipv4; + + int ipv6; + + uint16_t port; + + int max_connections; + + /* + * Server handles + */ + + struct MHD_Daemon *server_v4; + + struct MHD_Daemon *server_v6; + + char *crypto_init; + char *key; + char *cert; + + /* + * Client handles + */ + + /** + * cURL Multihandle + */ + CURLM *client_mh; + +}; + +/** + * Session handle for connections. + */ +struct Session +{ + + /** + * Stored in a linked list. + */ + struct Session *next; + + /** + * Stored in a linked list. + */ + struct Session *prev; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * The client (used to identify this connection) + */ + /* void *client; */ + + /** + * Continuation function to call once the transmission buffer + * has again space available. NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + + void *addr; + + size_t addrlen; + + /** + * Closure for transmit_cont. + */ + void *transmit_cont_cls; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity target; + + /** + * At what time did we reset last_received last? + */ + //struct GNUNET_TIME_Absolute last_quota_update; + + /** + * How many bytes have we received since the "last_quota_update" + * timestamp? + */ + //uint64_t last_received; + + /** + * Number of bytes per ms that this peer is allowed + * to send to us. + */ + //uint32_t quota; + + + int inbound; + + void *client_put; + void *client_get; + + +}; + +const char * +http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen); + +int +client_disconnect (struct Session *s); + +int +client_connect (struct Session *s); + +int +client_send (struct Session *s, const char *msgbuf, size_t msgbuf_size); + +int +client_start (struct Plugin *plugin); + +void +client_stop (struct Plugin *plugin); + +int +server_disconnect (struct Session *s); + +int +server_send (struct Session *s, const char *msgbuf, size_t msgbuf_size); + +int +server_start (struct Plugin *plugin); + +void +server_stop (struct Plugin *plugin); + +/* end of plugin_transport_http.h */ diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c new file mode 100644 index 000000000..9a5d4b261 --- /dev/null +++ b/src/transport/plugin_transport_http_client.c @@ -0,0 +1,236 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http_client.c + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "plugin_transport_http.h" + +#if VERBOSE_CLIENT +/** + * Function to log curl debug messages with GNUNET_log + * @param curl handle + * @param type curl_infotype + * @param data data + * @param size size + * @param cls closure + * @return 0 + */ +static int +client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) +{ + if (type == CURLINFO_TEXT) + { + char text[size + 2]; + + memcpy (text, data, size); + if (text[size - 1] == '\n') + text[size] = '\0'; + else + { + text[size] = '\n'; + text[size + 1] = '\0'; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client: %X - %s", cls, text); + } + return 0; +} +#endif + +int +client_disconnect (struct Session *s) +{ + int res = GNUNET_OK; + CURLMcode mret; + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, s->plugin->name, + "Deleting outbound session peer `%s'\n", + GNUNET_i2s (&s->target)); +#endif + + mret = curl_multi_remove_handle (s->plugin->client_mh, s->client_put); + if (mret != CURLM_OK) + { + curl_easy_cleanup (s->client_put); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + curl_easy_cleanup (s->client_put); + + mret = curl_multi_remove_handle (s->plugin->client_mh, s->client_get); + if (mret != CURLM_OK) + { + curl_easy_cleanup (s->client_get); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + curl_easy_cleanup (s->client_get); + + return res; +} + +int +client_send (struct Session *s, const char *msgbuf, size_t msgbuf_size) +{ + return GNUNET_OK; +} + +int +client_connect (struct Session *s) +{ + int res = GNUNET_OK; + char *url; + CURLMcode mret; + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, s->plugin->name, + "Initiating outbound session peer `%s'\n", + GNUNET_i2s (&s->target)); +#endif + + s->inbound = GNUNET_NO; + + /* create url */ + GNUNET_asprintf (&url, "%s://%s/", s->plugin->protocol, + http_plugin_address_to_string (NULL, s->addr, s->addrlen)); + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, s->plugin->name, "URL `%s'\n", url); +#endif + + /* create get connection */ + s->client_get = curl_easy_init (); +#if VERBOSE_CLIENT + curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); + curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); +#endif +#if BUILD_HTTPS + curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); +#endif + curl_easy_setopt (s->client_get, CURLOPT_URL, url); + //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); + //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); + //curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, curl_send_cb); + //curl_easy_setopt (s->client_get, CURLOPT_READDATA, ps); + //curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, curl_receive_cb); + //curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, ps); + curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT, + (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + //curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, ps); + curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT, + (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); + curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, + 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); +#if CURL_TCP_NODELAY + curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); +#endif + + /* create put connection */ + s->client_put = curl_easy_init (); +#if VERBOSE_CLIENT + curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); + curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); +#endif +#if BUILD_HTTPS + curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); +#endif + curl_easy_setopt (s->client_put, CURLOPT_URL, url); + curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); + //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); + //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); + //curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, curl_send_cb); + //curl_easy_setopt (s->client_put, CURLOPT_READDATA, ps); + //curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, curl_receive_cb); + //curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, ps); + curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT, + (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); + //curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, ps); + curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT, + (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); + curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, + 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); +#if CURL_TCP_NODELAY + curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); +#endif + + GNUNET_free (url); + + mret = curl_multi_add_handle (s->plugin->client_mh, s->client_get); + if (mret != CURLM_OK) + { + curl_easy_cleanup (s->client_get); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + + mret = curl_multi_add_handle (s->plugin->client_mh, s->client_put); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (s->plugin->client_mh, s->client_get); + curl_easy_cleanup (s->client_get); + curl_easy_cleanup (s->client_put); + res = GNUNET_SYSERR; + GNUNET_break (0); + } + + /* Perform connect */ + + return res; +} + +int +client_start (struct Plugin *plugin) +{ + int res = GNUNET_OK; + + curl_global_init (CURL_GLOBAL_ALL); + plugin->client_mh = curl_multi_init (); + + if (NULL == plugin->client_mh) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Could not initialize curl multi handle, failed to start %s plugin!\n"), + plugin->name); + res = GNUNET_SYSERR; + } + return res; +} + +void +client_stop (struct Plugin *plugin) +{ + curl_multi_cleanup (plugin->client_mh); + curl_global_cleanup (); +} + + + +/* end of plugin_transport_http_client.c */ diff --git a/src/transport/plugin_transport_http_new.c b/src/transport/plugin_transport_http_new.c new file mode 100644 index 000000000..3ad7dbac4 --- /dev/null +++ b/src/transport/plugin_transport_http_new.c @@ -0,0 +1,963 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http.c + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "plugin_transport_http.h" + +/** + * After how long do we expire an address that we + * learned from another peer if it is not reconfirmed + * by anyone? + */ +#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) + +/** + * Network format for IPv4 addresses. + */ +struct IPv4HttpAddress +{ + /** + * IPv4 address, in network byte order. + */ + uint32_t ipv4_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t port GNUNET_PACKED; +}; + +/** + * Wrapper to manage IPv4 addresses + */ +struct IPv4HttpAddressWrapper +{ + /** + * Linked list next + */ + struct IPv4HttpAddressWrapper *next; + + /** + * Linked list previous + */ + struct IPv4HttpAddressWrapper *prev; + + struct IPv4HttpAddress *addr; +}; + +/** + * Network format for IPv6 addresses. + */ +struct IPv6HttpAddress +{ + /** + * IPv6 address. + */ + struct in6_addr ipv6_addr GNUNET_PACKED; + + /** + * Port number, in network byte order. + */ + uint16_t port GNUNET_PACKED; + +}; + +/** + * Wrapper for IPv4 addresses. + */ +struct IPv6HttpAddressWrapper +{ + /** + * Linked list next + */ + struct IPv6HttpAddressWrapper *next; + + /** + * Linked list previous + */ + struct IPv6HttpAddressWrapper *prev; + + struct IPv6HttpAddress *addr; +}; + + +/** + * Context for address to string conversion. + */ +struct PrettyPrinterContext +{ + /** + * Function to call with the result. + */ + GNUNET_TRANSPORT_AddressStringCallback asc; + + /** + * Plugin + */ + struct Plugin *plugin; + + /** + * Clsoure for 'asc'. + */ + void *asc_cls; + + /** + * Port to add after the IP address. + */ + uint16_t port; +}; + + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin; + + + +/** + * Append our port and forward the result. + * + * @param cls the 'struct PrettyPrinterContext*' + * @param hostname hostname part of the address + */ +static void +append_port (void *cls, const char *hostname) +{ + struct PrettyPrinterContext *ppc = cls; + char *ret; + + if (hostname == NULL) + { + ppc->asc (ppc->asc_cls, NULL); + GNUNET_free (ppc); + return; + } + GNUNET_asprintf (&ret, "%s://%s:%d", ppc->plugin->protocol, hostname, + ppc->plugin->port); + ppc->asc (ppc->asc_cls, ret); + GNUNET_free (ret); +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +http_plugin_address_pretty_printer (void *cls, const char *type, + const void *addr, size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback asc, + void *asc_cls) +{ + GNUNET_assert (cls != NULL); + struct PrettyPrinterContext *ppc; + const void *sb; + size_t sbs; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4HttpAddress *t4; + const struct IPv6HttpAddress *t6; + uint16_t port; + + if (addrlen == sizeof (struct IPv6HttpAddress)) + { + t6 = addr; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->port; + memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); + port = ntohs (t6->port); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4HttpAddress)) + { + t4 = addr; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->port; + a4.sin_addr.s_addr = t4->ipv4_addr; + port = ntohs (t4->ipv4_addr); + sb = &a4; + sbs = sizeof (a4); + } + else + { + /* invalid address */ + GNUNET_break_op (0); + asc (asc_cls, NULL); + return; + } + ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); + ppc->asc = asc; + ppc->asc_cls = asc_cls; + ppc->port = port; + ppc->plugin = cls; + GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); +} + + + +/** + * Another peer has suggested an address for this + * peer and transport plugin. Check that this could be a valid + * address. If so, consider adding it to the list + * of addresses. + * + * @param cls closure + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport + */ +static int +http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4HttpAddress *v4; + struct IPv6HttpAddress *v6; + struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; + struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; + + GNUNET_assert (cls != NULL); + if ((addrlen != sizeof (struct IPv4HttpAddress)) && + (addrlen != sizeof (struct IPv6HttpAddress))) + return GNUNET_SYSERR; + if (addrlen == sizeof (struct IPv4HttpAddress)) + { + v4 = (struct IPv4HttpAddress *) addr; + while (w_tv4 != NULL) + { + if (0 == + memcmp (&w_tv4->addr->ipv4_addr, &v4->ipv4_addr, sizeof (uint32_t))) + break; + w_tv4 = w_tv4->next; + } + if (w_tv4 != NULL) + return GNUNET_OK; + else + return GNUNET_SYSERR; + } + if (addrlen == sizeof (struct IPv6HttpAddress)) + { + v6 = (struct IPv6HttpAddress *) addr; + while (w_tv6 != NULL) + { + if (0 == + memcmp (&w_tv6->addr->ipv6_addr, &v6->ipv6_addr, + sizeof (struct in6_addr))) + break; + w_tv6 = w_tv6->next; + } + if (w_tv6 != NULL) + return GNUNET_OK; + else + return GNUNET_SYSERR; + } + return GNUNET_SYSERR; +} + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addrlen length of the address + * @return string representing the same address + */ +const char * +http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) +{ + const struct IPv4HttpAddress *t4; + const struct IPv6HttpAddress *t6; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + char *address; + static char rbuf[INET6_ADDRSTRLEN + 13]; + uint16_t port; + int res; + + if (addrlen == sizeof (struct IPv6HttpAddress)) + { + address = GNUNET_malloc (INET6_ADDRSTRLEN); + t6 = addr; + a6.sin6_addr = t6->ipv6_addr; + inet_ntop (AF_INET6, &(a6.sin6_addr), address, INET6_ADDRSTRLEN); + port = ntohs (t6->port); + } + else if (addrlen == sizeof (struct IPv4HttpAddress)) + { + address = GNUNET_malloc (INET_ADDRSTRLEN); + t4 = addr; + a4.sin_addr.s_addr = t4->ipv4_addr; + inet_ntop (AF_INET, &(a4.sin_addr), address, INET_ADDRSTRLEN); + port = ntohs (t4->port); + } + else + { + /* invalid address */ + return NULL; + } + + GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13)); + + res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s:%u", address, port); + + GNUNET_free (address); + GNUNET_assert (res != 0); + return rbuf; +} + +struct Session * +lookup_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + const void *addr, size_t addrlen, int force_address) +{ + struct Session *s = NULL; + struct Session *t = NULL; + int e_peer; + int e_addr; + + t = plugin->head; + if (t == NULL) + return NULL; + while (t->next != NULL) + { + e_peer = GNUNET_NO; + e_addr = GNUNET_NO; + if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity))) + { + e_peer = GNUNET_YES; + if (addrlen == t->addrlen) + { + if (0 == memcmp (addr, &t->addr, addrlen)) + e_addr = GNUNET_YES; + } + } + + if ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) + { + s = t; + break; + } + else if ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && + (e_addr == GNUNET_YES)) + { + s = t; + break; + } + else if ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) + { + s = t; + break; + } + t = t->next; + } + + return s; +} + +void +delete_session (struct Session *s) +{ + GNUNET_free (s->addr); + GNUNET_free (s); +} + +struct Session * +create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, + const void *addr, size_t addrlen, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Session *s = NULL; + + s = GNUNET_malloc (sizeof (struct Session)); + memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); + s->plugin = plugin; + s->addr = GNUNET_malloc (addrlen); + memcpy (s->addr, addr, addrlen); + s->addrlen = addrlen; + s->transmit_cont = cont; + s->transmit_cont_cls = cont_cls; + s->next = NULL; + + return s; +} + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. Note that in the case of a + * peer disconnecting, the continuation MUST be called + * prior to the disconnect notification itself. This function + * will be called with this peer's HELLO message to initiate + * a fresh connection to another peer. + * + * @param cls closure + * @param target who should receive this message + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param priority how important is the message (most plugins will + * ignore message priority and just FIFO) + * @param to how long to wait at most for the transmission (does not + * require plugins to discard the message after the timeout, + * just advisory for the desired delay; most plugins will ignore + * this as well) + * @param session which session must be used (or NULL for "any") + * @param addr the address to use (can be NULL if the plugin + * is "on its own" (i.e. re-use existing TCP connection)) + * @param addrlen length of the address in bytes + * @param force_address GNUNET_YES if the plugin MUST use the given address, + * GNUNET_NO means the plugin may use any other address and + * GNUNET_SYSERR means that only reliable existing + * bi-directional connections should be used (regardless + * of address) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...); can be NULL + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +http_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target, + const char *msgbuf, size_t msgbuf_size, unsigned int priority, + struct GNUNET_TIME_Relative to, struct Session *session, + const void *addr, size_t addrlen, int force_address, + GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) +{ + struct Plugin *plugin = cls; + + GNUNET_assert (plugin != NULL); + + int res = GNUNET_SYSERR; + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Sending %u bytes to peer `%s'\n", msgbuf_size, + GNUNET_i2s (target)); +#endif + + struct Session *s = NULL; + + /* look for existing connection */ + s = lookup_session (plugin, target, addr, addrlen, force_address); + + /* create new connection */ + if (s == NULL) + { +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + "Initiiating new connection to peer `%s'\n", + GNUNET_i2s (target)); +#endif + s = create_session (plugin, target, addr, addrlen, cont, cont_cls); + GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); + // initiate new connection + client_connect (s); + } + else if (s->inbound == GNUNET_NO) + res = client_send (s, msgbuf, msgbuf_size); + else if (s->inbound == GNUNET_YES) + res = server_send (s, msgbuf, msgbuf_size); + + return res; +} + + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuationc). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +{ + struct Plugin *plugin = cls; + struct Session *next = NULL; + struct Session *s = plugin->head; + + while (s != NULL) + { + next = s->next; + if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity))) + { + if (s->inbound == GNUNET_NO) + GNUNET_assert (GNUNET_OK == client_disconnect (s)); + else + GNUNET_assert (GNUNET_OK == server_disconnect (s)); + GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); + delete_session (s); + } + s = next; + } +} + +/** + * Function called by the NAT subsystem suggesting another peer wants + * to connect to us via connection reversal. Try to connect back to the + * given IP. + * + * @param cls closure + * @param addr address to try + * @param addrlen number of bytes in addr + */ +static void +nat_connection_reversal (void *cls, const struct sockaddr *addr, + socklen_t addrlen) +{ + +} + +static void +nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4HttpAddress *t4 = NULL; + struct IPv4HttpAddressWrapper *w_t4 = NULL; + struct IPv6HttpAddress *t6 = NULL; + struct IPv6HttpAddressWrapper *w_t6 = NULL; + int af; + + af = addr->sa_family; + switch (af) + { + case AF_INET: + w_t4 = plugin->ipv4_addr_head; + while (w_t4 != NULL) + { + int res = memcmp (&w_t4->addr->ipv4_addr, + &((struct sockaddr_in *) addr)->sin_addr, + sizeof (struct in_addr)); + + if (0 == res) + break; + w_t4 = w_t4->next; + } + if (w_t4 == NULL) + { + w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); + t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddress)); + memcpy (&t4->ipv4_addr, &((struct sockaddr_in *) addr)->sin_addr, + sizeof (struct in_addr)); + t4->port = htons (plugin->port); + + w_t4->addr = t4; + + GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, + plugin->ipv4_addr_tail, w_t4); + } + plugin->env->notify_address (plugin->env->cls, add_remove, w_t4->addr, + sizeof (struct IPv4HttpAddress)); + + break; + case AF_INET6: + w_t6 = plugin->ipv6_addr_head; + while (w_t6) + { + int res = memcmp (&w_t6->addr->ipv6_addr, + &((struct sockaddr_in6 *) addr)->sin6_addr, + sizeof (struct in6_addr)); + + if (0 == res) + break; + w_t6 = w_t6->next; + } + if (w_t6 == NULL) + { + w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); + t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddress)); + + memcpy (&t6->ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, + sizeof (struct in6_addr)); + t6->port = htons (plugin->port); + + w_t6->addr = t6; + + GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, + plugin->ipv6_addr_tail, w_t6); + } + plugin->env->notify_address (plugin->env->cls, add_remove, w_t6->addr, + sizeof (struct IPv6HttpAddress)); + break; + default: + return; + } + +} + +static void +nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct Plugin *plugin = cls; + struct IPv4HttpAddressWrapper *w_t4 = NULL; + struct IPv6HttpAddressWrapper *w_t6 = NULL; + int af; + + af = addr->sa_family; + switch (af) + { + case AF_INET: + w_t4 = plugin->ipv4_addr_head; + while (w_t4 != NULL) + { + int res = memcmp (&w_t4->addr->ipv4_addr, + &((struct sockaddr_in *) addr)->sin_addr, + sizeof (struct in_addr)); + + if (0 == res) + break; + w_t4 = w_t4->next; + } + if (w_t4 == NULL) + return; + plugin->env->notify_address (plugin->env->cls, add_remove, w_t4->addr, + sizeof (struct IPv4HttpAddress)); + + GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, + w_t4); + GNUNET_free (w_t4->addr); + GNUNET_free (w_t4); + break; + case AF_INET6: + w_t6 = plugin->ipv6_addr_head; + while (w_t6 != NULL) + { + int res = memcmp (&w_t6->addr->ipv6_addr, + &((struct sockaddr_in6 *) addr)->sin6_addr, + sizeof (struct in6_addr)); + + if (0 == res) + break; + w_t6 = w_t6->next; + } + if (w_t6 == NULL) + return; + plugin->env->notify_address (plugin->env->cls, add_remove, w_t6->addr, + sizeof (struct IPv6HttpAddress)); + + GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, + w_t6); + GNUNET_free (w_t6->addr); + GNUNET_free (w_t6); + break; + default: + return; + } + +} + +/** + * Our external IP address/port mapping has changed. + * + * @param cls closure, the 'struct LocalAddrList' + * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean + * the previous (now invalid) one + * @param addr either the previous or the new public IP address + * @param addrlen actual lenght of the address + */ +static void +nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, + socklen_t addrlen) +{ + GNUNET_assert (cls != NULL); + struct Plugin *plugin = cls; + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "NPMC called %s to address `%s'\n", + (add_remove == GNUNET_NO) ? "remove" : "add", + GNUNET_a2s (addr, addrlen)); +#endif + /* convert 'addr' to our internal format */ + switch (add_remove) + { + case GNUNET_YES: + nat_add_address (cls, add_remove, addr, addrlen); + break; + case GNUNET_NO: + nat_remove_address (cls, add_remove, addr, addrlen); + break; + } +} + + +static void +start_report_addresses (struct Plugin *plugin) +{ + int res = GNUNET_OK; + struct sockaddr **addrs; + socklen_t *addrlens; + + res = + GNUNET_SERVICE_get_server_addresses (plugin->name, plugin->env->cfg, + &addrs, &addrlens); + + if (res != GNUNET_SYSERR) + { + plugin->nat = + GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, + (unsigned int) res, + (const struct sockaddr **) addrs, addrlens, + &nat_port_map_callback, &nat_connection_reversal, + plugin); + while (res > 0) + { + res--; + GNUNET_assert (addrs[res] != NULL); + GNUNET_free (addrs[res]); + } + GNUNET_free_non_null (addrs); + GNUNET_free_non_null (addrlens); + } + else + { + plugin->nat = + GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL, + NULL, &nat_connection_reversal, plugin); + } +} + +static void +stop_report_addresses (struct Plugin *plugin) +{ + /* Stop NAT handle */ + GNUNET_NAT_unregister (plugin->nat); + + /* Clean up addresses */ + struct IPv4HttpAddressWrapper *w_t4; + struct IPv6HttpAddressWrapper *w_t6; + + while (plugin->ipv4_addr_head != NULL) + { + w_t4 = plugin->ipv4_addr_head; + GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, + w_t4); + GNUNET_free (w_t4->addr); + GNUNET_free (w_t4); + } + + while (plugin->ipv6_addr_head != NULL) + { + w_t6 = plugin->ipv6_addr_head; + GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, + w_t6); + GNUNET_free (w_t6->addr); + GNUNET_free (w_t6); + } +} + +static int +configure_plugin (struct Plugin *plugin) +{ + int res = GNUNET_OK; + + /* Use IPv4? */ + if (GNUNET_CONFIGURATION_have_value + (plugin->env->cfg, plugin->name, "USE_IPv4")) + { + plugin->ipv4 = + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, + "USE_IPv4"); + } + else + plugin->ipv4 = GNUNET_YES; + + /* Use IPv6? */ + if (GNUNET_CONFIGURATION_have_value + (plugin->env->cfg, plugin->name, "USE_IPv6")) + { + plugin->ipv6 = + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, + "USE_IPv6"); + } + else + plugin->ipv6 = GNUNET_YES; + + if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"), + plugin->name); + res = GNUNET_SYSERR; + } + /* Reading port number from config file */ + unsigned long long port; + + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, + "PORT", &port)) || (port > 65535)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _("Port is required! Fix in configuration\n"), + plugin->name); + res = GNUNET_SYSERR; + } + plugin->port = port; + + return res; +} + +/** + * Entry point for the plugin. + */ +void * +LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + int res; + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->send = &http_plugin_send; + api->disconnect = &http_plugin_disconnect; + api->address_pretty_printer = &http_plugin_address_pretty_printer; + api->check_address = &http_plugin_address_suggested; + api->address_to_string = &http_plugin_address_to_string; + +#if BUILD_HTTPS + plugin->name = "transport-https"; + plugin->protocol = "https"; +#else + plugin->name = "transport-http"; + plugin->protocol = "http"; +#endif + /* Configure plugin from configuration */ + + res = configure_plugin (plugin); + if (res == GNUNET_SYSERR) + { + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + + /* Start client */ + res = client_start (plugin); + if (res == GNUNET_SYSERR) + { + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + + /* Start server */ + res = server_start (plugin); + if (res == GNUNET_SYSERR) + { + server_stop (plugin); + client_stop (plugin); + + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; + } + + /* Report addresses to transport service */ + start_report_addresses (plugin); + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Plugin `%s' loaded\n", plugin->name); +#endif + + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + struct Session *s = NULL; + + /* Stop reporting addresses to transport service */ + stop_report_addresses (plugin); + + /* cleaning up sessions */ + s = plugin->head; + while (s != NULL) + { + struct Session *t = s->next; + + if (s->inbound == GNUNET_NO) + GNUNET_assert (GNUNET_OK == client_disconnect (s)); + else + GNUNET_assert (GNUNET_OK == server_disconnect (s)); + + GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); + delete_session (s); + s = t; + } + + /* Stop server */ + server_stop (plugin); + + /* Stop client */ + client_stop (plugin); + + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "Plugin `%s' unloaded\n", plugin->name); +#endif + + GNUNET_free (plugin); + GNUNET_free (api); + + return NULL; +} + +/* end of plugin_transport_http.c */ diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c new file mode 100644 index 000000000..96d3e27ae --- /dev/null +++ b/src/transport/plugin_transport_http_server.c @@ -0,0 +1,374 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_http.c + * @brief http transport service plugin + * @author Matthias Wachs + */ + +#include "plugin_transport_http.h" + +static void +server_log (void *arg, const char *fmt, va_list ap) +{ + char text[1024]; + + vsnprintf (text, sizeof (text), fmt, ap); + va_end (ap); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "server: %s\n", text); +} + +/** + * Check if incoming connection is accepted. + * NOTE: Here every connection is accepted + * @param cls plugin as closure + * @param addr address of incoming connection + * @param addr_len address length of incoming connection + * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected + * + */ +static int +server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) +{ + return 0; +} + + +/** + * Callback called by MHD when it needs data to send + * @param cls current session + * @param pos position in buffer + * @param buf the buffer to write data to + * @param max max number of bytes available in buffer + * @return bytes written to buffer + */ +#if 0 +static ssize_t +server_send_cb (void *cls, uint64_t pos, char *buf, size_t max) +{ + + return 0; +} +#endif + + +#if BUILD_HTTPS +static char * +server_load_file (const char *file) +{ + struct GNUNET_DISK_FileHandle *gn_file; + struct stat fstat; + char *text = NULL; + + if (0 != STAT (file, &fstat)) + return NULL; + text = GNUNET_malloc (fstat.st_size + 1); + gn_file = + GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_USER_READ); + if (gn_file == NULL) + { + GNUNET_free (text); + return NULL; + } + if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size)) + { + GNUNET_free (text); + GNUNET_DISK_file_close (gn_file); + return NULL; + } + text[fstat.st_size] = '\0'; + GNUNET_DISK_file_close (gn_file); + return text; +} +#endif + + +#if BUILD_HTTPS + +static int +server_load_certificate (struct Plugin *plugin) +{ + int res = GNUNET_OK; + + char *key_file; + char *cert_file; + + /* Get crypto init string from config + * If not present just use default values */ + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, + "CRYPTO_INIT", &plugin->crypto_init); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, + "KEY_FILE", &key_file)) + { + key_file = "https_key.key"; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, + "CERT_FILE", &cert_file)) + { + cert_file = "https_cert.crt"; + } + + /* read key & certificates from file */ +#if VERBOSE_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Loading TLS certificate from key-file `%s' cert-file`%s'\n", + key_file, cert_file); +#endif + + plugin->key = server_load_file (key_file); + plugin->cert = server_load_file (cert_file); + + if ((plugin->key == NULL) || (plugin->cert == NULL)) + { + struct GNUNET_OS_Process *cert_creation; + + GNUNET_free_non_null (plugin->key); + plugin->key = NULL; + GNUNET_free_non_null (plugin->cert); + plugin->cert = NULL; + +#if VERBOSE_SERVER + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No usable TLS certificate found, creating certificate\n"); +#endif + errno = 0; + cert_creation = + GNUNET_OS_start_process (NULL, NULL, + "gnunet-transport-certificate-creation", + "gnunet-transport-certificate-creation", + key_file, cert_file, NULL); + if (cert_creation == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); + GNUNET_free (key_file); + GNUNET_free (cert_file); + + GNUNET_free_non_null (plugin->key); + GNUNET_free_non_null (plugin->cert); + GNUNET_free_non_null (plugin->crypto_init); + + return GNUNET_SYSERR; + } + GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); + GNUNET_OS_process_close (cert_creation); + + plugin->key = server_load_file (key_file); + plugin->cert = server_load_file (cert_file); + } + + if ((plugin->key == NULL) || (plugin->cert == NULL)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, + _ + ("No usable TLS certificate found and creating one failed!\n"), + "transport-https"); + GNUNET_free (key_file); + GNUNET_free (cert_file); + + GNUNET_free_non_null (plugin->key); + GNUNET_free_non_null (plugin->cert); + GNUNET_free_non_null (plugin->crypto_init); + + return GNUNET_SYSERR; + } + GNUNET_free (key_file); + GNUNET_free (cert_file); +#if DEBUG_HTTP + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); +#endif + + return res; +} +#endif + + +/** + * Process GET or PUT request received via MHD. For + * GET, queue response that will send back our pending + * messages. For PUT, process incoming data and send + * to GNUnet core. In either case, check if a session + * already exists and create a new one if not. + */ +static int +server_access_cb (void *cls, struct MHD_Connection *mhd_connection, + const char *url, const char *method, const char *version, + const char *upload_data, size_t * upload_data_size, + void **httpSessionCache) +{ + return 0; +} + +static void +server_disconnect_cb (void *cls, struct MHD_Connection *connection, + void **httpSessionCache) +{ +} + +int +server_disconnect (struct Session *s) +{ + return GNUNET_OK; +} + +int +server_send (struct Session *s, const char *msgbuf, size_t msgbuf_size) +{ + return GNUNET_OK; +} + +int +server_start (struct Plugin *plugin) +{ + int res = GNUNET_OK; + +#if BUILD_HTTPS + res = server_load_certificate (plugin); + if (res == GNUNET_SYSERR) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TABORT\n"); + return res; + } +#endif + + plugin->server_v4 = NULL; + if (plugin->ipv4 == GNUNET_YES) + { + plugin->server_v4 = MHD_start_daemon ( +#if VERBOSE_SERVER + MHD_USE_DEBUG | +#endif +#if BUILD_HTTPS + MHD_USE_SSL | +#endif + MHD_NO_FLAG, plugin->port, + &server_accept_cb, plugin, + &server_access_cb, plugin, + //MHD_OPTION_SOCK_ADDR, + //(struct sockaddr_in *) + //plugin->bind4_address, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) + plugin->max_connections, +#if BUILD_HTTPS + MHD_OPTION_HTTPS_PRIORITIES, + plugin->crypto_init, + MHD_OPTION_HTTPS_MEM_KEY, + plugin->key, + MHD_OPTION_HTTPS_MEM_CERT, + plugin->cert, +#endif + MHD_OPTION_CONNECTION_TIMEOUT, + (unsigned int) 3, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (2 * + GNUNET_SERVER_MAX_MESSAGE_SIZE), + MHD_OPTION_NOTIFY_COMPLETED, + &server_disconnect_cb, plugin, + MHD_OPTION_EXTERNAL_LOGGER, + server_log, NULL, MHD_OPTION_END); + if (plugin->server_v4 == NULL) + res = GNUNET_SYSERR; + } + plugin->server_v6 = NULL; + if (plugin->ipv6 == GNUNET_YES) + { + plugin->server_v6 = MHD_start_daemon ( +#if VERBOSE_SERVER + MHD_USE_DEBUG | +#endif +#if BUILD_HTTPS + MHD_USE_SSL | +#endif + MHD_USE_IPv6, plugin->port, + &server_accept_cb, plugin, + &server_access_cb, plugin, + //MHD_OPTION_SOCK_ADDR, + //tmp, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) + plugin->max_connections, +#if BUILD_HTTPS + MHD_OPTION_HTTPS_PRIORITIES, + plugin->crypto_init, + MHD_OPTION_HTTPS_MEM_KEY, + plugin->key, + MHD_OPTION_HTTPS_MEM_CERT, + plugin->cert, +#endif + MHD_OPTION_CONNECTION_TIMEOUT, + (unsigned int) 3, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (2 * + GNUNET_SERVER_MAX_MESSAGE_SIZE), + MHD_OPTION_NOTIFY_COMPLETED, + &server_disconnect_cb, plugin, + MHD_OPTION_EXTERNAL_LOGGER, + server_log, NULL, MHD_OPTION_END); + + if (plugin->server_v6 == NULL) + res = GNUNET_SYSERR; + } + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "%s server component started on port %u\n", plugin->name, + plugin->port); +#endif + return res; +} + +void +server_stop (struct Plugin *plugin) +{ + + if (plugin->server_v4 != NULL) + { + MHD_stop_daemon (plugin->server_v4); + plugin->server_v4 = NULL; + } + if (plugin->server_v6 != NULL) + { + MHD_stop_daemon (plugin->server_v6); + plugin->server_v6 = NULL; + } + +#if BUILD_HTTPS + GNUNET_free_non_null (plugin->crypto_init); + GNUNET_free_non_null (plugin->cert); + GNUNET_free_non_null (plugin->key); +#endif + +#if DEBUG_HTTP + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, + "%s server component stopped\n", plugin->name); +#endif +} + + + +/* end of plugin_transport_http.c */ -- 2.25.1