X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fplugin_transport_http_server.c;h=6a9c1b0baba318e9002aede5072a3ebdc1264ee8;hb=4bd01d03e323377bbbd7609e29d8179bcb682deb;hp=96f79e482e971d3b3cc819ec3fc9d4297a74c02e;hpb=d8c53b12a818ff7cf82d06a1a69c395bdef85ee6;p=oweals%2Fgnunet.git diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c index 96f79e482..6a9c1b0ba 100644 --- a/src/transport/plugin_transport_http_server.c +++ b/src/transport/plugin_transport_http_server.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2002-2014 GNUnet e.V. + Copyright (C) 2002-2014, 2017 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -29,7 +29,7 @@ #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_plugin.h" -#include "gnunet_nat_lib.h" +#include "gnunet_nat_service.h" #include "plugin_transport_http_common.h" #include #include @@ -92,6 +92,11 @@ struct ServerRequest */ int connected; + /** + * Currently suspended + */ + bool suspended; + }; @@ -201,7 +206,7 @@ struct GNUNET_ATS_Session /** * Message stream tokenizer for incoming data */ - struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; + struct GNUNET_MessageStreamTokenizer *msg_tk; /** * Client recv handle @@ -501,7 +506,9 @@ server_wake_up (void *cls) LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p: Waking up PUT handle\n", s); + GNUNET_assert (s->server_recv->suspended); MHD_resume_connection (s->server_recv->mhd_conn); + s->server_recv->suspended = false; } @@ -541,7 +548,11 @@ server_delete_session (struct GNUNET_ATS_Session *s) GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); s->recv_wakeup_task = NULL; if (NULL != s->server_recv) + { + GNUNET_assert (s->server_recv->suspended); + s->server_recv->suspended = false; MHD_resume_connection (s->server_recv->mhd_conn); + } } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, @@ -578,7 +589,14 @@ server_delete_session (struct GNUNET_ATS_Session *s) MHD_set_connection_option (s->server_send->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1 /* 0 = no timeout, so this is MIN */); - server_reschedule (plugin, s->server_send->mhd_daemon, GNUNET_YES); + if (s->server_send->suspended) + { + s->server_send->suspended = false; + MHD_resume_connection (s->server_send->mhd_conn); + } + server_reschedule (plugin, + s->server_send->mhd_daemon, + GNUNET_YES); } if (NULL != s->server_recv) @@ -590,7 +608,9 @@ server_delete_session (struct GNUNET_ATS_Session *s) MHD_set_connection_option (s->server_recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1 /* 0 = no timeout, so this is MIN */); - server_reschedule (plugin, s->server_recv->mhd_daemon, GNUNET_YES); + server_reschedule (plugin, + s->server_recv->mhd_daemon, + GNUNET_YES); } notify_session_monitor (plugin, s, @@ -604,14 +624,13 @@ server_delete_session (struct GNUNET_ATS_Session *s) } if (NULL != s->msg_tk) { - GNUNET_SERVER_mst_destroy (s->msg_tk); + GNUNET_MST_destroy (s->msg_tk); s->msg_tk = NULL; } GNUNET_HELLO_address_free (s->address); LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p destroyed\n", s); - GNUNET_free (s); } @@ -757,9 +776,16 @@ http_server_plugin_send (void *cls, GNUNET_free (stat_txt); if (NULL != session->server_send) + { + if (session->server_send->suspended) + { + MHD_resume_connection (session->server_send->mhd_conn); + session->server_send->suspended = false; + } server_reschedule (session->plugin, session->server_send->mhd_daemon, GNUNET_YES); + } return bytes_sent; } @@ -774,8 +800,8 @@ http_server_plugin_send (void *cls, */ static int destroy_session_shutdown_cb (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *value) + const struct GNUNET_PeerIdentity *peer, + void *value) { struct GNUNET_ATS_Session *s = value; struct ServerRequest *sc_send; @@ -784,13 +810,15 @@ destroy_session_shutdown_cb (void *cls, sc_send = s->server_send; sc_recv = s->server_recv; server_delete_session (s); - - GNUNET_free_non_null (sc_send); - GNUNET_free_non_null (sc_recv); + if (NULL != sc_send) + sc_send->session = NULL; + if (NULL != sc_recv) + sc_recv->session = NULL; return GNUNET_OK; } + /** * Terminate session. * @@ -810,6 +838,7 @@ destroy_session_cb (void *cls, return GNUNET_OK; } + /** * Function that can be used to force the plugin to disconnect * from the given peer and cancel all previous transmissions @@ -1607,6 +1636,12 @@ server_send_callback (void *cls, s); return MHD_CONTENT_READER_END_OF_STREAM; } + else + { + MHD_suspend_connection (s->server_send->mhd_conn); + s->server_send->suspended = true; + return 0; + } return bytes_read; } @@ -1615,13 +1650,11 @@ server_send_callback (void *cls, * Callback called by MessageStreamTokenizer when a message has arrived * * @param cls current session as closure - * @param client client * @param message the message to be forwarded to transport service - * @return #GNUNET_OK + * @return #GNUNET_OK (all OK) */ static int server_receive_mst_cb (void *cls, - void *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_ATS_Session *s = cls; @@ -1648,7 +1681,9 @@ server_receive_mst_cb (void *cls, "# bytes received via %s_server", plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, - stat_txt, ntohs (message->size), GNUNET_NO); + stat_txt, + ntohs (message->size), + GNUNET_NO); GNUNET_free (stat_txt); s->next_receive = GNUNET_TIME_relative_to_absolute (delay); if (delay.rel_value_us > 0) @@ -1839,23 +1874,30 @@ server_access_cb (void *cls, *upload_data_size); if (s->msg_tk == NULL) { - s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); + s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb, + s); } - GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, *upload_data_size, - GNUNET_NO, GNUNET_NO); + GNUNET_MST_from_buffer (s->msg_tk, + upload_data, + *upload_data_size, + GNUNET_NO, GNUNET_NO); server_mhd_connection_timeout (plugin, s, - GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL - / 1000LL); + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL + / 1000LL); (*upload_data_size) = 0; } else { /* delay processing */ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n", - s, sc, GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n", + s, + sc, + GNUNET_STRINGS_relative_time_to_string (delay, + GNUNET_YES)); GNUNET_assert(s->server_recv->mhd_conn == mhd_connection); MHD_suspend_connection (s->server_recv->mhd_conn); + s->server_recv->suspended = true; if (NULL == s->recv_wakeup_task) s->recv_wakeup_task = GNUNET_SCHEDULER_add_delayed (delay, @@ -1924,7 +1966,7 @@ server_disconnect_cb (void *cls, sc->session->server_recv = NULL; if (NULL != sc->session->msg_tk) { - GNUNET_SERVER_mst_destroy (sc->session->msg_tk); + GNUNET_MST_destroy (sc->session->msg_tk); sc->session->msg_tk = NULL; } } @@ -1934,6 +1976,37 @@ server_disconnect_cb (void *cls, } +/** + * Callback from MHD when a connection starts/stops + * + * @param cls closure with the `struct HTTP_Server_Plugin *` + * @param connection connection handle + * @param socket_context socket-specific pointer + * @param toe reason for connection notification + * @see #MHD_OPTION_NOTIFY_CONNECTION + */ +static void +server_connection_cb (void *cls, + struct MHD_Connection *connection, + void **socket_context, + enum MHD_ConnectionNotificationCode toe) +{ + struct HTTP_Server_Plugin *plugin = cls; + const union MHD_ConnectionInfo *info; + + if (MHD_CONNECTION_NOTIFY_STARTED == toe) + return; + + /* Reschedule to remove closed socket from our select set */ + info = MHD_get_connection_info (connection, + MHD_CONNECTION_INFO_DAEMON); + GNUNET_assert (NULL != info); + server_reschedule (plugin, + info->daemon, + GNUNET_YES); +} + + /** * Check if incoming connection is accepted. * @@ -2212,9 +2285,11 @@ run_mhd_start_daemon (struct HTTP_Server_Plugin *plugin, timeout, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (2 * - GNUNET_SERVER_MAX_MESSAGE_SIZE), + GNUNET_MAX_MESSAGE_SIZE), MHD_OPTION_NOTIFY_COMPLETED, &server_disconnect_cb, plugin, + MHD_OPTION_NOTIFY_CONNECTION, + &server_connection_cb, plugin, MHD_OPTION_EXTERNAL_LOGGER, &server_log, NULL, MHD_OPTION_END); @@ -2462,12 +2537,14 @@ server_remove_address (void *cls, * @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 ac address class the address belongs to * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void server_nat_port_map_callback (void *cls, int add_remove, + enum GNUNET_NAT_AddressClass ac, const struct sockaddr *addr, socklen_t addrlen) { @@ -2487,7 +2564,8 @@ server_nat_port_map_callback (void *cls, if ((NULL != plugin->server_addr_v4) && (0 != memcmp (&plugin->server_addr_v4->sin_addr, - &s4->sin_addr, sizeof (struct in_addr)))) + &s4->sin_addr, + sizeof (struct in_addr)))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Skipping address `%s' (not bindto address)\n", @@ -2743,13 +2821,16 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin) return; } - plugin->nat = - GNUNET_NAT_register (plugin->env->cfg, - GNUNET_YES, - plugin->port, + plugin->nat + = GNUNET_NAT_register (plugin->env->cfg, + "transport-http_server", + IPPROTO_TCP, (unsigned int) res, - (const struct sockaddr **) addrs, addrlens, - &server_nat_port_map_callback, NULL, plugin, NULL); + (const struct sockaddr **) addrs, + addrlens, + &server_nat_port_map_callback, + NULL, + plugin); while (res > 0) { res--; @@ -2803,13 +2884,18 @@ server_check_ipv6_support (struct HTTP_Server_Plugin *plugin) int res = GNUNET_NO; /* Probe IPv6 support */ - desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); + desc = GNUNET_NETWORK_socket_create (PF_INET6, + SOCK_STREAM, + 0); if (NULL == desc) { - if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || - (errno == EACCES)) + if ( (errno == ENOBUFS) || + (errno == ENOMEM) || + (errno == ENFILE) || + (errno == EACCES) ) { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); } LOG (GNUNET_ERROR_TYPE_WARNING, _("Disabling IPv6 since it is not supported on this system!\n")); @@ -2817,7 +2903,8 @@ server_check_ipv6_support (struct HTTP_Server_Plugin *plugin) } else { - GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (desc)); desc = NULL; res = GNUNET_YES; } @@ -2864,21 +2951,23 @@ server_notify_external_hostname (void *cls) LOG (GNUNET_ERROR_TYPE_INFO, "Enabling SSL verification for external hostname address `%s'\n", plugin->external_hostname); - plugin->ext_addr = GNUNET_HELLO_address_allocate (plugin->env->my_identity, - "https_client", - ext_addr, - ext_addr_len, - GNUNET_HELLO_ADDRESS_INFO_NONE); + plugin->ext_addr + = GNUNET_HELLO_address_allocate (plugin->env->my_identity, + "https_client", + ext_addr, + ext_addr_len, + GNUNET_HELLO_ADDRESS_INFO_NONE); plugin->env->notify_address (plugin->env->cls, GNUNET_YES, plugin->ext_addr); GNUNET_free (ext_addr); #else - plugin->ext_addr = GNUNET_HELLO_address_allocate (plugin->env->my_identity, - "http_client", - ext_addr, - ext_addr_len, - GNUNET_HELLO_ADDRESS_INFO_NONE); + plugin->ext_addr + = GNUNET_HELLO_address_allocate (plugin->env->my_identity, + "http_client", + ext_addr, + ext_addr_len, + GNUNET_HELLO_ADDRESS_INFO_NONE); plugin->env->notify_address (plugin->env->cls, GNUNET_YES, plugin->ext_addr); @@ -2955,15 +3044,20 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) LOG (GNUNET_ERROR_TYPE_INFO, _("Using port %u\n"), plugin->port); - if ((plugin->use_ipv4 == GNUNET_YES) && - (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, - plugin->name, "BINDTO", &bind4_address))) + if ( (plugin->use_ipv4 == GNUNET_YES) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + plugin->name, + "BINDTO", + &bind4_address))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding %s plugin to specific IPv4 address: `%s'\n", - plugin->protocol, bind4_address); + plugin->protocol, + bind4_address); plugin->server_addr_v4 = GNUNET_new (struct sockaddr_in); - if (1 != inet_pton (AF_INET, bind4_address, + if (1 != inet_pton (AF_INET, + bind4_address, &plugin->server_addr_v4->sin_addr)) { LOG (GNUNET_ERROR_TYPE_ERROR, @@ -2977,7 +3071,7 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) else { LOG (GNUNET_ERROR_TYPE_DEBUG, - _("Binding to IPv4 address %s\n"), + "Binding to IPv4 address %s\n", bind4_address); plugin->server_addr_v4->sin_family = AF_INET; plugin->server_addr_v4->sin_port = htons (plugin->port); @@ -2989,14 +3083,17 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, - "BINDTO6", &bind6_address))) + "BINDTO6", + &bind6_address))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding %s plugin to specific IPv6 address: `%s'\n", plugin->protocol, bind6_address); plugin->server_addr_v6 = GNUNET_new (struct sockaddr_in6); if (1 != - inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr)) + inet_pton (AF_INET6, + bind6_address, + &plugin->server_addr_v6->sin6_addr)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specific IPv6 address `%s' in configuration file is invalid!\n"), @@ -3009,7 +3106,7 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) else { LOG (GNUNET_ERROR_TYPE_DEBUG, - _("Binding to IPv6 address %s\n"), + "Binding to IPv6 address %s\n", bind6_address); plugin->server_addr_v6->sin6_family = AF_INET6; plugin->server_addr_v6->sin6_port = htons (plugin->port); @@ -3019,17 +3116,19 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) plugin->verify_external_hostname = GNUNET_NO; #if BUILD_HTTPS - plugin->verify_external_hostname = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, - plugin->name, - "VERIFY_EXTERNAL_HOSTNAME"); + plugin->verify_external_hostname + = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, + plugin->name, + "VERIFY_EXTERNAL_HOSTNAME"); if (GNUNET_SYSERR == plugin->verify_external_hostname) plugin->verify_external_hostname = GNUNET_NO; if (GNUNET_YES == plugin->verify_external_hostname) plugin->options |= HTTP_OPTIONS_VERIFY_CERTIFICATE; #endif - external_hostname_use_port = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, - plugin->name, - "EXTERNAL_HOSTNAME_USE_PORT"); + external_hostname_use_port + = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, + plugin->name, + "EXTERNAL_HOSTNAME_USE_PORT"); if (GNUNET_SYSERR == external_hostname_use_port) external_hostname_use_port = GNUNET_NO; @@ -3170,16 +3269,6 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) /* Stop to report addresses to transport service */ server_stop_report_addresses (plugin); - if (NULL != plugin->server_v4) - { - MHD_stop_daemon (plugin->server_v4); - plugin->server_v4 = NULL; - } - if (NULL != plugin->server_v6) - { - MHD_stop_daemon (plugin->server_v6); - plugin->server_v6 = NULL; - } if (NULL != plugin->server_v4_task) { GNUNET_SCHEDULER_cancel (plugin->server_v4_task); @@ -3201,6 +3290,16 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) plugin); GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions); plugin->sessions = NULL; + if (NULL != plugin->server_v4) + { + MHD_stop_daemon (plugin->server_v4); + plugin->server_v4 = NULL; + } + if (NULL != plugin->server_v6) + { + MHD_stop_daemon (plugin->server_v6); + plugin->server_v6 = NULL; + } /* Clean up */ GNUNET_free_non_null (plugin->external_hostname); GNUNET_free_non_null (plugin->ext_addr); @@ -3431,12 +3530,12 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) } /* Compile URL regex */ - if (regcomp(&plugin->url_regex, - URL_REGEX, - REG_EXTENDED)) + if (regcomp (&plugin->url_regex, + URL_REGEX, + REG_EXTENDED)) { LOG (GNUNET_ERROR_TYPE_ERROR, - _("Unable to compile URL regex\n")); + _("Unable to compile URL regex\n")); LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); return NULL; }