From 702169aa561b11d3f0af2a05019673c6436acd38 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 23 Jun 2014 21:48:38 +0000 Subject: -drastically simplify http server session cleanup (and startup) logic --- src/transport/plugin_transport_http_server.c | 1826 ++++++++++---------- .../test_transport_api_http_reverse_peer1.conf | 2 +- .../test_transport_api_http_reverse_peer2.conf | 2 +- src/transport/transport-testing.c | 4 +- src/transport/transport.conf.in | 12 +- 5 files changed, 937 insertions(+), 909 deletions(-) (limited to 'src') diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c index aba4b5ed0..0db5e31c5 100644 --- a/src/transport/plugin_transport_http_server.c +++ b/src/transport/plugin_transport_http_server.c @@ -54,242 +54,247 @@ /** - * Session handle for connections. + * Information we keep with MHD for an HTTP request. */ -struct Session +struct ServerConnection { /** - * Stored in a linked list. + * The session this server connection belongs to */ - struct Session *next; + struct Session *session; /** - * Stored in a linked list. + * The MHD connection */ - struct Session *prev; + struct MHD_Connection *mhd_conn; /** - * To whom are we talking to (set to our identity - * if we are still waiting for the welcome message) + * The MHD daemon */ - struct GNUNET_PeerIdentity target; + struct MHD_Daemon *mhd_daemon; /** - * Pointer to the global plugin struct. + * Options requested by peer */ - struct HTTP_Server_Plugin *plugin; + uint32_t options; +#define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */ /** - * next pointer for double linked list + * _RECV or _SEND */ - struct HTTP_Message *msg_head; + int direction; /** - * previous pointer for double linked list + * For PUT connections: Is this the first or last callback with size 0 + * For GET connections: Have we sent a message */ - struct HTTP_Message *msg_tail; + int connected; + +}; + +/** + * Wrapper to manage addresses + */ +struct HttpAddressWrapper +{ /** - * Message stream tokenizer for incoming data + * Linked list next */ - struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; + struct HttpAddressWrapper *next; /** - * Client recv handle + * Linked list previous */ - struct ServerConnection *server_recv; + struct HttpAddressWrapper *prev; /** - * Client send handle + * An address we are using. */ - struct ServerConnection *server_send; + struct HttpAddress *address; /** - * Address + * Length of the address. */ - struct GNUNET_HELLO_Address *address; + size_t addrlen; +}; + +/** + * Message to send using http + */ +struct HTTP_Message +{ /** - * Unique HTTP/S connection tag for this connection + * next pointer for double linked list */ - uint32_t tag; + struct HTTP_Message *next; /** - * ATS network type in NBO + * previous pointer for double linked list */ - uint32_t ats_address_network_type; + struct HTTP_Message *prev; + + /** + * buffer containing data to send + */ + char *buf; /** - * Was session given to transport service? + * amount of data already sent */ - int session_passed; + size_t pos; /** - * Did we immediately end the session in disconnect_cb + * buffer length */ - int session_ended; + size_t size; /** - * Absolute time when to receive data again - * Used for receive throttling + * HTTP/S specific overhead */ - struct GNUNET_TIME_Absolute next_receive; + size_t overhead; /** - * Session timeout task + * Continuation function to call once the transmission buffer + * has again space available. NULL if there is no + * continuation to call. */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** - * Should this session get disconnected? GNUNET_YES/NO + * Closure for transmit_cont. */ - int disconnect; + void *transmit_cont_cls; }; -struct ServerConnection +/** + * Session handle for connections. + */ +struct Session { - /** - * _RECV or _SEND - */ - int direction; /** - * For PUT connections: Is this the first or last callback with size 0 - * For GET connections: Have we sent a message + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) */ - int connected; + struct GNUNET_PeerIdentity target; /** - * The session this server connection belongs to + * Pointer to the global plugin struct. */ - struct Session *session; + struct HTTP_Server_Plugin *plugin; /** - * The MHD connection + * next pointer for double linked list */ - struct MHD_Connection *mhd_conn; + struct HTTP_Message *msg_head; /** - * The MHD daemon + * previous pointer for double linked list */ - struct MHD_Daemon *mhd_daemon; + struct HTTP_Message *msg_tail; /** - * Options requested by peer + * Message stream tokenizer for incoming data */ - uint32_t options; -#define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */ -}; - + struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; -/** - * Encapsulation of all of the state of the plugin. - */ -struct HTTP_Server_Plugin -{ /** - * Our environment. + * Client recv handle */ - struct GNUNET_TRANSPORT_PluginEnvironment *env; + struct ServerConnection *server_recv; /** - * Linked list head of open sessions. + * Client send handle */ - struct Session *head; + struct ServerConnection *server_send; /** - * Linked list tail of open sessions. + * Address */ - struct Session *tail; + struct GNUNET_HELLO_Address *address; /** - * Plugin name + * Absolute time when to receive data again + * Used for receive throttling */ - char *name; + struct GNUNET_TIME_Absolute next_receive; /** - * Protocol + * Session timeout task */ - char *protocol; + GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** - * My options to be included in the address + * Unique HTTP/S connection tag for this connection */ - uint32_t options; + uint32_t tag; /** - * External address + * ATS network type in NBO */ - char *external_hostname; + uint32_t ats_address_network_type; /** - * Verify external address + * #GNUNET_YES if this session is known to the service. */ - int verify_external_hostname; + int known_to_service; - /** - * Maximum number of sockets the plugin can use - * Each http inbound /outbound connections are two connections - */ - unsigned int max_connections; +}; - /** - * Current number of sockets the plugin can use - * Each http inbound /outbound connections are two connections - */ - unsigned int cur_connections; +/** + * Encapsulation of all of the state of the plugin. + */ +struct HTTP_Server_Plugin +{ /** - * Did we immediately end the session in disconnect_cb + * Our environment. */ - int in_shutdown; + struct GNUNET_TRANSPORT_PluginEnvironment *env; /** - * Length of peer id + * Hash map of open sessions. */ - int peer_id_length; + struct GNUNET_CONTAINER_MultiPeerMap *sessions; /** - * External hostname the plugin can be connected to, can be different to - * the host's FQDN, used e.g. for reverse proxying + * Function to call about session status changes. */ - struct GNUNET_HELLO_Address *ext_addr; + GNUNET_TRANSPORT_SessionInfoCallback sic; /** - * Notify transport only about external address + * Closure for @e sic. */ - unsigned int external_only; + void *sic_cls; /** - * use IPv6 + * Plugin name */ - uint16_t use_ipv6; + char *name; /** - * use IPv4 + * Protocol */ - uint16_t use_ipv4; + char *protocol; /** - * Port used + * External address */ - uint16_t port; + char *external_hostname; /** - * Task calling transport service about external address + * External hostname the plugin can be connected to, can be different to + * the host's FQDN, used e.g. for reverse proxying */ - GNUNET_SCHEDULER_TaskIdentifier notify_ext_task; + struct GNUNET_HELLO_Address *ext_addr; /** * NAT handle & address management */ struct GNUNET_NAT_Handle *nat; - - /** - * List of own addresses - */ - /** * IPv4 addresses DLL head */ @@ -310,26 +315,6 @@ struct HTTP_Server_Plugin */ struct sockaddr_in6 *server_addr_v6; - /** - * MHD IPv4 task - */ - GNUNET_SCHEDULER_TaskIdentifier server_v4_task; - - /** - * MHD IPv6 task - */ - GNUNET_SCHEDULER_TaskIdentifier server_v6_task; - - /** - * The IPv4 server is scheduled to run asap - */ - int server_v4_immediately; - - /** - * The IPv6 server is scheduled to run asap - */ - int server_v6_immediately; - /** * MHD IPv4 daemon */ @@ -340,11 +325,6 @@ struct HTTP_Server_Plugin */ struct MHD_Daemon *server_v6; - /** - * Regex for parsing URLs - */ - regex_t url_regex; - #if BUILD_HTTPS /** * Crypto related @@ -368,105 +348,224 @@ struct HTTP_Server_Plugin char *cert; #endif -}; - - -/** - * Wrapper to manage addresses - */ -struct HttpAddressWrapper -{ /** - * Linked list next + * MHD IPv4 task */ - struct HttpAddressWrapper *next; + GNUNET_SCHEDULER_TaskIdentifier server_v4_task; /** - * Linked list previous + * MHD IPv6 task */ - struct HttpAddressWrapper *prev; - - struct HttpAddress *address; - - size_t addrlen; -}; - + GNUNET_SCHEDULER_TaskIdentifier server_v6_task; -/** - * Message to send using http - */ -struct HTTP_Message -{ /** - * next pointer for double linked list + * Task calling transport service about external address */ - struct HTTP_Message *next; + GNUNET_SCHEDULER_TaskIdentifier notify_ext_task; /** - * previous pointer for double linked list + * Notify transport only about external address */ - struct HTTP_Message *prev; + unsigned int external_only; /** - * buffer containing data to send + * The IPv4 server is scheduled to run asap */ - char *buf; + int server_v4_immediately; /** - * amount of data already sent + * The IPv6 server is scheduled to run asap */ - size_t pos; + int server_v6_immediately; /** - * buffer length + * Verify external address */ - size_t size; + int verify_external_hostname; /** - * HTTP/S specific overhead + * Maximum number of sockets the plugin can use + * Each http inbound /outbound connections are two connections */ - size_t overhead; + unsigned int max_connections; /** - * Continuation function to call once the transmission buffer - * has again space available. NULL if there is no - * continuation to call. + * Current number of sockets the plugin can use + * Each http inbound /outbound connections are two connections */ - GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + unsigned int cur_connections; /** - * Closure for transmit_cont. + * Did we immediately end the session in disconnect_cb */ - void *transmit_cont_cls; + int in_shutdown; + + /** + * Length of peer id + */ + int peer_id_length; + + /** + * My options to be included in the address + */ + uint32_t options; + + /** + * use IPv6 + */ + uint16_t use_ipv6; + + /** + * use IPv4 + */ + uint16_t use_ipv4; + + /** + * Port used + */ + uint16_t port; + + /** + * Regex for parsing URLs. FIXME: this seems overkill. + */ + regex_t url_regex; + }; /** - * Start session timeout for session s - * @param s the session + * If a session monitor is attached, notify it about the new + * session state. + * + * @param plugin our plugin + * @param session session that changed state + * @param state new state of the session */ static void -server_start_session_timeout (struct Session *s); +notify_session_monitor (struct HTTP_Server_Plugin *plugin, + struct Session *session, + enum GNUNET_TRANSPORT_SessionState state) +{ + struct GNUNET_TRANSPORT_SessionInfo info; + + if (NULL == plugin->sic) + return; + memset (&info, 0, sizeof (info)); + info.state = state; + info.is_inbound = GNUNET_YES; + // info.num_msg_pending = session->msgs_in_queue; // FIXME + // info.num_bytes_pending = session->bytes_in_queue; // FIXME + // info.receive_delay = session->next_receive; // FIXME + // info.session_timeout = session->timeout; // FIXME + info.address = session->address; + plugin->sic (plugin->sic_cls, + session, + &info); +} /** - * Increment session timeout due to activity for session s - * @param s the session + * Reschedule the execution of both IPv4 and IPv6 server. + * + * @param plugin the plugin + * @param server which server to schedule v4 or v6? + * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait + * until timeout */ static void -server_reschedule_session_timeout (struct Session *s); +server_reschedule (struct HTTP_Server_Plugin *plugin, + struct MHD_Daemon *server, + int now); /** - * Cancel timeout for session s - * @param s the session + * Deletes the session. Must not be used afterwards. + * + * @param s the session to delete */ static void -server_stop_session_timeout (struct Session *s); +server_delete_session (struct Session *s) +{ + struct HTTP_Server_Plugin *plugin = s->plugin; + struct HTTP_Message *msg; + struct HTTP_Message *tmp; + struct ServerConnection *send; + struct ServerConnection *recv; + + if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) + { + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, + &s->target, + s)); + msg = s->msg_head; + while (NULL != msg) + { + tmp = msg->next; + GNUNET_CONTAINER_DLL_remove (s->msg_head, + s->msg_tail, + msg); + if (NULL != msg->transmit_cont) + msg->transmit_cont (msg->transmit_cont_cls, + &s->target, + GNUNET_SYSERR, + msg->size, + msg->pos + msg->overhead); + GNUNET_free (msg); + msg = tmp; + } + send = s->server_send; + if (NULL != send) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server: %p / %p Terminating inbound PUT session to peer `%s'\n", + s, send, + GNUNET_i2s (&s->target)); + send->session = NULL; + MHD_set_connection_option (send->mhd_conn, + MHD_CONNECTION_OPTION_TIMEOUT, + 1 /* 0 = no timeout, so this is MIN */); + server_reschedule (plugin, + send->mhd_daemon, + GNUNET_YES); + } + recv = s->server_recv; + if (NULL != recv) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Server: %p / %p Terminating inbound GET session to peer `%s'\n", + s, recv, GNUNET_i2s (&s->target)); + recv->session = NULL; + MHD_set_connection_option (recv->mhd_conn, + MHD_CONNECTION_OPTION_TIMEOUT, + 1 /* 0 = no timeout, so this is MIN */); + server_reschedule (plugin, + recv->mhd_daemon, + GNUNET_YES); + } + if (GNUNET_YES == s->known_to_service) + plugin->env->session_end (plugin->env->cls, + s->address, + s); + if (NULL != s->msg_tk) + { + GNUNET_SERVER_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); +} /** - * Disconnect session @a s + * Disconnect session @a s by telling MHD to close the + * connections (reducing timeout, etc.). * * @param cls closure with the `struct HTTP_Server_Plugin` * @param s the session @@ -474,31 +573,54 @@ server_stop_session_timeout (struct Session *s); */ static int http_server_plugin_disconnect_session (void *cls, - struct Session *s); + struct Session *s) +{ + server_delete_session (s); + return GNUNET_OK; +} /** - * Does session s exist? + * Session was idle, so disconnect it * - * @param plugin the plugin handle - * @param s the session - * @return #GNUNET_YES on success, #GNUNET_NO on error + * @param cls the session + * @param tc task context */ -static int -server_exist_session (struct HTTP_Server_Plugin *plugin, struct Session *s); +static void +server_session_timeout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Session *s = cls; + + s->timeout_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (TIMEOUT_LOG, + "Session %p was idle for %s, disconnecting\n", + s, + GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT, + GNUNET_YES)); + server_delete_session (s); +} /** - * Reschedule the execution of both IPv4 and IPv6 server - * @param plugin the plugin - * @param server which server to schedule v4 or v6? - * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait - * until timeout + * Increment session timeout due to activity session @a s + * + * @param s the session */ static void -server_reschedule (struct HTTP_Server_Plugin *plugin, - struct MHD_Daemon *server, - int now); +server_reschedule_session_timeout (struct Session *s) +{ + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); + GNUNET_SCHEDULER_cancel (s->timeout_task); + s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT, + &server_session_timeout, + s); + GNUNET_log (TIMEOUT_LOG, + "Timeout rescheduled for session %p set to %s\n", + s, + GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT, + GNUNET_YES)); +} /** @@ -530,29 +652,19 @@ server_reschedule (struct HTTP_Server_Plugin *plugin, */ static ssize_t http_server_plugin_send (void *cls, - struct Session *session, - const char *msgbuf, size_t msgbuf_size, - unsigned int priority, - struct GNUNET_TIME_Relative to, - GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) + struct Session *session, + const char *msgbuf, + size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative to, + GNUNET_TRANSPORT_TransmitContinuation cont, + void *cont_cls) { struct HTTP_Server_Plugin *plugin = cls; struct HTTP_Message *msg; - int bytes_sent = 0; + ssize_t bytes_sent = 0; char *stat_txt; - GNUNET_assert (plugin != NULL); - GNUNET_assert (session != NULL); - - if (GNUNET_NO == server_exist_session (plugin, session)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (session->disconnect) - return GNUNET_SYSERR; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p/connection %p: Sending message with %u to peer `%s'\n", session, @@ -570,24 +682,44 @@ http_server_plugin_send (void *cls, msg->transmit_cont = cont; msg->transmit_cont_cls = cont_cls; memcpy (msg->buf, msgbuf, msgbuf_size); - - GNUNET_CONTAINER_DLL_insert_tail (session->msg_head, session->msg_tail, msg); - - GNUNET_asprintf (&stat_txt, "# bytes currently in %s_server buffers", plugin->protocol); + GNUNET_CONTAINER_DLL_insert_tail (session->msg_head, + session->msg_tail, + msg); + GNUNET_asprintf (&stat_txt, + "# bytes currently in %s_server buffers", + plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, stat_txt, msgbuf_size, GNUNET_NO); GNUNET_free (stat_txt); if (NULL != session->server_send) - { server_reschedule (session->plugin, session->server_send->mhd_daemon, GNUNET_YES); - } return bytes_sent; } +/** + * Terminate session. + * + * @param cls the `struct HTTP_Server_Plugin *` + * @param peer for which this is a session + * @param value the `struct Session` to clean up + * @return #GNUNET_OK (continue to iterate) + */ +static int +destroy_session_cb (void *cls, + const struct GNUNET_PeerIdentity *peer, + void *value) +{ + struct Session *s = value; + + server_delete_session (s); + return GNUNET_OK; +} + + /** * Function that can be used to force the plugin to disconnect * from the given peer and cancel all previous transmissions @@ -601,24 +733,14 @@ http_server_plugin_disconnect_peer (void *cls, const struct GNUNET_PeerIdentity *target) { struct HTTP_Server_Plugin *plugin = cls; - struct Session *next; - struct Session *pos; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport tells me to disconnect `%s'\n", GNUNET_i2s (target)); - next = plugin->head; - while (NULL != (pos = next)) - { - next = pos->next; - if (0 == memcmp (target, &pos->target, sizeof (struct GNUNET_PeerIdentity))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Disconnecting session %p to `%s'\n", - pos, GNUNET_i2s (target)); - http_server_plugin_disconnect_session (plugin, pos); - } - } + GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, + target, + &destroy_session_cb, + plugin); } @@ -671,9 +793,9 @@ http_server_plugin_address_suggested (void *cls, /** * Creates a new outbound session the transport - * service will use to send data to the peer + * service will use to send data to the peer. * - * Since HTTP/S server cannot create sessions, always return NULL + * Since HTTP/S server cannot create sessions, always returns NULL. * * @param cls the plugin * @param address the address @@ -688,85 +810,155 @@ http_server_plugin_get_session (void *cls, /** - * Deleting the session - * Must not be used afterwards + * Call MHD IPv4 to process pending requests and then go back + * and schedule the next run. * - * @param cls closure with the `struct HTTP_ServerPlugin` - * @param s the session to delete - * @return #GNUNET_OK on success + * @param cls plugin as closure + * @param tc task context */ -static int -server_delete_session (void *cls, - struct Session *s) +static void +server_v4_run (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { struct HTTP_Server_Plugin *plugin = cls; - struct HTTP_Message *msg; - struct HTTP_Message *tmp; - server_stop_session_timeout(s); - GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); - msg = s->msg_head; - while (NULL != msg) + plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + plugin->server_v4_immediately = GNUNET_NO; + GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); + server_reschedule (plugin, plugin->server_v4, GNUNET_NO); +} + + +/** + * Call MHD IPv6 to process pending requests and then go back + * and schedule the next run. + * + * @param cls plugin as closure + * @param tc task context + */ +static void +server_v6_run (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct HTTP_Server_Plugin *plugin = cls; + + plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + plugin->server_v6_immediately = GNUNET_NO; + GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); + server_reschedule (plugin, plugin->server_v6, GNUNET_NO); +} + + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + * + * @param plugin plugin + * @param daemon_handle the MHD daemon handle + * @return gnunet task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier +server_schedule (struct HTTP_Server_Plugin *plugin, + struct MHD_Daemon *daemon_handle, + int now) +{ + GNUNET_SCHEDULER_TaskIdentifier ret; + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + int max; + MHD_UNSIGNED_LONG_LONG timeout; + static unsigned long long last_timeout = 0; + int haveto; + struct GNUNET_TIME_Relative tv; + + if (GNUNET_YES == plugin->in_shutdown) + return GNUNET_SCHEDULER_NO_TASK; + + ret = GNUNET_SCHEDULER_NO_TASK; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == + MHD_get_fdset (daemon_handle, + &rs, + &ws, + &es, + &max)); + haveto = MHD_get_timeout (daemon_handle, &timeout); + if (haveto == MHD_YES) { - tmp = msg->next; - GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); - if (NULL != msg->transmit_cont) - msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR, - msg->size, msg->pos + msg->overhead); - GNUNET_free (msg); - msg = tmp; + if (timeout != last_timeout) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "SELECT Timeout changed from %llu to %llu (ms)\n", + last_timeout, timeout); + last_timeout = timeout; + } + if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL) + tv.rel_value_us = (uint64_t) timeout * 1000LL; + else + tv = GNUNET_TIME_UNIT_SECONDS; } - if (NULL != s->msg_tk) + else + tv = GNUNET_TIME_UNIT_SECONDS; + /* Force immediate run, since we have outbound data to send */ + if (now == GNUNET_YES) + tv = GNUNET_TIME_UNIT_MILLISECONDS; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + + if (daemon_handle == plugin->server_v4) { - GNUNET_SERVER_mst_destroy (s->msg_tk); - s->msg_tk = NULL; + if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v4_task); + plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; + } +#if 0 + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling IPv4 server task in %llu ms\n", + tv); +#endif + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + tv, wrs, wws, + &server_v4_run, plugin); + } + if (daemon_handle == plugin->server_v6) + { + if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (plugin->server_v6_task); + plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; + } +#if 0 + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling IPv6 server task in %llu ms\n", tv); +#endif + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + tv, wrs, wws, + &server_v6_run, plugin); } - GNUNET_HELLO_address_free (s->address); - GNUNET_free_non_null (s->server_recv); - GNUNET_free_non_null (s->server_send); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Session %p destroyed\n", - s); - GNUNET_free (s); - return GNUNET_OK; -} - - -/** -* Cancel timeout for session s -* -* @param s the session -*/ -static void -server_stop_session_timeout (struct Session *s) -{ - GNUNET_assert (NULL != s); - - if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) - { - GNUNET_SCHEDULER_cancel (s->timeout_task); - s->timeout_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_log (TIMEOUT_LOG, "Timeout stopped for session %p\n", s); - } + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + return ret; } -/** - * Function that queries MHD's select sets and - * starts the task waiting for them. - * @param plugin plugin - * @param daemon_handle the MHD daemon handle - * @param now schedule immediately - * @return task identifier - */ -static GNUNET_SCHEDULER_TaskIdentifier -server_schedule (struct HTTP_Server_Plugin *plugin, - struct MHD_Daemon *daemon_handle, - int now); - - /** * Reschedule the execution of both IPv4 and IPv6 server + * * @param plugin the plugin * @param server which server to schedule v4 or v6? * @param now #GNUNET_YES to schedule execution immediately, #GNUNET_NO to wait @@ -811,55 +1003,6 @@ server_reschedule (struct HTTP_Server_Plugin *plugin, } -/** - * Disconnect session @a s - * - * @param cls closure with the `struct HTTP_Server_Plugin` - * @param s the session - * @return #GNUNET_OK on success - */ -static int -http_server_plugin_disconnect_session (void *cls, - struct Session *s) -{ - struct HTTP_Server_Plugin *plugin = cls; - struct ServerConnection * send; - struct ServerConnection * recv; - - if (GNUNET_NO == server_exist_session (plugin, s)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - s->disconnect = GNUNET_YES; - send = (struct ServerConnection *) s->server_send; - if (send != NULL) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Server: %p / %p Terminating inbound PUT session to peer `%s'\n", - s, send, GNUNET_i2s (&s->target)); - - MHD_set_connection_option (send->mhd_conn, - MHD_CONNECTION_OPTION_TIMEOUT, - 1); - server_reschedule (s->plugin, send->mhd_daemon, GNUNET_YES); - } - - recv = (struct ServerConnection *) s->server_recv; - if (recv != NULL) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Server: %p / %p Terminating inbound GET session to peer `%s'\n", - s, recv, GNUNET_i2s (&s->target)); - MHD_set_connection_option (recv->mhd_conn, - MHD_CONNECTION_OPTION_TIMEOUT, - 1); - server_reschedule (s->plugin, recv->mhd_daemon, GNUNET_YES); - } - return GNUNET_OK; -} - - /** * Function that is called to get the keepalive factor. * GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to @@ -874,16 +1017,12 @@ http_server_query_keepalive_factor (void *cls) return 3; } + static void http_server_plugin_update_session_timeout (void *cls, - const struct GNUNET_PeerIdentity *peer, - struct Session *session) + const struct GNUNET_PeerIdentity *peer, + struct Session *session) { - struct HTTP_Server_Plugin *plugin = cls; - - if (GNUNET_NO == server_exist_session (plugin, session)) - return; - server_reschedule_session_timeout (session); } @@ -900,7 +1039,7 @@ server_mhd_connection_timeout (struct HTTP_Server_Plugin *plugin, struct Session *s, unsigned int to) { - /* Setting timeouts for other connections */ + /* Setting timeouts for other connections */ if (NULL != s->server_recv) { LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -1053,6 +1192,48 @@ server_parse_url (struct HTTP_Server_Plugin *plugin, } +/** + * Closure for #session_tag_it(). + */ +struct SessionTagContext +{ + /** + * Set to session matching the tag. + */ + struct Session *res; + + /** + * Tag we are looking for. + */ + uint32_t tag; +}; + + +/** + * Find a session with a matching tag. + * + * @param cls the `struct SessionTagContext *` + * @param key peer identity (unused) + * @param value the `struct Session *` + * @return #GNUNET_NO if we found the session, #GNUNET_OK if not + */ +static int +session_tag_it (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct SessionTagContext *stc = cls; + struct Session *s = value; + + if (s->tag == stc->tag) + { + stc->res = s; + return GNUNET_NO; + } + return GNUNET_YES; +} + + /** * Lookup a mhd connection and create one if none is found * @@ -1064,18 +1245,18 @@ server_parse_url (struct HTTP_Server_Plugin *plugin, */ static struct ServerConnection * server_lookup_connection (struct HTTP_Server_Plugin *plugin, - struct MHD_Connection *mhd_connection, const char *url, - const char *method) + struct MHD_Connection *mhd_connection, + const char *url, + const char *method) { struct Session *s = NULL; struct ServerConnection *sc = NULL; const union MHD_ConnectionInfo *conn_info; struct HttpAddress *addr; - struct GNUNET_ATS_Information ats; struct GNUNET_PeerIdentity target; size_t addr_len; - uint32_t tag = 0; + struct SessionTagContext stc; uint32_t options; int direction = GNUNET_SYSERR; unsigned int to; @@ -1089,8 +1270,9 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin, "New %s connection from %s\n", method, url); - - if (GNUNET_SYSERR == server_parse_url (plugin, url, &target, &tag, &options)) + stc.tag = 0; + if (GNUNET_SYSERR == + server_parse_url (plugin, url, &target, &stc.tag, &options)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Invalid url %s\n", url); @@ -1112,51 +1294,38 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin, LOG (GNUNET_ERROR_TYPE_DEBUG, "New %s connection from %s with tag %u (%u of %u)\n", method, - GNUNET_i2s (&target), tag, + GNUNET_i2s (&target), + stc.tag, plugin->cur_connections, plugin->max_connections); - /* find duplicate session */ - s = plugin->head; - while (s != NULL) - { - if ((0 == memcmp (&s->target, &target, sizeof (struct GNUNET_PeerIdentity))) && - (s->tag == tag)) - break; - s = s->next; - } - if (s != NULL) - { - if ((_RECEIVE == direction) && (NULL != s->server_recv)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Duplicate PUT connection from `%s' tag %u, dismissing new connection\n", - GNUNET_i2s (&target), - tag); - return NULL; - } - if ((_SEND == direction) && (NULL != s->server_send)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Duplicate GET connection from `%s' tag %u, dismissing new connection\n", - GNUNET_i2s (&target), - tag); - return NULL; - } - } - else + /* find existing session */ + stc.res = NULL; + GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions, + &target, + &session_tag_it, + &stc); + if (NULL == (s = stc.res)) { /* create new session */ addr = NULL; switch (conn_info->client_addr->sa_family) { case (AF_INET): - addr = http_common_address_from_socket (plugin->protocol, conn_info->client_addr, sizeof (struct sockaddr_in)); + addr = http_common_address_from_socket (plugin->protocol, + conn_info->client_addr, + sizeof (struct sockaddr_in)); addr_len = http_common_address_get_size (addr); - ats = plugin->env->get_address_type (plugin->env->cls, conn_info->client_addr, sizeof (struct sockaddr_in)); + ats = plugin->env->get_address_type (plugin->env->cls, + conn_info->client_addr, + sizeof (struct sockaddr_in)); break; case (AF_INET6): - addr = http_common_address_from_socket (plugin->protocol, conn_info->client_addr, sizeof (struct sockaddr_in6)); + addr = http_common_address_from_socket (plugin->protocol, + conn_info->client_addr, + sizeof (struct sockaddr_in6)); addr_len = http_common_address_get_size (addr); - ats = plugin->env->get_address_type (plugin->env->cls, conn_info->client_addr, sizeof (struct sockaddr_in6)); + ats = plugin->env->get_address_type (plugin->env->cls, + conn_info->client_addr, + sizeof (struct sockaddr_in6)); break; default: /* external host name */ @@ -1164,21 +1333,24 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin, ats.type = htonl (GNUNET_ATS_NET_WAN); return NULL; } - s = GNUNET_new (struct Session); - memcpy (&s->target, &target, sizeof (struct GNUNET_PeerIdentity)); + s->target = target; s->plugin = plugin; - s->address = GNUNET_HELLO_address_allocate (&s->target, PLUGIN_NAME, - addr, addr_len, GNUNET_HELLO_ADDRESS_INFO_INBOUND); + s->address = GNUNET_HELLO_address_allocate (&s->target, + PLUGIN_NAME, + addr, + addr_len, + GNUNET_HELLO_ADDRESS_INFO_INBOUND); s->ats_address_network_type = ats.value; s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; - s->tag = tag; - s->server_recv = NULL; - s->server_send = NULL; - s->session_passed = GNUNET_NO; - s->session_ended = GNUNET_NO; - server_start_session_timeout(s); - GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); + s->tag = stc.tag; + s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT, + &server_session_timeout, + s); + (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions, + &s->target, + s, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new session %p for peer `%s' connecting from `%s'\n", @@ -1188,6 +1360,23 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin, addr_len)); GNUNET_free_non_null (addr); } + + if ( (_RECEIVE == direction) && (NULL != s->server_recv) ) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Duplicate PUT connection from `%s' tag %u, dismissing new connection\n", + GNUNET_i2s (&target), + stc.tag); + return NULL; + } + if ((_SEND == direction) && (NULL != s->server_send)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Duplicate GET connection from `%s' tag %u, dismissing new connection\n", + GNUNET_i2s (&target), + stc.tag); + return NULL; + } sc = GNUNET_new (struct ServerConnection); if (conn_info->client_addr->sa_family == AF_INET) sc->mhd_daemon = plugin->server_v4; @@ -1205,6 +1394,7 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin, if ((NULL != s->server_send) && (NULL != s->server_recv)) { + s->known_to_service = GNUNET_YES; plugin->env->session_start (NULL, s->address ,s, NULL, 0); } @@ -1223,46 +1413,12 @@ server_lookup_connection (struct HTTP_Server_Plugin *plugin, to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL); server_mhd_connection_timeout (plugin, s, to); } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting timeout for %p to %u sec.\n", sc, to); return sc; } -/** - * Lookup a session for a server connection - * - * @param plugin the plugin - * @param sc the server connection - * @return the session found or NULL - */ -static struct Session * -server_lookup_session (struct HTTP_Server_Plugin *plugin, - struct ServerConnection * sc) -{ - struct Session *s; - - for (s = plugin->head; NULL != s; s = s->next) - if ((s->server_recv == sc) || (s->server_send == sc)) - return s; - return NULL; -} - - -static int -server_exist_session (struct HTTP_Server_Plugin *plugin, - struct Session *s) -{ - struct Session * head; - - for (head = plugin->head; head != NULL; head = head->next) - if (head == s) - return GNUNET_YES; - return GNUNET_NO; -} - - /** * Callback called by MHD when it needs data to send * @@ -1273,7 +1429,10 @@ server_exist_session (struct HTTP_Server_Plugin *plugin, * @return bytes written to buffer */ static ssize_t -server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) +server_send_callback (void *cls, + uint64_t pos, + char *buf, + size_t max) { struct Session *s = cls; struct ServerConnection *sc; @@ -1281,8 +1440,6 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) struct HTTP_Message *msg; char *stat_txt; - if (GNUNET_NO == server_exist_session (s->plugin, s)) - return 0; sc = s->server_send; if (NULL == sc) return 0; @@ -1298,7 +1455,9 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) /* removing message */ if (msg->pos == msg->size) { - GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); + GNUNET_CONTAINER_DLL_remove (s->msg_head, + s->msg_tail, + msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK, msg->size, msg->size + msg->overhead); @@ -1342,7 +1501,8 @@ server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) * @return #GNUNET_OK */ static int -server_receive_mst_cb (void *cls, void *client, +server_receive_mst_cb (void *cls, + void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; @@ -1351,24 +1511,30 @@ server_receive_mst_cb (void *cls, void *client, struct GNUNET_TIME_Relative delay; char *stat_txt; - if (GNUNET_NO == server_exist_session (s->plugin, s)) - return GNUNET_OK; - - atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE); atsi.value = s->ats_address_network_type; - GNUNET_break (s->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); - - delay = plugin->env->receive (plugin->env->cls, s->address, s, message); - plugin->env->update_address_metrics (plugin->env->cls, s->address, s, &atsi, 1); - - GNUNET_asprintf (&stat_txt, "# bytes received via %s_server", plugin->protocol); + GNUNET_break (s->ats_address_network_type != + ntohl (GNUNET_ATS_NET_UNSPECIFIED)); + + if (GNUNET_NO == s->known_to_service) + { + s->known_to_service = GNUNET_YES; + plugin->env->session_start (NULL, s->address, s, NULL, 0); + } + delay = plugin->env->receive (plugin->env->cls, + s->address, + s, + message); + plugin->env->update_address_metrics (plugin->env->cls, + s->address, s, + &atsi, 1); + GNUNET_asprintf (&stat_txt, + "# bytes received via %s_server", + plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, stat_txt, ntohs (message->size), GNUNET_NO); GNUNET_free (stat_txt); - - s->session_passed = GNUNET_YES; - s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); + s->next_receive = GNUNET_TIME_relative_to_absolute (delay); if (delay.rel_value_us > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -1384,6 +1550,7 @@ server_receive_mst_cb (void *cls, void *client, return GNUNET_OK; } + /** * Add headers to a request indicating that we allow Cross-Origin Resource * Sharing. @@ -1402,6 +1569,7 @@ add_cors_headers(struct MHD_Response *response) "86400"); } + /** * MHD callback for a new incoming connection * @@ -1416,26 +1584,31 @@ add_cors_headers(struct MHD_Response *response) * @return MHD_YES if connection is accepted, MHD_NO on reject */ 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, +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) { struct HTTP_Server_Plugin *plugin = cls; - int res = MHD_YES; - struct ServerConnection *sc = *httpSessionCache; struct Session *s; struct MHD_Response *response; + int res = MHD_YES; LOG (GNUNET_ERROR_TYPE_DEBUG, _("Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %u\n"), sc, - plugin->cur_connections, plugin->max_connections, - method, version, url, (*upload_data_size)); - - GNUNET_assert (cls != NULL); - if (sc == NULL) + plugin->cur_connections, + plugin->max_connections, + method, + version, + url, + (*upload_data_size)); + if (NULL == sc) { /* CORS pre-flight request */ if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method)) @@ -1449,13 +1622,18 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, } /* new connection */ sc = server_lookup_connection (plugin, mhd_connection, url, method); - if (sc != NULL) + if (NULL != sc) { + /* attach to new / existing session */ (*httpSessionCache) = sc; } else { - response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); + /* existing session already has matching connection, refuse */ + response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), + HTTP_ERROR_RESPONSE, + MHD_NO, + MHD_NO); MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/html"); @@ -1465,33 +1643,19 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, return res; } } - else - { - /* 'old' connection */ - if (NULL == server_lookup_session (plugin, sc)) - { - /* Session was already disconnected */ - return MHD_NO; - } - } - - /* existing connection */ - sc = (*httpSessionCache); - s = sc->session; - GNUNET_assert (NULL != s); - /* connection is to be disconnected */ - if (s->disconnect == GNUNET_YES) + /* 'old' connection */ + if (NULL == (s = sc->session)) { - /* Sent HTTP/1.1: 200 OK as response */ + /* Session was already disconnected; + sent HTTP/1.1: 200 OK as response */ response = MHD_create_response_from_data (strlen ("Thank you!"), - "Thank you!", - MHD_NO, MHD_NO); + "Thank you!", + MHD_NO, MHD_NO); add_cors_headers(response); MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return MHD_YES; } - GNUNET_assert (s != NULL); if (sc->direction == _SEND) { @@ -1595,280 +1759,119 @@ server_access_cb (void *cls, struct MHD_Connection *mhd_connection, * @param httpSessionCache the pointer to distinguish */ static void -server_disconnect_cb (void *cls, struct MHD_Connection *connection, +server_disconnect_cb (void *cls, + struct MHD_Connection *connection, void **httpSessionCache) { struct HTTP_Server_Plugin *plugin = cls; struct ServerConnection *sc = *httpSessionCache; struct Session *s; - struct Session *t; LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnect for connection %p\n", sc); - if (sc == NULL) - return; - - if (NULL == (s = server_lookup_session (plugin, sc))) - return; - for (t = plugin->head; t != NULL; t = t->next) - if (t == s) - break; - if (NULL == t) - return; - + if (NULL == sc) + return; /* never really got setup */ + if (NULL == (s = sc->session)) + return; /* session already dead */ if (sc->direction == _SEND) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connection %p, GET on address `%s' disconnected\n", - GNUNET_i2s (&s->target), s->server_send, + GNUNET_i2s (&s->target), + s->server_send, http_common_plugin_address_to_string (plugin->protocol, s->address->address, s->address->address_length)); s->server_send = NULL; - if (!(sc->options & OPTION_LONG_POLL) && NULL != (s->server_recv)) + if (! ( (0 != (sc->options & OPTION_LONG_POLL)) && + (NULL != s->server_recv) ) ) { - s->disconnect = GNUNET_YES; - GNUNET_assert (NULL != s->server_recv->mhd_conn); -#if MHD_VERSION >= 0x00090E00 - MHD_set_connection_option (s->server_recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, - 1); -#endif - server_reschedule (plugin, s->server_recv->mhd_daemon, GNUNET_NO); + server_delete_session (s); + GNUNET_free (sc); + plugin->cur_connections--; + return; } } if (sc->direction == _RECEIVE) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connection %p PUT on address `%s' disconnected\n", - GNUNET_i2s (&s->target), s->server_recv, + GNUNET_i2s (&s->target), + s->server_recv, http_common_plugin_address_to_string (plugin->protocol, s->address->address, s->address->address_length)); s->server_recv = NULL; - if (s->msg_tk != NULL) + if (NULL != s->msg_tk) { GNUNET_SERVER_mst_destroy (s->msg_tk); s->msg_tk = NULL; } } - GNUNET_free (sc); plugin->cur_connections--; - if (s->disconnect && (s->server_send == NULL) && (s->server_recv == NULL)) + if ( (NULL == s->server_send) && + (NULL == s->server_recv) ) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' on address `%s' disconnected\n", - GNUNET_i2s (&s->target), - http_common_plugin_address_to_string (plugin->protocol, - s->address->address, - s->address->address_length)); - - if ((GNUNET_YES == s->session_passed) && (GNUNET_NO == s->session_ended)) - { - /* Notify transport immediately that this session is invalid */ - s->session_ended = GNUNET_YES; - plugin->env->session_end (plugin->env->cls, s->address, s); - } - server_delete_session (plugin, s); - } -} - - -/** - * Check if incoming 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) -{ - struct HTTP_Server_Plugin *plugin = cls; - - if (plugin->cur_connections <= plugin->max_connections) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - _("Accepting connection (%u of %u) from `%s'\n"), - plugin->cur_connections, plugin->max_connections, - GNUNET_a2s (addr, addr_len)); - return MHD_YES; - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Server reached maximum number connections (%u), rejecting new connection\n"), - plugin->max_connections); - return MHD_NO; - } -} - - -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_DEBUG, "Server: %s\n", text); -} - - -/** - * Call MHD IPv4 to process pending requests and then go back - * and schedule the next run. - * @param cls plugin as closure - * @param tc task context - */ -static void -server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct HTTP_Server_Plugin *plugin = cls; - - GNUNET_assert (cls != NULL); - - plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; -#if 0 - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Running IPv4 server\n"); -#endif - plugin->server_v4_immediately = GNUNET_NO; - GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); - server_reschedule (plugin, plugin->server_v4, GNUNET_NO); -} - - -/** - * Call MHD IPv6 to process pending requests and then go back - * and schedule the next run. - * @param cls plugin as closure - * @param tc task context - */ -static void -server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct HTTP_Server_Plugin *plugin = cls; + GNUNET_i2s (&s->target), + http_common_plugin_address_to_string (plugin->protocol, + s->address->address, + s->address->address_length)); - GNUNET_assert (cls != NULL); - plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; -#if 0 - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Running IPv6 server\n"); -#endif - plugin->server_v6_immediately = GNUNET_NO; - GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); - server_reschedule (plugin, plugin->server_v6, GNUNET_NO); + server_delete_session (s); + } } /** - * Function that queries MHD's select sets and - * starts the task waiting for them. + * Check if incoming connection is accepted. * - * @param plugin plugin - * @param daemon_handle the MHD daemon handle - * @return gnunet task identifier + * @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 GNUNET_SCHEDULER_TaskIdentifier -server_schedule (struct HTTP_Server_Plugin *plugin, - struct MHD_Daemon *daemon_handle, - int now) +static int +server_accept_cb (void *cls, + const struct sockaddr *addr, + socklen_t addr_len) { - GNUNET_SCHEDULER_TaskIdentifier ret; - fd_set rs; - fd_set ws; - fd_set es; - struct GNUNET_NETWORK_FDSet *wrs; - struct GNUNET_NETWORK_FDSet *wws; - struct GNUNET_NETWORK_FDSet *wes; - int max; - MHD_UNSIGNED_LONG_LONG timeout; - static unsigned long long last_timeout = 0; - int haveto; - - struct GNUNET_TIME_Relative tv; - - if (GNUNET_YES == plugin->in_shutdown) - return GNUNET_SCHEDULER_NO_TASK; - - ret = GNUNET_SCHEDULER_NO_TASK; - FD_ZERO (&rs); - FD_ZERO (&ws); - FD_ZERO (&es); - wrs = GNUNET_NETWORK_fdset_create (); - wes = GNUNET_NETWORK_fdset_create (); - wws = GNUNET_NETWORK_fdset_create (); - max = -1; - GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); - haveto = MHD_get_timeout (daemon_handle, &timeout); - if (haveto == MHD_YES) - { - if (timeout != last_timeout) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "SELECT Timeout changed from %llu to %llu (ms)\n", - last_timeout, timeout); - last_timeout = timeout; - } - if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL) - tv.rel_value_us = (uint64_t) timeout * 1000LL; - else - tv = GNUNET_TIME_UNIT_SECONDS; - } - else - tv = GNUNET_TIME_UNIT_SECONDS; - /* Force immediate run, since we have outbound data to send */ - if (now == GNUNET_YES) - tv = GNUNET_TIME_UNIT_MILLISECONDS; - GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); - GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); - GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); + struct HTTP_Server_Plugin *plugin = cls; - if (daemon_handle == plugin->server_v4) + if (plugin->cur_connections <= plugin->max_connections) { - if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (plugin->server_v4_task); - plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; - } -#if 0 LOG (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling IPv4 server task in %llu ms\n", - tv); -#endif - ret = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - tv, wrs, wws, - &server_v4_run, plugin); + _("Accepting connection (%u of %u) from `%s'\n"), + plugin->cur_connections, plugin->max_connections, + GNUNET_a2s (addr, addr_len)); + return MHD_YES; } - if (daemon_handle == plugin->server_v6) + else { - if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (plugin->server_v6_task); - plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; - } -#if 0 - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling IPv6 server task in %llu ms\n", tv); -#endif - ret = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - tv, wrs, wws, - &server_v6_run, plugin); + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Server reached maximum number connections (%u), rejecting new connection\n"), + plugin->max_connections); + return MHD_NO; } - GNUNET_NETWORK_fdset_destroy (wrs); - GNUNET_NETWORK_fdset_destroy (wws); - GNUNET_NETWORK_fdset_destroy (wes); - return ret; +} + + +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_DEBUG, + "Server: %s\n", + text); } @@ -1927,7 +1930,8 @@ server_load_certificate (struct HTTP_Server_Plugin *plugin) if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, + GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, + plugin->name, "KEY_FILE", &key_file)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, @@ -1935,7 +1939,8 @@ server_load_certificate (struct HTTP_Server_Plugin *plugin) return GNUNET_SYSERR; } if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, + GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, + plugin->name, "CERT_FILE", &cert_file)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, @@ -2035,7 +2040,7 @@ server_load_certificate (struct HTTP_Server_Plugin *plugin) * Start the HTTP server * * @param plugin the plugin handle - * @return GNUNET_OK on success, GNUNET_SYSERR on failure + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ static int server_start (struct HTTP_Server_Plugin *plugin) @@ -2181,7 +2186,7 @@ server_start (struct HTTP_Server_Plugin *plugin) } -void +static void server_stop (struct HTTP_Server_Plugin *plugin) { if (plugin->server_v4 != NULL) @@ -2223,20 +2228,24 @@ server_stop (struct HTTP_Server_Plugin *plugin) * Add an address to the server's set of addresses and notify transport * * @param cls the plugin handle - * @param add_remove GNUNET_YES on add, GNUNET_NO on remove + * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove * @param addr the address * @param addrlen address length */ static void -server_add_address (void *cls, int add_remove, const struct sockaddr *addr, - socklen_t addrlen) +server_add_address (void *cls, + int add_remove, + const struct sockaddr *addr, + socklen_t addrlen) { struct HTTP_Server_Plugin *plugin = cls; struct GNUNET_HELLO_Address *address; struct HttpAddressWrapper *w = NULL; w = GNUNET_new (struct HttpAddressWrapper); - w->address = http_common_address_from_socket (plugin->protocol, addr, addrlen); + w->address = http_common_address_from_socket (plugin->protocol, + addr, + addrlen); if (NULL == w->address) { GNUNET_free (w); @@ -2244,7 +2253,9 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr, } w->addrlen = http_common_address_get_size (w->address); - GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w); + GNUNET_CONTAINER_DLL_insert (plugin->addr_head, + plugin->addr_tail, + w); LOG (GNUNET_ERROR_TYPE_DEBUG, "Notifying transport to add address `%s'\n", http_common_plugin_address_to_string (plugin->protocol, @@ -2259,7 +2270,9 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr, "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE); #endif - plugin->env->notify_address (plugin->env->cls, add_remove, address); + plugin->env->notify_address (plugin->env->cls, + add_remove, + address); GNUNET_HELLO_address_free (address); } @@ -2268,28 +2281,38 @@ server_add_address (void *cls, int add_remove, const struct sockaddr *addr, * Remove an address from the server's set of addresses and notify transport * * @param cls the plugin handle - * @param add_remove GNUNET_YES on add, GNUNET_NO on remove + * @param add_remove #GNUNET_YES on add, #GNUNET_NO on remove * @param addr the address * @param addrlen address length */ static void -server_remove_address (void *cls, int add_remove, const struct sockaddr *addr, - socklen_t addrlen) +server_remove_address (void *cls, + int add_remove, + const struct sockaddr *addr, + socklen_t addrlen) { struct HTTP_Server_Plugin *plugin = cls; struct GNUNET_HELLO_Address *address; struct HttpAddressWrapper *w = plugin->addr_head; size_t saddr_len; - void * saddr = http_common_address_from_socket (plugin->protocol, addr, addrlen); + void * saddr; + + saddr = http_common_address_from_socket (plugin->protocol, + addr, + addrlen); if (NULL == saddr) return; - saddr_len = http_common_address_get_size (saddr); + saddr_len = http_common_address_get_size (saddr); while (NULL != w) { - if (GNUNET_YES == http_common_cmp_addresses(w->address, w->addrlen, saddr, saddr_len)) - break; - w = w->next; + if (GNUNET_YES == + http_common_cmp_addresses (w->address, + w->addrlen, + saddr, + saddr_len)) + break; + w = w->next; } GNUNET_free (saddr); @@ -2301,10 +2324,9 @@ server_remove_address (void *cls, int add_remove, const struct sockaddr *addr, http_common_plugin_address_to_string (plugin->protocol, w->address, w->addrlen)); - - - GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); - + GNUNET_CONTAINER_DLL_remove (plugin->addr_head, + plugin->addr_tail, + w); /* modify our published address list */ #if BUILD_HTTPS address = GNUNET_HELLO_address_allocate (plugin->env->my_identity, @@ -2325,16 +2347,17 @@ server_remove_address (void *cls, int add_remove, const struct sockaddr *addr, * 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 + * @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 -server_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, - socklen_t addrlen) +server_nat_port_map_callback (void *cls, + int add_remove, + const struct sockaddr *addr, + socklen_t addrlen) { - GNUNET_assert (cls != NULL); struct HTTP_Server_Plugin *plugin = cls; LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -2403,7 +2426,8 @@ static int server_get_addresses (struct HTTP_Server_Plugin *plugin, const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, - struct sockaddr ***addrs, socklen_t ** addr_lens) + struct sockaddr ***addrs, + socklen_t ** addr_lens) { int disablev6; unsigned long long port; @@ -2591,7 +2615,8 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin) socklen_t *addrlens; res = server_get_addresses (plugin, - plugin->name, plugin->env->cfg, + plugin->name, + plugin->env->cfg, &addrs, &addrlens); LOG (GNUNET_ERROR_TYPE_DEBUG, _("Found %u addresses to report to NAT service\n"), @@ -2604,7 +2629,9 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin) } plugin->nat = - GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, + GNUNET_NAT_register (plugin->env->cfg, + GNUNET_YES, + plugin->port, (unsigned int) res, (const struct sockaddr **) addrs, addrlens, &server_nat_port_map_callback, NULL, plugin); @@ -2627,17 +2654,21 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin) static void server_stop_report_addresses (struct HTTP_Server_Plugin *plugin) { + struct HttpAddressWrapper *w; + /* Stop NAT handle */ if (NULL != plugin->nat) + { GNUNET_NAT_unregister (plugin->nat); - + plugin->nat = NULL; + } /* Clean up addresses */ - struct HttpAddressWrapper *w; - - while (plugin->addr_head != NULL) + while (NULL != plugin->addr_head) { w = plugin->addr_head; - GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); + GNUNET_CONTAINER_DLL_remove (plugin->addr_head, + plugin->addr_tail, + w); GNUNET_free (w->address); GNUNET_free (w); } @@ -2648,7 +2679,7 @@ server_stop_report_addresses (struct HTTP_Server_Plugin *plugin) * Check if IPv6 supported on this system * * @param plugin the plugin handle - * @return GNUNET_YES on success, else GNUNET_NO + * @return #GNUNET_YES on success, else #GNUNET_NO */ static int server_check_ipv6_support (struct HTTP_Server_Plugin *plugin) @@ -2689,7 +2720,8 @@ server_check_ipv6_support (struct HTTP_Server_Plugin *plugin) * @param tc task context (unused) */ static void -server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +server_notify_external_hostname (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { struct HTTP_Server_Plugin *plugin = cls; struct HttpAddress *ext_addr; @@ -2737,7 +2769,7 @@ server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskCo * Configure the plugin * * @param plugin plugin handle - * @return GNUNET_OK on success, GNUNET_SYSERR on failure + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ static int server_configure_plugin (struct HTTP_Server_Plugin *plugin) @@ -2754,7 +2786,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) (plugin->env->cfg, plugin->name, "USE_IPv4")) { plugin->use_ipv4 = - GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, + plugin->name, "USE_IPv4"); } else @@ -2768,7 +2801,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) (plugin->env->cfg, plugin->name, "USE_IPv6")) { plugin->use_ipv6 = - GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, + plugin->name, "USE_IPv6"); } else @@ -2786,7 +2820,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) /* Reading port number from config file */ if ((GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, + GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, + plugin->name, "PORT", &port)) || (port > 65535)) { LOG (GNUNET_ERROR_TYPE_ERROR, @@ -2830,7 +2865,8 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) if ((plugin->use_ipv6 == GNUNET_YES) && (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + plugin->name, "BINDTO6", &bind6_address))) { LOG (GNUNET_ERROR_TYPE_DEBUG, @@ -2861,84 +2897,99 @@ 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, + 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 = 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; - if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, - "EXTERNAL_HOSTNAME", &eh_tmp)) + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, + plugin->name, + "EXTERNAL_HOSTNAME", + &eh_tmp)) { - char * tmp = NULL; - char * pos = NULL; - char * pos_url = NULL; + char *tmp; + char *pos = NULL; + char *pos_url = NULL; - if (NULL != strstr(eh_tmp, "://")) - { - tmp = &strstr(eh_tmp, "://")[3]; - } - else - tmp = eh_tmp; + if (NULL != strstr(eh_tmp, "://")) + tmp = &strstr(eh_tmp, "://")[3]; + else + tmp = eh_tmp; - if (GNUNET_YES == external_hostname_use_port) + if (GNUNET_YES == external_hostname_use_port) + { + if ( (strlen (tmp) > 1) && (NULL != (pos = strchr(tmp, '/'))) ) { - if ( (strlen (tmp) > 1) && (NULL != (pos = strchr(tmp, '/'))) ) - { - pos_url = pos + 1; - pos[0] = '\0'; - GNUNET_asprintf (&plugin->external_hostname, "%s:%u/%s", tmp, (uint16_t) port, (NULL == pos_url) ? "" : pos_url); - } - else - GNUNET_asprintf (&plugin->external_hostname, "%s:%u", tmp, (uint16_t) port); + pos_url = pos + 1; + pos[0] = '\0'; + GNUNET_asprintf (&plugin->external_hostname, + "%s:%u/%s", + tmp, + (uint16_t) port, + (NULL == pos_url) ? "" : pos_url); } else - plugin->external_hostname = GNUNET_strdup (tmp); - GNUNET_free (eh_tmp); - - LOG (GNUNET_ERROR_TYPE_INFO, - _("Using external hostname `%s'\n"), - plugin->external_hostname); - plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (&server_notify_external_hostname, plugin); + GNUNET_asprintf (&plugin->external_hostname, + "%s:%u", + tmp, + (uint16_t) port); + } + else + plugin->external_hostname = GNUNET_strdup (tmp); + GNUNET_free (eh_tmp); - /* Use only configured external hostname */ - if (GNUNET_CONFIGURATION_have_value - (plugin->env->cfg, plugin->name, "EXTERNAL_HOSTNAME_ONLY")) - { - plugin->external_only = - GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, - "EXTERNAL_HOSTNAME_ONLY"); - } - else - plugin->external_only = GNUNET_NO; + LOG (GNUNET_ERROR_TYPE_INFO, + _("Using external hostname `%s'\n"), + plugin->external_hostname); + plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (&server_notify_external_hostname, + plugin); + + /* Use only configured external hostname */ + if (GNUNET_CONFIGURATION_have_value + (plugin->env->cfg, + plugin->name, + "EXTERNAL_HOSTNAME_ONLY")) + { + plugin->external_only = + GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, + plugin->name, + "EXTERNAL_HOSTNAME_ONLY"); + } + else + plugin->external_only = GNUNET_NO; - if (GNUNET_YES == plugin->external_only) - LOG (GNUNET_ERROR_TYPE_DEBUG, - _("Notifying transport only about hostname `%s'\n"), - plugin->external_hostname); + if (GNUNET_YES == plugin->external_only) + LOG (GNUNET_ERROR_TYPE_DEBUG, + _("Notifying transport only about hostname `%s'\n"), + plugin->external_hostname); } else LOG (GNUNET_ERROR_TYPE_DEBUG, "No external hostname configured\n"); /* Optional parameters */ - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, - plugin->name, - "MAX_CONNECTIONS", &max_connections)) + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, + plugin->name, + "MAX_CONNECTIONS", + &max_connections)) max_connections = 128; plugin->max_connections = max_connections; - LOG (GNUNET_ERROR_TYPE_DEBUG, - _("Maximum number of connections is %u\n"), - plugin->max_connections); - + LOG (GNUNET_ERROR_TYPE_DEBUG, + _("Maximum number of connections is %u\n"), + plugin->max_connections); plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity)); @@ -2946,74 +2997,6 @@ server_configure_plugin (struct HTTP_Server_Plugin *plugin) } -/** - * Session was idle, so disconnect it - * - * @param cls the session - * @param tc task context - */ -static void -server_session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct Session *s = cls; - - s->timeout_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_log (TIMEOUT_LOG, - "Session %p was idle for %s, disconnecting\n", - s, - GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT, - GNUNET_YES)); - - /* call session destroy function */ - GNUNET_assert (GNUNET_OK == - http_server_plugin_disconnect_session (s->plugin, s)); -} - - -/** -* Start session timeout for session s -* -* @param s the session -*/ -static void -server_start_session_timeout (struct Session *s) -{ - GNUNET_assert (NULL != s); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); - s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT, - &server_session_timeout, - s); - GNUNET_log (TIMEOUT_LOG, - "Timeout for session %p set to %s\n", - s, - GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT, - GNUNET_YES)); -} - - -/** -* Increment session timeout due to activity session s -* -* @param s the session -*/ -static void -server_reschedule_session_timeout (struct Session *s) -{ - GNUNET_assert (NULL != s); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); - - GNUNET_SCHEDULER_cancel (s->timeout_task); - s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_SERVER_SESSION_TIMEOUT, - &server_session_timeout, - s); - GNUNET_log (TIMEOUT_LOG, - "Timeout rescheduled for session %p set to %s\n", - s, - GNUNET_STRINGS_relative_time_to_string (HTTP_SERVER_SESSION_TIMEOUT, - GNUNET_YES)); -} - - /** * Exit point from the plugin. * @@ -3025,8 +3008,6 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct HTTP_Server_Plugin *plugin = api->cls; - struct Session *pos; - struct Session *next; if (NULL == api->cls) { @@ -3068,29 +3049,17 @@ LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) /* Stop to report addresses to transport service */ server_stop_report_addresses (plugin); server_stop (plugin); - next = plugin->head; - while (NULL != (pos = next)) - { - next = pos->next; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Removing left over session %p\n", - pos); - - if ((GNUNET_YES == pos->session_passed) && (GNUNET_NO == pos->session_ended)) - { - /* Notify transport immediately that this session is invalid */ - pos->session_ended = GNUNET_YES; - plugin->env->session_end (plugin->env->cls, pos->address, pos); - } - server_delete_session (plugin, pos); - } - + GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions, + &destroy_session_cb, + plugin); + GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions); + plugin->sessions = NULL; /* Clean up */ GNUNET_free_non_null (plugin->external_hostname); GNUNET_free_non_null (plugin->ext_addr); GNUNET_free_non_null (plugin->server_addr_v4); GNUNET_free_non_null (plugin->server_addr_v6); - regfree(&plugin->url_regex); + regfree (&plugin->url_regex); LOG (GNUNET_ERROR_TYPE_DEBUG, _("Shutdown for plugin `%s' complete\n"), @@ -3136,11 +3105,66 @@ static enum GNUNET_ATS_Network_Type http_server_get_network (void *cls, struct Session *session) { - GNUNET_assert (NULL != session); return ntohl (session->ats_address_network_type); } +/** + * Return information about the given session to the + * monitor callback. + * + * @param cls the `struct Plugin` with the monitor callback (`sic`) + * @param peer peer we send information about + * @param value our `struct Session` to send information about + * @return #GNUNET_OK (continue to iterate) + */ +static int +send_session_info_iter (void *cls, + const struct GNUNET_PeerIdentity *peer, + void *value) +{ + struct HTTP_Server_Plugin *plugin = cls; + struct Session *session = value; + + notify_session_monitor (plugin, + session, + GNUNET_TRANSPORT_SS_UP); + return GNUNET_OK; +} + + +/** + * Begin monitoring sessions of a plugin. There can only + * be one active monitor per plugin (i.e. if there are + * multiple monitors, the transport service needs to + * multiplex the generated events over all of them). + * + * @param cls closure of the plugin + * @param sic callback to invoke, NULL to disable monitor; + * plugin will being by iterating over all active + * sessions immediately and then enter monitor mode + * @param sic_cls closure for @a sic + */ +static void +http_server_plugin_setup_monitor (void *cls, + GNUNET_TRANSPORT_SessionInfoCallback sic, + void *sic_cls) +{ + struct HTTP_Server_Plugin *plugin = cls; + + plugin->sic = sic; + plugin->sic_cls = sic_cls; + if (NULL != sic) + { + GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions, + &send_session_info_iter, + plugin); + /* signal end of first iteration */ + sic (sic_cls, NULL, NULL); + } +} + + /** * Entry point for the plugin. * @@ -3167,6 +3191,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) } plugin = GNUNET_new (struct HTTP_Server_Plugin); plugin->env = env; + plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128, + GNUNET_YES); api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions); api->cls = plugin; api->send = &http_server_plugin_send; @@ -3181,6 +3207,8 @@ LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) api->address_pretty_printer = &http_common_plugin_address_pretty_printer; api->get_network = &http_server_get_network; api->update_session_timeout = &http_server_plugin_update_session_timeout; + // api->update_inbound_delay = &http_server_plugin_update_inbound_delay; // FIXME: implement/support! + api->setup_monitor = &http_server_plugin_setup_monitor; #if BUILD_HTTPS plugin->name = "transport-https_server"; plugin->protocol = "https"; diff --git a/src/transport/test_transport_api_http_reverse_peer1.conf b/src/transport/test_transport_api_http_reverse_peer1.conf index 351b29746..aebaf88e2 100644 --- a/src/transport/test_transport_api_http_reverse_peer1.conf +++ b/src/transport/test_transport_api_http_reverse_peer1.conf @@ -1,4 +1,4 @@ -INLINE@ template_cfg_peer1.conf +@INLINE@ template_cfg_peer1.conf [PATHS] GNUNET_TEST_HOME = /tmp/test-transport/api-http-p1/ diff --git a/src/transport/test_transport_api_http_reverse_peer2.conf b/src/transport/test_transport_api_http_reverse_peer2.conf index 0283d12b5..210e44a02 100644 --- a/src/transport/test_transport_api_http_reverse_peer2.conf +++ b/src/transport/test_transport_api_http_reverse_peer2.conf @@ -1,4 +1,4 @@ -INLINE@ template_cfg_peer2.conf +@INLINE@ template_cfg_peer2.conf [PATHS] GNUNET_TEST_HOME = /tmp/test-transport/api-http-p2/ diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c index b2af478e1..d25d3f4b7 100644 --- a/src/transport/transport-testing.c +++ b/src/transport/transport-testing.c @@ -259,8 +259,8 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth /* Create configuration and call testing lib to modify it */ p->cfg = GNUNET_CONFIGURATION_create (); - GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); - + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (p->cfg, cfgname)); if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg)) { LOG (GNUNET_ERROR_TYPE_ERROR, diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in index 20a878c2e..845c4d384 100644 --- a/src/transport/transport.conf.in +++ b/src/transport/transport.conf.in @@ -68,11 +68,11 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM; # PROXY = # User name for proxy server -# PROXY_USERNAME = +# PROXY_USERNAME = # User password for proxy server -# PROXY_PASSWORD = +# PROXY_PASSWORD = -# Type of proxy server, +# Type of proxy server, # Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME # Default: HTTP # PROXY_TYPE = HTTP @@ -95,11 +95,11 @@ TESTING_IGNORE_KEYS = ACCEPT_FROM; # PROXY = # User name for proxy server -# PROXY_USERNAME = +# PROXY_USERNAME = # User password for proxy server -# PROXY_PASSWORD = +# PROXY_PASSWORD = -# Type of proxy server, +# Type of proxy server, # Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME # Default: HTTP # PROXY_TYPE = HTTP -- cgit v1.2.3