/* 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/S client transport plugin * @author Matthias Wachs */ #if BUILD_HTTPS #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_client_init #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_client_done #else #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_client_init #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_client_done #endif #include "platform.h" #include "gnunet_protocols.h" #include "gnunet_connection_lib.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "plugin_transport_http_common.h" #include #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING /** * 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) /** * Encapsulation of all of the state of the plugin. */ struct HTTP_Client_Plugin; /** * Session handle for connections. */ struct Session { /** * To whom are we talking to (set to our identity * if we are still waiting for the welcome message) */ struct GNUNET_PeerIdentity sender; /** * Stored in a linked list. */ struct Session *next; /** * Pointer to the global plugin struct. */ struct HTTP_Client_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; /** * Closure for transmit_cont. */ void *transmit_cont_cls; /** * 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; }; /** * Encapsulation of all of the state of the plugin. */ struct HTTP_Client_Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * Linked list head of open sessions. */ struct Session *head; /** * Linked list tail of open sessions. */ struct Session *tail; /** * Plugin name */ char *name; /** * Protocol */ char *protocol; /** * use IPv6 */ uint16_t use_ipv6; /** * use IPv4 */ uint16_t use_ipv4; /** * cURL Multihandle */ CURLM *curl_multi_handle; }; /** * 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 session which session must be used * @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 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_client_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 HTTP_Client_Plugin *plugin = cls; int bytes_sent = 0; GNUNET_assert (plugin != NULL); GNUNET_assert (session != NULL); /* struct Plugin *plugin = cls; */ return bytes_sent; } /** * 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_client_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { // struct Plugin *plugin = cls; // FIXME } static void client_stop (struct HTTP_Client_Plugin *plugin) { if (NULL != plugin->curl_multi_handle) { curl_multi_cleanup (plugin->curl_multi_handle); plugin->curl_multi_handle = NULL; } curl_global_cleanup (); } static int client_start (struct HTTP_Client_Plugin *plugin) { curl_global_init (CURL_GLOBAL_ALL); plugin->curl_multi_handle = curl_multi_init (); if (NULL == plugin->curl_multi_handle) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("Could not initialize curl multi handle, failed to start %s plugin!\n"), plugin->name); return GNUNET_SYSERR; } return GNUNET_OK; } /** * 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_client_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) { /* struct Plugin *plugin = cls; */ /* A HTTP/S client does not have any valid address so:*/ return GNUNET_NO; } /** * Exit point from the plugin. */ void * LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct HTTP_Client_Plugin *plugin = api->cls; client_stop (plugin); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /** * Entry point for the plugin. */ void * LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct HTTP_Client_Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct HTTP_Client_Plugin)); plugin->env = env; api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->send = &http_client_plugin_send; api->disconnect = &http_client_plugin_disconnect; api->check_address = &http_client_plugin_address_suggested; api->address_to_string = &http_common_plugin_address_to_string; api->string_to_address = &http_common_plugin_string_to_address; api->address_pretty_printer = &http_common_plugin_address_pretty_printer; #if BUILD_HTTPS plugin->name = "transport-https_client"; plugin->protocol = "https"; #else plugin->name = "transport-http_client"; plugin->protocol = "http"; #endif /* Start client */ if (GNUNET_SYSERR == client_start (plugin)) { LIBGNUNET_PLUGIN_TRANSPORT_DONE (api); return NULL; } return api; } /* end of plugin_transport_http_client.c */