(no commit message)
[oweals/gnunet.git] / src / transport / plugin_transport_http.c
index 297bc8c077546d7866d23e6b563a236555c7af31..f04929af9abeaaccb35ab267b2445d78d001fb32 100644 (file)
 */
 
 /**
- * @file transport/plugin_transport_http.c
- * @brief Implementation of the HTTP transport service
- * @author Matthias Wachs
+ * @file transport/plugin_transport_template.c
+ * @brief template for a new transport service
+ * @author Christian Grothoff
  */
 
 #include "platform.h"
+#include "gnunet_constants.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_resolver_service.h"
 #include "plugin_transport.h"
 #include "microhttpd.h"
 #include <curl/curl.h>
 
-#define VERBOSE GNUNET_YES
-#define DEBUG GNUNET_YES
+#define DEBUG_HTTP GNUNET_NO
+
+/**
+ * Text of the response sent back after the last bytes of a PUT
+ * request have been received (just to formally obey the HTTP
+ * protocol).
+ */
+#define HTTP_PUT_RESPONSE "Thank you!"
 
 /**
  * After how long do we expire an address that we
  */
 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
 
-#define HTTP_TIMEOUT 600
-
-#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0);
+/**
+ * Page returned if request invalid
+ */
+#define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
 
 /**
- * Text of the response sent back after the last bytes of a PUT
- * request have been received (just to formally obey the HTTP
- * protocol).
+ * Timeout for a http connect
  */
-#define HTTP_PUT_RESPONSE "Thank you!"
+#define HTTP_CONNECT_TIMEOUT 30
+
 
 /**
  * Encapsulation of all of the state of the plugin.
  */
 struct Plugin;
 
+struct CBC
+{
+  char *buf;
+  size_t pos;
+  size_t size;
+  size_t len;
+};
+
 
 /**
  * Session handle for connections.
@@ -78,11 +94,6 @@ struct Session
    */
   struct Plugin *plugin;
 
-  /**
-   * The client (used to identify this connection)
-   */
-  /* void *client; */
-
   /**
    * Continuation function to call once the transmission buffer
    * has again space available.  NULL if there is no
@@ -101,6 +112,31 @@ struct Session
    */
   struct GNUNET_PeerIdentity sender;
 
+  /**
+   * Sender's url
+   */
+  char * url;
+
+  /**
+   * Sender's ip address to distinguish between incoming connections
+   */
+  char * ip;
+
+  /**
+   * Sender's ip address to distinguish between incoming connections
+   */
+  struct sockaddr_in * addr;
+
+  /**
+   * Did we initiate the connection (GNUNET_YES) or the other peer (GNUNET_NO)?
+   */
+  unsigned int is_client;
+
+  /**
+   * Is the connection active (GNUNET_YES) or terminated (GNUNET_NO)?
+   */
+  unsigned int is_active;
+
   /**
    * At what time did we reset last_received last?
    */
@@ -118,6 +154,19 @@ struct Session
    */
   uint32_t quota;
 
+  /**
+   * Is there a HTTP/PUT in progress?
+   */
+  unsigned int is_put_in_progress;
+
+  /**
+   * Encoded hash
+   */
+  struct GNUNET_CRYPTO_HashAsciiEncoded hash;
+
+  struct CBC cbc;
+
+  CURL *curl_handle;
 };
 
 /**
@@ -139,9 +188,13 @@ struct Plugin
    * List of open sessions.
    */
   struct Session *sessions;
-};
 
-static struct Plugin *plugin;
+  /**
+   * Number of active sessions
+   */
+
+  unsigned int session_count;
+};
 
 /**
  * Daemon for listening for new IPv4 connections.
@@ -163,121 +216,570 @@ static GNUNET_SCHEDULER_TaskIdentifier http_task_v4;
  */
 static GNUNET_SCHEDULER_TaskIdentifier http_task_v6;
 
+
 /**
- * ID of the task downloading the hostlist
+ * Our primary task for http daemon handling IPv6 connections
  */
-static GNUNET_SCHEDULER_TaskIdentifier ti_download;
+static GNUNET_SCHEDULER_TaskIdentifier http_task_send;
+
+
+/**
+ * Information about this plugin
+ */
+static struct Plugin *plugin;
 
-static int running;
+/**
+ * cURL Multihandle
+ */
+static CURLM *multi_handle;
 
 /**
- * Buffer for data downloaded via HTTP.
+ * Our hostname
  */
-static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
+static char * hostname;
 
 /**
- * Curl multi for managing client operations.
+ * Our ASCII encoded, hashed peer identity
+ * This string is used to distinguish between connections and is added to the urls
  */
-static CURLM *curl_multi;
-static CURL  *curl;
+static struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
 
-static char * get_url( const struct GNUNET_PeerIdentity * target)
+static char buf[2048];
+static char test[2048] = "HEEEELLLO";
+
+/**
+ * Message-Packet header.
+ */
+struct HTTPMessage
 {
-  return strdup("http://localhost:12389");
-}
+  /**
+   * size of the message, in bytes, including this header.
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * What is the identity of the sender (GNUNET_hash of public key)
+   */
+  struct GNUNET_PeerIdentity sender;
+
+};
 
-static size_t curl_read_function( void *ptr, size_t size, size_t nmemb, void *stream)
+/**
+ * Finds a http session in our linked list using peer identity as a key
+ * @param peer peeridentity
+ * @return http session corresponding to peer identity
+ */
+static struct Session * find_session_by_pi( const struct GNUNET_PeerIdentity *peer )
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl read function\n");
-  // strcpy ("Testmessa")
-  return 0;
+  struct Session * cur;
+  GNUNET_HashCode hc_peer;
+  GNUNET_HashCode hc_current;
+
+  cur = plugin->sessions;
+  hc_peer = peer->hashPubKey;
+  while (cur != NULL)
+  {
+    hc_current = cur->sender.hashPubKey;
+    if ( 0 == GNUNET_CRYPTO_hash_cmp( &hc_peer, &hc_current))
+      return cur;
+    cur = plugin->sessions->next;
+  }
+  return NULL;
 }
 
 /**
- * Task that is run when we are ready to receive more data from the hostlist
- * server.
+ * Create a new session
  *
- * @param cls closure, unused
- * @param tc task context, unused
+ * @param address address the peer is using
+ * @peer  peer identity
+ * @return created session object
  */
-static void
-task_download (void *cls,
-             const struct GNUNET_SCHEDULER_TaskContext *tc)
+
+static struct Session * create_session (struct sockaddr_in *address, const struct GNUNET_PeerIdentity *peer)
 {
-  ti_download = GNUNET_SCHEDULER_NO_TASK;
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    return;
+  struct sockaddr_in  *addrin;
+  struct sockaddr_in6 *addrin6;
+
+  struct Session * ses = GNUNET_malloc ( sizeof( struct Session) );
+  ses->addr = GNUNET_malloc ( sizeof (struct sockaddr_in) );
+
+  ses->next = NULL;
+  ses->plugin = plugin;
 
+  memcpy(ses->addr, address, sizeof (struct sockaddr_in));
+  if ( AF_INET == address->sin_family)
+  {
+    ses->ip = GNUNET_malloc (INET_ADDRSTRLEN);
+    addrin = address;
+    inet_ntop(addrin->sin_family,&(addrin->sin_addr),ses->ip,INET_ADDRSTRLEN);
+  }
+  if ( AF_INET6 == address->sin_family)
+  {
+    ses->ip = GNUNET_malloc (INET6_ADDRSTRLEN);
+    addrin6 = (struct sockaddr_in6 *) address;
+    inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr) ,ses->ip,INET6_ADDRSTRLEN);
+  }
+  memcpy(&ses->sender, peer, sizeof (struct GNUNET_PeerIdentity));
+  GNUNET_CRYPTO_hash_to_enc(&ses->sender.hashPubKey,&(ses->hash));
+  ses->is_active = GNUNET_NO;
+
+  return ses;
+}
+
+/**
+ * Callback called by MHD when a connection is terminated
+ */
+static void requestCompletedCallback (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
+{
+  struct Session * cs;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Download!!!\n");
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Logging shutdown\n");
-  GNUNET_STATISTICS_set(plugin->env->stats,"shutdown",2, GNUNET_NO);
+  cs = *httpSessionCache;
+  if (cs != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection from peer `%s' was terminated\n",GNUNET_i2s(&cs->sender));
+    /* session set to inactive */
+    cs->is_active = GNUNET_NO;
+    cs->is_put_in_progress = GNUNET_NO;
+  }
+  return;
 }
+
 /**
- * Ask CURL for the select set and then schedule the
- * receiving task with the scheduler.
+ * Check if we are allowed to connect to the given IP.
+ */
+static int
+acceptPolicyCallback (void *cls,
+                      const struct sockaddr *addr, socklen_t addr_len)
+{
+  /* Every connection is accepted, nothing more to do here */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connect!\n");
+  return MHD_YES;
+}
+
+
+
+/**
+ * Process GET or PUT request received via MHD.  For
+ * GET, queue response that will send back our pending
+ * messages.  For PUT, process incoming data and send
+ * to GNUnet core.  In either case, check if a session
+ * already exists and create a new one if not.
+ */
+static int
+accessHandlerCallback (void *cls,
+                       struct MHD_Connection *session,
+                       const char *url,
+                       const char *method,
+                       const char *version,
+                       const char *upload_data,
+                       size_t * upload_data_size, void **httpSessionCache)
+{
+  struct MHD_Response *response;
+  struct Session * cs;
+  struct Session * cs_temp;
+  const union MHD_ConnectionInfo * conn_info;
+  struct sockaddr_in  *addrin;
+  struct sockaddr_in6 *addrin6;
+  char * address = NULL;
+  struct GNUNET_PeerIdentity pi_in;
+  int res = GNUNET_NO;
+  size_t bytes_recv;
+  struct GNUNET_MessageHeader *gn_msg;
+  int send_error_to_client;
+
+  gn_msg = NULL;
+  send_error_to_client = GNUNET_NO;
+  if ( NULL == *httpSessionCache)
+  {
+    /* check url for peer identity */
+    res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
+    if ( GNUNET_SYSERR == res )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident\n");
+      response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
+      res = MHD_queue_response (session, MHD_HTTP_NOT_FOUND, response);
+      MHD_destroy_response (response);
+      return res;
+    }
+
+    conn_info = MHD_get_connection_info(session, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
+    /* Incoming IPv4 connection */
+    if ( AF_INET == conn_info->client_addr->sin_family)
+    {
+      address = GNUNET_malloc (INET_ADDRSTRLEN);
+      addrin = conn_info->client_addr;
+      inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
+    }
+    /* Incoming IPv6 connection */
+    if ( AF_INET6 == conn_info->client_addr->sin_family)
+    {
+      address = GNUNET_malloc (INET6_ADDRSTRLEN);
+      addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
+      inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
+    }
+    /* find existing session for address */
+    cs = NULL;
+    if (plugin->session_count > 0)
+    {
+      cs = plugin->sessions;
+      while ( NULL != cs)
+      {
+
+        /* Comparison based on ip address */
+        // res = (0 == memcmp(&(conn_info->client_addr->sin_addr),&(cs->addr->sin_addr), sizeof (struct in_addr))) ? GNUNET_YES : GNUNET_NO;
+
+        /* Comparison based on ip address, port number and address family */
+        // res = (0 == memcmp((conn_info->client_addr),(cs->addr), sizeof (struct sockaddr_in))) ? GNUNET_YES : GNUNET_NO;
+
+        /* Comparison based on PeerIdentity */
+        res = (0 == memcmp(&pi_in,&(cs->sender), sizeof (struct GNUNET_PeerIdentity))) ? GNUNET_YES : GNUNET_NO;
+
+        if ( GNUNET_YES  == res)
+        {
+          /* existing session for this address found */
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session `%s' found\n",address);
+          break;
+        }
+        cs = cs->next;
+      }
+    }
+    /* no existing session, create a new one*/
+    if (cs == NULL )
+    {
+      /* create new session object */
+      cs = create_session(conn_info->client_addr, &pi_in);
+
+      /* Insert session into linked list */
+      if ( plugin->sessions == NULL)
+      {
+        plugin->sessions = cs;
+        plugin->session_count = 1;
+      }
+      cs_temp = plugin->sessions;
+      while ( cs_temp->next != NULL )
+      {
+        cs_temp = cs_temp->next;
+      }
+      if (cs_temp != cs )
+      {
+        cs_temp->next = cs;
+        plugin->session_count++;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"New Session `%s' inserted, count %u \n", address, plugin->session_count);
+    }
+    /* Set closure */
+    if (*httpSessionCache == NULL)
+    {
+      *httpSessionCache = cs;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has new an incoming `%s' request from peer `%s' (`[%s]:%u')\n",method, GNUNET_i2s(&cs->sender),cs->ip,cs->addr->sin_port);
+  }
+  else
+  {
+    cs = *httpSessionCache;
+  }
+  /* Is it a PUT or a GET request */
+  if ( 0 == strcmp (MHD_HTTP_METHOD_PUT, method) )
+  {
+    /* New  */
+    if ((*upload_data_size == 0) && (cs->is_put_in_progress == GNUNET_NO))
+    {
+      /* not yet ready */
+      cs->is_put_in_progress = GNUNET_YES;
+      cs->is_active = GNUNET_YES;
+      return MHD_YES;
+    }
+    if ( *upload_data_size > 0 )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"PUT URL: `%s'\n",url);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"PUT Request: %lu bytes: `%s' \n", (*upload_data_size), upload_data);
+      /* No data left */
+      bytes_recv = *upload_data_size ;
+      *upload_data_size = 0;
+
+      /* checking size */
+      if (bytes_recv < sizeof (struct GNUNET_MessageHeader))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Message too small, is %u bytes, has to be at least %u '\n",bytes_recv, sizeof(struct GNUNET_MessageHeader));
+        send_error_to_client = GNUNET_YES;
+      }
+
+      if ( bytes_recv > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Message too big, is %u bytes, maximum %u '\n",bytes_recv, GNUNET_SERVER_MAX_MESSAGE_SIZE);
+        send_error_to_client = GNUNET_YES;
+      }
+
+      struct GNUNET_MessageHeader * gn_msg = GNUNET_malloc (bytes_recv);
+      memcpy (gn_msg,upload_data,bytes_recv);
+
+      if ( ntohs(gn_msg->size) != bytes_recv )
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Message has incorrect size, is %u bytes vs %u recieved'\n",ntohs(gn_msg->size) , bytes_recv);
+        GNUNET_free (gn_msg);
+        send_error_to_client = GNUNET_YES;
+      }
+
+      if ( GNUNET_YES == send_error_to_client)
+      {
+        response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
+        res = MHD_queue_response (session, MHD_HTTP_BAD_REQUEST, response);
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 400 BAD REQUEST as PUT Response\n",HTTP_PUT_RESPONSE, strlen (HTTP_PUT_RESPONSE), res );
+        MHD_destroy_response (response);
+        return MHD_NO;
+      }
+
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Recieved GNUnet message type %u size %u and payload %u \n",ntohs (gn_msg->type), ntohs (gn_msg->size), ntohs (gn_msg->size)-sizeof(struct GNUNET_MessageHeader));
+
+      /* forwarding message to transport */
+      plugin->env->receive(plugin->env, &(cs->sender), gn_msg, 1, cs , cs->ip, strlen(cs->ip) );
+      return MHD_YES;
+    }
+    if ((*upload_data_size == 0) && (cs->is_put_in_progress == GNUNET_YES))
+    {
+      cs->is_put_in_progress = GNUNET_NO;
+      response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
+      res = MHD_queue_response (session, MHD_HTTP_OK, response);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 200 OK as PUT Response\n",HTTP_PUT_RESPONSE, strlen (HTTP_PUT_RESPONSE), res );
+      MHD_destroy_response (response);
+      return res;
+    }
+  }
+  if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Got GET Request\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"URL: `%s'\n",url);
+    response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
+    res = MHD_queue_response (session, MHD_HTTP_OK, response);
+    MHD_destroy_response (response);
+    return res;
+  }
+  return MHD_NO;
+}
+
+
+/**
+ * Call MHD to process pending requests and then go back
+ * and schedule the next run.
+ */
+static void http_daemon_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier
+http_daemon_prepare (struct MHD_Daemon *daemon_handle)
+{
+  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;
+  unsigned long long timeout;
+  int haveto;
+  struct GNUNET_TIME_Relative tv;
+
+  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)
+    tv.value = (uint64_t) timeout;
+  else
+    tv = GNUNET_TIME_UNIT_FOREVER_REL;
+  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
+  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
+  GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
+  ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
+                                     GNUNET_SCHEDULER_PRIORITY_HIGH,
+                                     GNUNET_SCHEDULER_NO_TASK,
+                                     tv,
+                                     wrs,
+                                     wws,
+                                     &http_daemon_run,
+                                     daemon_handle);
+  GNUNET_NETWORK_fdset_destroy (wrs);
+  GNUNET_NETWORK_fdset_destroy (wws);
+  GNUNET_NETWORK_fdset_destroy (wes);
+  return ret;
+}
+
+/**
+ * Call MHD to process pending requests and then go back
+ * and schedule the next run.
  */
 static void
-download_prepare ()
+http_daemon_run (void *cls,
+            const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct MHD_Daemon *daemon_handle = cls;
+
+  if (daemon_handle == http_daemon_v4)
+    http_task_v4 = GNUNET_SCHEDULER_NO_TASK;
+
+  if (daemon_handle == http_daemon_v6)
+    http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+
+
+  GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
+  if (daemon_handle == http_daemon_v4)
+    http_task_v4 = http_daemon_prepare (daemon_handle);
+  if (daemon_handle == http_daemon_v6)
+    http_task_v6 = http_daemon_prepare (daemon_handle);
+  return;
+}
+
+static size_t send_read_callback(void *stream, size_t size, size_t nmemb, void *ptr)
+{
+  struct Session  * ses = ptr;
+  struct CBC * cbc = &(ses->cbc);
+
+  if (cbc->len > (size * nmemb))
+    return CURL_READFUNC_ABORT;
+
+  if (( cbc->pos == cbc->len) && (cbc->len < (size * nmemb)))
+    return 0;
+  memcpy(stream, cbc->buf, cbc->len);
+  cbc->pos = cbc->len;
+  return cbc->len;
+}
+
+
+static size_t send_prepare(struct Session* session );
+
+static void send_execute (void *cls,
+             const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  int running;
+  struct CURLMsg *msg;
   CURLMcode mret;
+  char * current_url= "test";
+
+ // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"send_execute\n");
+
+  http_task_send = GNUNET_SCHEDULER_NO_TASK;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+  do
+    {
+      running = 0;
+      mret = curl_multi_perform (multi_handle, &running);
+      //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"send_execute %u\n", running);
+      if (running == 0)
+        {
+          do
+            {
+
+              msg = curl_multi_info_read (multi_handle, &running);
+              GNUNET_break (msg != NULL);
+              if (msg == NULL)
+                break;
+              switch (msg->msg)
+                {
+                case CURLMSG_DONE:
+                  if ( (msg->data.result != CURLE_OK) &&
+                       (msg->data.result != CURLE_GOT_NOTHING) )
+                    GNUNET_log(GNUNET_ERROR_TYPE_INFO,
+                               _("%s failed for `%s' at %s:%d: `%s'\n"),
+                               "curl_multi_perform",
+                               current_url,
+                               __FILE__,
+                               __LINE__,
+                               curl_easy_strerror (msg->data.result));
+                  else
+                    {
+                    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                                _("Download of hostlist `%s' completed.\n"),
+                                current_url);
+                    }
+                  return;
+                default:
+                  break;
+                }
+
+            }
+          while ( (running > 0) );
+        }
+    }
+  while (mret == CURLM_CALL_MULTI_PERFORM);
+  send_prepare(cls);
+}
+
+
+static size_t send_prepare(struct Session* session )
+{
   fd_set rs;
   fd_set ws;
   fd_set es;
   int max;
   struct GNUNET_NETWORK_FDSet *grs;
   struct GNUNET_NETWORK_FDSet *gws;
-  long timeout;
-  struct GNUNET_TIME_Relative rtime;
+  long to;
+  CURLMcode mret;
 
+//  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"send_prepare\n");
   max = -1;
   FD_ZERO (&rs);
   FD_ZERO (&ws);
   FD_ZERO (&es);
-  mret = curl_multi_fdset (curl_multi, &rs, &ws, &es, &max);
+  mret = curl_multi_fdset (multi_handle, &rs, &ws, &es, &max);
   if (mret != CURLM_OK)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("%s failed at %s:%d: `%s'\n"),
                   "curl_multi_fdset", __FILE__, __LINE__,
                   curl_multi_strerror (mret));
-      /*clean_up ();*/
-      return;
+      return -1;
     }
-  mret = curl_multi_timeout (curl_multi, &timeout);
+  mret = curl_multi_timeout (multi_handle, &to);
   if (mret != CURLM_OK)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("%s failed at %s:%d: `%s'\n"),
                   "curl_multi_timeout", __FILE__, __LINE__,
                   curl_multi_strerror (mret));
-      /* clean_up ();*/
-      return;
+      return -1;
     }
 
-  rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0 );
-  /*rtime = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time),
-                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
-                                                                   timeout));*/
   grs = GNUNET_NETWORK_fdset_create ();
   gws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Scheduling http plugin send operation using cURL\n");
-  ti_download = GNUNET_SCHEDULER_add_select (plugin->env->sched,
-                                             GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                             GNUNET_SCHEDULER_NO_TASK,
-                                             rtime,
-                                             grs,
-                                             gws,
-                                             &task_download,
-                                             curl_multi);
+  http_task_send = GNUNET_SCHEDULER_add_select (plugin->env->sched,
+                                   GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                   GNUNET_SCHEDULER_NO_TASK,
+                                   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
+                                   grs,
+                                   gws,
+                                   &send_execute,
+                                   session);
   GNUNET_NETWORK_fdset_destroy (gws);
   GNUNET_NETWORK_fdset_destroy (grs);
+
+  /* FIXME: return bytes REALLY sent */
+  return 0;
 }
 
+
 /**
  * Function that can be used by the transport service to transmit
  * a message using the plugin.
@@ -287,7 +789,7 @@ download_prepare ()
  * @param priority how important is the message
  * @param msgbuf the message to transmit
  * @param msgbuf_size number of bytes in 'msgbuf'
- * @param timeout when should we time out 
+ * @param timeout when should we time out
  * @param session which session must be used (or NULL for "any")
  * @param addr the address to use (can be NULL if the plugin
  *                is "on its own" (i.e. re-use existing TCP connection))
@@ -306,98 +808,97 @@ download_prepare ()
  */
 static ssize_t
 http_plugin_send (void *cls,
-                  const struct GNUNET_PeerIdentity * target,
-                  const char *msgbuf,
-                  size_t msgbuf_size,
-                  unsigned int priority,
-                  struct GNUNET_TIME_Relative timeout,
-                  struct Session *session,
-                  const void *addr,
-                  size_t addrlen,
-                  int force_address,
-                  GNUNET_TRANSPORT_TransmitContinuation cont,
-                  void *cont_cls)
+                      const struct GNUNET_PeerIdentity *target,
+                      const char *msgbuf,
+                      size_t msgbuf_size,
+                      unsigned int priority,
+                      struct GNUNET_TIME_Relative timeout,
+                      struct Session *session,
+                      const void *addr,
+                      size_t addrlen,
+                      int force_address,
+                      GNUNET_TRANSPORT_TransmitContinuation cont,
+                      void *cont_cls)
 {
-  char * peer_url = get_url( target );
+  struct Session* ses;
+  struct Session* ses_temp;
+  int bytes_sent = 0;
 
-  CURLMcode mret;
-  CURLcode ret;
+  //FILE * hd_src ;
 
-  int bytes_sent = 0;
-  /*  struct Plugin *plugin = cls; */
+  CURLMcode mret;
+  char * url;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sending %u bytes (`%s')'\n",msgbuf_size, msgbuf);
-  /* Insert code to send using cURL */
-  curl = curl_easy_init ();
-  /*
-  CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
-  CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport told plugin to send to peer `%s'\n",GNUNET_i2s(target));
 
+  /* find session for peer */
+  ses = find_session_by_pi (target);
+  if (NULL != ses )
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Existing session for peer `%s' found\n", GNUNET_i2s(target));
+  if ( ses == NULL)
+  {
+    /* create new session object */
 
-  CURL_EASY_SETOPT (curl, CURLOPT_UPLOAD, 1L);
-  CURL_EASY_SETOPT (curl, CURLOPT_PUT, 1L);
-  CURL_EASY_SETOPT (curl, CURLOPT_READDATA, msgbuf);
+    /*FIXME: what is const void * really? Assuming struct sockaddr_in * ! */
+    ses = create_session((struct sockaddr_in *) addr, target);
+    ses->is_active = GNUNET_YES;
 
-  CURL_EASY_SETOPT (curl, CURLOPT_URL, peer_url);
-  if (ret != CURLE_OK)
-    {*/
-      /* clean_up (); */
-  /*    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Peer URL is not correct\n");
-      return 0;
+    /* Insert session into linked list */
+    if ( plugin->sessions == NULL)
+    {
+      plugin->sessions = ses;
+      plugin->session_count = 1;
     }
-  CURL_EASY_SETOPT (curl,
-                    CURLOPT_FAILONERROR,
-                    1);
-  CURL_EASY_SETOPT (curl,
-                    CURLOPT_VERBOSE,
-                    1);
-  CURL_EASY_SETOPT (curl,
-                    CURLOPT_BUFFERSIZE,
-                    GNUNET_SERVER_MAX_MESSAGE_SIZE);
-  if (0 == strncmp (peer_url, "http", 4))
-    CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
-  CURL_EASY_SETOPT (curl,
-                    CURLOPT_CONNECTTIMEOUT,
-                    60L);
-  CURL_EASY_SETOPT (curl,
-                    CURLOPT_TIMEOUT,
-                    60L);*/
-
-  CURL_EASY_SETOPT (curl, CURLOPT_URL, "http://www.tum.de/");
-  curl_multi = curl_multi_init ();
-  if (curl_multi == NULL)
+    ses_temp = plugin->sessions;
+    while ( ses_temp->next != NULL )
     {
-      GNUNET_break (0);
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "curl multi is not correct\n");
-      /* clean_up (); */
-      return 0;
+      ses_temp = ses_temp->next;
     }
-  mret = curl_multi_add_handle (curl_multi, curl);
-  if (mret != CURLM_OK)
+    if (ses_temp != ses )
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("%s failed at %s:%d: `%s'\n"),
-                  "curl_multi_add_handle", __FILE__, __LINE__,
-                  curl_multi_strerror (mret));
-      mret = curl_multi_cleanup (curl_multi);
-      if (mret != CURLM_OK)
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    _("%s failed at %s:%d: `%s'\n"),
-                    "curl_multi_cleanup", __FILE__, __LINE__,
-                    curl_multi_strerror (mret));
-      curl_multi = NULL;
-      /* clean_up (); */
-      return 0;
+      ses_temp->next = ses;
+      plugin->session_count++;
     }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"New Session `%s' inserted, count %u \n", GNUNET_i2s(target), plugin->session_count);
+  }
+
+  ses->curl_handle = curl_easy_init();
+  if( NULL == ses->curl_handle)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Getting cURL handle failed\n");
+    return -1;
+  }
+
+  url = GNUNET_malloc( 7 + strlen(ses->ip) + 7 + strlen ((char *) &(ses->hash)) + 1);
+  GNUNET_asprintf(&url,"http://%s:%u/%s",ses->ip,12389, (char *) &(ses->hash));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"url: %s %u\n",url, 7 + strlen(ses->ip) + 7 + strlen ((char *) &(ses->hash)) + 1 );
+
+  (ses->cbc).len = msgbuf_size;
+  (ses->cbc).buf = buf;
+  memcpy(ses->cbc.buf,msgbuf,msgbuf_size);
 
-  download_prepare();
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"msgbuf %s cbc: len %u cbc.buf `%s' test `%s'\n",msgbuf,ses->cbc.len,ses->cbc.buf,test);
 
-  GNUNET_free(peer_url);
-  /* FIXME: */
-  bytes_sent = msgbuf_size;
+  curl_easy_setopt(ses->curl_handle, CURLOPT_VERBOSE, 1L);
+  curl_easy_setopt(ses->curl_handle, CURLOPT_URL, url);
+  curl_easy_setopt(ses->curl_handle, CURLOPT_PUT, 1L);
+  curl_easy_setopt(ses->curl_handle, CURLOPT_READFUNCTION, send_read_callback);
+  curl_easy_setopt(ses->curl_handle, CURLOPT_READDATA, ses);
+  curl_easy_setopt(ses->curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t) (ses->cbc).len);
+  curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (timeout.value / 1000 ));
+  curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
 
+  mret = curl_multi_add_handle(multi_handle, ses->curl_handle);
+  if (mret != CURLM_OK)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("%s failed at %s:%d: `%s'\n"),
+                "curl_multi_add_handle", __FILE__, __LINE__,
+                curl_multi_strerror (mret));
+    return -1;
+  }
+  bytes_sent = send_prepare (ses );
+  GNUNET_free ( url );
   return bytes_sent;
 }
 
@@ -411,13 +912,13 @@ http_plugin_send (void *cls,
  * @param cls closure
  * @param target peer from which to disconnect
  */
-void
+static void
 http_plugin_disconnect (void *cls,
                             const struct GNUNET_PeerIdentity *target)
 {
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Plugin: http_plugin_disconnect\n");
   // struct Plugin *plugin = cls;
   // FIXME
-  return;
 }
 
 
@@ -437,14 +938,15 @@ http_plugin_disconnect (void *cls,
  */
 static void
 http_plugin_address_pretty_printer (void *cls,
-                                    const char *type,
-                                    const void *addr,
-                                    size_t addrlen,
-                                    int numeric,
-                                    struct GNUNET_TIME_Relative timeout,
-                                    GNUNET_TRANSPORT_AddressStringCallback
-                                    asc, void *asc_cls)
+                                        const char *type,
+                                        const void *addr,
+                                        size_t addrlen,
+                                        int numeric,
+                                        struct GNUNET_TIME_Relative timeout,
+                                        GNUNET_TRANSPORT_AddressStringCallback
+                                        asc, void *asc_cls)
 {
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Plugin: http_plugin_address_pretty_printer\n");
   asc (asc_cls, NULL);
 }
 
@@ -470,148 +972,30 @@ http_plugin_address_suggested (void *cls,
 
   /* check if the address is plausible; if so,
      add it to our list! */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Plugin: http_plugin_address_suggested\n");
   return GNUNET_OK;
 }
 
-/**
- * Check if we are allowed to connect to the given IP.
- */
-static int
-acceptPolicyCallback (void *cls,
-                      const struct sockaddr *addr, socklen_t addr_len)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Incoming connection \n");
-  /* Currently all incoming connections are accepted, so nothing to do here */
-  return MHD_YES;
-}
-
-/**
- * Process GET or PUT request received via MHD.  For
- * GET, queue response that will send back our pending
- * messages.  For PUT, process incoming data and send
- * to GNUnet core.  In either case, check if a session
- * already exists and create a new one if not.
- */
-static int
-accessHandlerCallback (void *cls,
-                       struct MHD_Connection *session,
-                       const char *url,
-                       const char *method,
-                       const char *version,
-                       const char *upload_data,
-                       size_t * upload_data_size, void **httpSessionCache)
-{
-  struct MHD_Response *response;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has an incoming `%s' request from \n",method);
-
-  /* Find out if session exists, otherwise create one */
-
-  /* Is it a PUT or a GET request */
-  if ( 0 == strcmp (MHD_HTTP_METHOD_PUT, method) )
-  {
-    /* PUT method here */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Got PUT Request with size %u \n",upload_data_size);
-    GNUNET_STATISTICS_update( plugin->env->stats , gettext_noop("# PUT requests"), 1, GNUNET_NO);
-  }
-  if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Got GET Request with size\n");
-    GNUNET_STATISTICS_update( plugin->env->stats , gettext_noop("# GET requests"), 1, GNUNET_NO);
-  }
-
-  response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),
-                                   HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
-  MHD_queue_response (session, MHD_HTTP_OK, response);
-  MHD_destroy_response (response);
-
-  return MHD_YES;
-}
 
 /**
- * Function that queries MHD's select sets and
- * starts the task waiting for them.
- */
-static GNUNET_SCHEDULER_TaskIdentifier prepare_daemon (struct MHD_Daemon *daemon_handle);
-/**
- * Call MHD to process pending requests and then go back
- * and schedule the next run.
- */
-static void
-run_daemon (void *cls,
-            const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct MHD_Daemon *daemon_handle = cls;
-
-  if (daemon_handle == http_daemon_v4)
-    http_task_v4 = GNUNET_SCHEDULER_NO_TASK;
-
-  if (daemon_handle == http_daemon_v6)
-    http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
-
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    return;
-
-  GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
-  if (daemon_handle == http_daemon_v4)
-    http_task_v4 = prepare_daemon (daemon_handle);
-  if (daemon_handle == http_daemon_v6)
-    http_task_v6 = prepare_daemon (daemon_handle);
-  return;
-}
-
-/**
- * Function that queries MHD's select sets and
- * starts the task waiting for them.
+ * Function called for a quick conversion of the binary address to
+ * a numeric address.  Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
  */
-static GNUNET_SCHEDULER_TaskIdentifier
-prepare_daemon (struct MHD_Daemon *daemon_handle)
+static const char*
+http_plugin_address_to_string (void *cls,
+                                   const void *addr,
+                                   size_t addrlen)
 {
-  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;
-  unsigned long long timeout;
-  int haveto;
-  struct GNUNET_TIME_Relative tv;
-
-  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)
-    tv.value = (uint64_t) timeout;
-  else
-    tv = GNUNET_TIME_UNIT_FOREVER_REL;
-  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
-  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
-  GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
-  ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
-                                     GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                     GNUNET_SCHEDULER_NO_TASK,
-                                     tv,
-                                     wrs,
-                                     wws,
-                                     &run_daemon,
-                                     daemon_handle);
-  GNUNET_NETWORK_fdset_destroy (wrs);
-  GNUNET_NETWORK_fdset_destroy (wws);
-  GNUNET_NETWORK_fdset_destroy (wes);
-  return ret;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Plugin: http_plugin_address_to_string\n");
+  GNUNET_break (0);
+  return NULL;
 }
 
 /**
@@ -622,14 +1006,11 @@ libgnunet_plugin_transport_http_done (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
+  struct Session * cs;
+  struct Session * cs_next;
+  CURLMcode mret;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Shutting down http plugin...\n");
-
-  if ( ti_download != GNUNET_SCHEDULER_NO_TASK)
-  {
-    GNUNET_SCHEDULER_cancel(plugin->env->sched, ti_download);
-    ti_download = GNUNET_SCHEDULER_NO_TASK;
-  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unloading http plugin...\n");
 
   if ( http_task_v4 != GNUNET_SCHEDULER_NO_TASK)
   {
@@ -643,6 +1024,12 @@ libgnunet_plugin_transport_http_done (void *cls)
     http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
   }
 
+  if ( http_task_send != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_send);
+    http_task_send = GNUNET_SCHEDULER_NO_TASK;
+  }
+
   if (http_daemon_v4 != NULL)
   {
     MHD_stop_daemon (http_daemon_v4);
@@ -654,17 +1041,31 @@ libgnunet_plugin_transport_http_done (void *cls)
     http_daemon_v6 = NULL;
   }
 
+  mret = curl_multi_cleanup(multi_handle);
+  if ( CURLM_OK != mret)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed");
+
+  /* free all sessions */
+  cs = plugin->sessions;
+  while ( NULL != cs)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing session to `%s'\n",cs->ip);
+      cs_next = cs->next;
+      GNUNET_free (cs->ip);
+      GNUNET_free (cs->addr);
+      GNUNET_free (cs);
+      plugin->session_count--;
+      cs = cs_next;
+    }
+
+  /* GNUNET_SERVICE_stop (plugin->service); */
 
-  if ( NULL != curl_multi)
-  {
-    curl_multi_cleanup (curl_multi);
-    curl_multi = NULL;
-  }
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;
 }
 
+
 /**
  * Entry point for the plugin.
  */
@@ -673,20 +1074,42 @@ libgnunet_plugin_transport_http_init (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
   struct GNUNET_TRANSPORT_PluginFunctions *api;
+  struct GNUNET_SERVICE_Context *service;
+  unsigned int timeout;
+  struct GNUNET_TIME_Relative gn_timeout;
   long long unsigned int port;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting http plugin...\n");
+
+  service = NULL;
+  /*
+  service = GNUNET_SERVICE_start ("transport-http", env->sched, env->cfg);
+  if (service == NULL)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "", _
+                       ("Failed to start service for `%s' transport plugin.\n"),
+                       "http");
+      return NULL;
+    }
+    */
+
   plugin = GNUNET_malloc (sizeof (struct Plugin));
   plugin->env = env;
-
+  plugin->sessions = NULL;
+  plugin->service = service;
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
   api->send = &http_plugin_send;
   api->disconnect = &http_plugin_disconnect;
   api->address_pretty_printer = &http_plugin_address_pretty_printer;
   api->check_address = &http_plugin_address_suggested;
+  api->address_to_string = &http_plugin_address_to_string;
 
+  hostname = GNUNET_RESOLVER_local_fqdn_get ();
+
+  /* Hashing our identity to use it in URLs */
+  GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &my_ascii_hash_ident);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting http plugin...\n");
   /* Reading port number from config file */
   if ((GNUNET_OK !=
        GNUNET_CONFIGURATION_get_value_number (env->cfg,
@@ -698,63 +1121,61 @@ libgnunet_plugin_transport_http_init (void *cls)
       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
                        "http",
                        _
-                       ("Require valid port number for service `%s' in configuration!\n"),
+                       ("Require valid port number for transport plugin `%s' in configuration!\n"),
                        "transport-http");
       libgnunet_plugin_transport_http_done (api);
       return NULL;
     }
+
+  gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
+  timeout = ( gn_timeout.value / 1000);
   if ((http_daemon_v4 == NULL) && (http_daemon_v6 == NULL) && (port != 0))
     {
-      http_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
-                                         port,
-                                         &acceptPolicyCallback,
-                                         NULL, &accessHandlerCallback, NULL,
-                                         MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
-                                         MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
-                                         MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
-                                         MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
-                                         MHD_OPTION_END);
-      http_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
-                                         port,
-                                         &acceptPolicyCallback,
-                                         NULL, &accessHandlerCallback, NULL,
-                                         MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
-                                         MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
-                                         MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
-                                         MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
-                                         MHD_OPTION_END);
+    http_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
+                                       port,
+                                       &acceptPolicyCallback,
+                                       NULL , &accessHandlerCallback, NULL,
+                                       MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
+                                       MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
+                                       MHD_OPTION_CONNECTION_TIMEOUT, timeout,
+                                       /* FIXME: set correct limit */
+                                       MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
+                                       MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
+                                       MHD_OPTION_END);
+    http_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
+                                       port,
+                                       &acceptPolicyCallback,
+                                       NULL , &accessHandlerCallback, NULL,
+                                       MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
+                                       MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
+                                       MHD_OPTION_CONNECTION_TIMEOUT, timeout,
+                                       /* FIXME: set correct limit */
+                                       MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
+                                       MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
+                                       MHD_OPTION_END);
     }
-
-  curl_multi = curl_multi_init ();
-
   if (http_daemon_v4 != NULL)
-    http_task_v4 = prepare_daemon (http_daemon_v4);
+    http_task_v4 = http_daemon_prepare (http_daemon_v4);
   if (http_daemon_v6 != NULL)
-    http_task_v6 = prepare_daemon (http_daemon_v6);
+    http_task_v6 = http_daemon_prepare (http_daemon_v6);
 
-  if ((http_daemon_v4 == NULL) || (http_daemon_v6 != NULL))
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD on port %u\n",port);
+  if (http_task_v4 != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 on port %u\n",port);
+  if (http_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 on port %u\n",port);
 
-
-  if (NULL == plugin->env->stats)
+  /* Initializing cURL */
+  multi_handle = curl_multi_init();
+  if ( NULL == multi_handle )
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Failed to retrieve statistics handle\n"));
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
+                     "http",
+                     _("Could not initialize curl multi handle, failed to start http plugin!\n"),
+                     "transport-http");
     libgnunet_plugin_transport_http_done (api);
     return NULL;
   }
-
-  GNUNET_STATISTICS_set ( env->stats, "# PUT requests", 0, GNUNET_NO);
-  GNUNET_STATISTICS_set ( env->stats, "# GET requests", 0, GNUNET_NO);
-
-  if ( ((NULL == http_daemon_v4) && (NULL == http_daemon_v6)) || (NULL == curl_multi))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Initializing http plugin failed\n");
-    libgnunet_plugin_transport_http_done (api);
-    return NULL;
-  }
-  else
-    return api;
+  return api;
 }
 
-/* end of plugin_transport_http.c */
+/* end of plugin_transport_template.c */