(no commit message)
[oweals/gnunet.git] / src / transport / plugin_transport_http.c
index 03f57c7cee6eabc1ff75341ef4885750dd67b2e1..f71acf4b0cbb0c703748bc67a60a900962747a9c 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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 2, or (at your
+     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
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 */
 
 /**
 */
 
 /**
- * @file transport/plugin_transport_template.c
- * @brief template for a new transport service
- * @author Christian Grothoff
+ * @file transport/plugin_transport_http.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
  */
 
 #include "platform.h"
 #include "gnunet_constants.h"
 #include "gnunet_protocols.h"
 #include "gnunet_connection_lib.h"
  */
 
 #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 "gnunet_service_lib.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_transport_service.h"
 #include "gnunet_resolver_service.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_container_lib.h"
 #include "plugin_transport.h"
 #include "plugin_transport.h"
+#include "gnunet_os_lib.h"
 #include "microhttpd.h"
 #include <curl/curl.h>
 
 #include "microhttpd.h"
 #include <curl/curl.h>
 
+
+#define DEBUG_CURL GNUNET_NO
 #define DEBUG_HTTP GNUNET_NO
 #define DEBUG_HTTP GNUNET_NO
+#define DEBUG_CONNECTIONS GNUNET_YES
+
+#define INBOUND GNUNET_NO
+#define OUTBOUND GNUNET_YES
 
 /**
  * Text of the response sent back after the last bytes of a PUT
 
 /**
  * Text of the response sent back after the last bytes of a PUT
  */
 #define HTTP_CONNECT_TIMEOUT 30
 
  */
 #define HTTP_CONNECT_TIMEOUT 30
 
-
 /**
 /**
- * Encapsulation of all of the state of the plugin.
+ * Network format for IPv4 addresses.
  */
  */
-struct Plugin;
+struct IPv4HttpAddress
+{
+  /**
+   * IPv4 address, in network byte order.
+   */
+  uint32_t ipv4_addr GNUNET_PACKED;
+
+  /**
+   * Port number, in network byte order.
+   */
+  uint16_t u_port GNUNET_PACKED;
 
 
-struct CBC
+};
+
+
+/**
+ * Network format for IPv6 addresses.
+ */
+struct IPv6HttpAddress
 {
 {
-  char *buf;
-  size_t pos;
-  size_t size;
-  size_t len;
+  /**
+   * IPv6 address.
+   */
+  struct in6_addr ipv6_addr GNUNET_PACKED;
+
+  /**
+   * Port number, in network byte order.
+   */
+  uint16_t u6_port GNUNET_PACKED;
+
 };
 
 
 /**
 };
 
 
 /**
- * Session handle for connections.
+ *  Message to send using http
  */
  */
-struct Session
+struct HTTP_Message
 {
 {
+  /**
+   * next pointer for double linked list
+   */
+  struct HTTP_Message * next;
 
   /**
 
   /**
-   * Stored in a linked list.
+   * previous pointer for double linked list
    */
    */
-  struct Session *next;
+  struct HTTP_Message * prev;
 
   /**
 
   /**
-   * Pointer to the global plugin struct.
+   * buffer containing data to send
    */
    */
-  struct Plugin *plugin;
+  char *buf;
+
+  /**
+   * amount of data already sent
+   */
+  size_t pos;
+
+  /**
+   * buffer length
+   */
+  size_t size;
 
   /**
    * Continuation function to call once the transmission buffer
 
   /**
    * Continuation function to call once the transmission buffer
@@ -105,257 +148,453 @@ struct Session
    * Closure for transmit_cont.
    */
   void *transmit_cont_cls;
    * Closure for transmit_cont.
    */
   void *transmit_cont_cls;
+};
+
 
 
+struct HTTP_PeerContext
+{
   /**
   /**
-   * To whom are we talking to (set to our identity
-   * if we are still waiting for the welcome message)
+   * peer's identity
    */
    */
-  struct GNUNET_PeerIdentity sender;
+  struct GNUNET_PeerIdentity identity;
 
   /**
 
   /**
-   * Sender's url
+   * Pointer to the global plugin struct.
    */
    */
-  char * url;
+  struct Plugin *plugin;
 
   /**
 
   /**
-   * Sender's ip address to distinguish between incoming connections
+   * Linked list of connections with this peer
+   * head
    */
    */
-  char * ip;
+  struct Session * head;
 
   /**
 
   /**
-   * Sender's ip address to distinguish between incoming connections
+   * Linked list of connections with this peer
+   * tail
    */
    */
-  struct sockaddr_in * addr;
+  struct Session * tail;
 
   /**
 
   /**
-   * Did we initiate the connection (GNUNET_YES) or the other peer (GNUNET_NO)?
+   * id for next session
    */
    */
-  unsigned int is_client;
+  size_t session_id_counter;
+};
+
 
 
+struct Session
+{
   /**
   /**
-   * Is the connection active (GNUNET_YES) or terminated (GNUNET_NO)?
+   * API requirement.
    */
    */
-  unsigned int is_active;
+  struct SessionHeader header;
 
   /**
 
   /**
-   * At what time did we reset last_received last?
+   * next session in linked list
    */
    */
-  struct GNUNET_TIME_Absolute last_quota_update;
+  struct Session * next;
 
   /**
 
   /**
-   * How many bytes have we received since the "last_quota_update"
-   * timestamp?
+   * previous session in linked list
    */
    */
-  uint64_t last_received;
+  struct Session * prev;
 
   /**
 
   /**
-   * Number of bytes per ms that this peer is allowed
-   * to send to us.
+   * address of this session
    */
    */
-  uint32_t quota;
+  void * addr;
 
   /**
 
   /**
-   * Is there a HTTP/PUT in progress?
+   * address length
    */
    */
-  unsigned int is_put_in_progress;
+  size_t addrlen;
 
   /**
 
   /**
-   * Encoded hash
+   * target url
    */
    */
-  struct GNUNET_CRYPTO_HashAsciiEncoded hash;
+  char * url;
 
 
-  struct CBC cbc;
+  /**
+   * Message queue for outbound messages
+   * head of queue
+   */
+  struct HTTP_Message * pending_msgs_head;
 
 
-  CURL *curl_handle;
-};
+  /**
+   * Message queue for outbound messages
+   * tail of queue
+   */
+  struct HTTP_Message * pending_msgs_tail;
 
 
-/**
- * Encapsulation of all of the state of the plugin.
- */
-struct Plugin
-{
   /**
   /**
-   * Our environment.
+   * partner peer this connection belongs to
    */
    */
-  struct GNUNET_TRANSPORT_PluginEnvironment *env;
+  struct HTTP_PeerContext * peercontext;
 
   /**
 
   /**
-   * Handle to the network service.
+   * message stream tokenizer for incoming data
    */
    */
-  struct GNUNET_SERVICE_Context *service;
+  struct GNUNET_SERVER_MessageStreamTokenizer *msgtok;
 
   /**
 
   /**
-   * List of open sessions.
+   * session direction
+   * outbound: OUTBOUND (GNUNET_YES)
+   * inbound : INBOUND (GNUNET_NO)
    */
    */
-  struct Session *sessions;
+  unsigned int direction;
 
   /**
 
   /**
-   * Number of active sessions
+   * is session connected to send data?
    */
    */
+  unsigned int send_connected;
 
 
-  unsigned int session_count;
-};
+  /**
+   * is send connection active?
+   */
+  unsigned int send_active;
 
 
-/**
- * Daemon for listening for new IPv4 connections.
- */
-static struct MHD_Daemon *http_daemon_v4;
+  /**
+   * connection disconnect forced (e.g. from transport)
  */
+  unsigned int send_force_disconnect;
 
 
-/**
- * Daemon for listening for new IPv6connections.
- */
-static struct MHD_Daemon *http_daemon_v6;
+  /**
+   * is session connected to receive data?
  */
+  unsigned int recv_connected;
 
 
-/**
- * Our primary task for http daemon handling IPv4 connections
- */
-static GNUNET_SCHEDULER_TaskIdentifier http_task_v4;
+  /**
+   * is receive connection active?
  */
+  unsigned int recv_active;
 
 
-/**
- * Our primary task for http daemon handling IPv6 connections
- */
-static GNUNET_SCHEDULER_TaskIdentifier http_task_v6;
+  /**
+   * connection disconnect forced (e.g. from transport)
  */
+  unsigned int recv_force_disconnect;
 
 
+  /**
+   * id for next session
+   * NOTE: 0 is not an ID, zero is not defined. A correct ID is always > 0
+   */
+  size_t session_id;
 
 
-/**
- * Our primary task for http daemon handling IPv6 connections
- */
-static GNUNET_SCHEDULER_TaskIdentifier http_task_send;
+  /**
+   * entity managing sending data
+   * outbound session: CURL *
+   * inbound session: mhd_connection *
+   */
+  void * send_endpoint;
 
 
+  /**
+   * entity managing recieving data
+   * outbound session: CURL *
+   * inbound session: mhd_connection *
+   */
+  void * recv_endpoint;
+};
 
 /**
 
 /**
- * Information about this plugin
+ * Encapsulation of all of the state of the plugin.
  */
  */
-static struct Plugin *plugin;
+struct Plugin
+{
+  /**
+   * Our environment.
+   */
+  struct GNUNET_TRANSPORT_PluginEnvironment *env;
 
 
-/**
- * cURL Multihandle
- */
-static CURLM *multi_handle;
+  unsigned int port_inbound;
 
 
-/**
- * Our hostname
- */
-static char * hostname;
+  struct GNUNET_CONTAINER_MultiHashMap *peers;
 
 
-/**
- * Our ASCII encoded, hashed peer identity
- * This string is used to distinguish between connections and is added to the urls
- */
-static struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
+  /**
+   * Daemon for listening for new IPv4 connections.
+   */
+  struct MHD_Daemon *http_server_daemon_v4;
 
 
-static char buf[2048];
+  /**
+   * Daemon for listening for new IPv6connections.
+   */
+  struct MHD_Daemon *http_server_daemon_v6;
+
+  /**
+   * Our primary task for http daemon handling IPv4 connections
+   */
+  GNUNET_SCHEDULER_TaskIdentifier http_server_task_v4;
 
 
-/**
- * Message-Packet header.
- */
-struct HTTPMessage
-{
   /**
   /**
-   * size of the message, in bytes, including this header.
+   * Our primary task for http daemon handling IPv6 connections
    */
    */
-  struct GNUNET_MessageHeader header;
+  GNUNET_SCHEDULER_TaskIdentifier http_server_task_v6;
 
   /**
 
   /**
-   * What is the identity of the sender (GNUNET_hash of public key)
+   * The task sending data
    */
    */
-  struct GNUNET_PeerIdentity sender;
+  GNUNET_SCHEDULER_TaskIdentifier http_server_task_send;
 
 
+  /**
+   * cURL Multihandle
+   */
+  CURLM * multi_handle;
+
+  /**
+   * Our ASCII encoded, hashed peer identity
+   * This string is used to distinguish between connections and is added to the urls
+   */
+  struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
 };
 
 };
 
+
 /**
 /**
- * Finds a http session in our linked list using peer identity as a key
- * @param peer peeridentity
- * @return http session corresponding to peer identity
+ * 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 struct Session * find_session_by_pi( const struct GNUNET_PeerIdentity *peer )
+static const char*
+http_plugin_address_to_string (void *cls,
+                                   const void *addr,
+                                   size_t addrlen);
+
+static char * create_url(void * cls, const void * addr, size_t addrlen, size_t id)
 {
 {
-  struct Session * cur;
-  GNUNET_HashCode hc_peer;
-  GNUNET_HashCode hc_current;
+  struct Plugin *plugin = cls;
+  char *url = NULL;
 
 
-  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;
+  GNUNET_assert ((addr!=NULL) && (addrlen != 0));
+  GNUNET_asprintf(&url,
+                  "http://%s/%s;%u",
+                  http_plugin_address_to_string(NULL, addr, addrlen),
+                  (char *) (&plugin->my_ascii_hash_ident),id);
+
+  return url;
 }
 
 /**
 }
 
 /**
- * Create a new session
- *
- * @param address address the peer is using
- * @peer  peer identity
- * @return created session object
+ * Removes a message from the linked list of messages
+ * @param con connection to remove message from
+ * @param msg message to remove
+ * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
  */
  */
+static int remove_http_message (struct Session * ps, struct HTTP_Message * msg)
+{
+  GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
+  GNUNET_free(msg);
+  return GNUNET_OK;
+}
 
 
-static struct Session * create_session (struct sockaddr_in *address, const struct GNUNET_PeerIdentity *peer)
+/**
+ * Removes a session from the linked list of sessions
+ * @param pc peer context
+ * @param ps session
+ * @param call_msg_cont GNUNET_YES to call pending message continuations, otherwise no
+ * @param call_msg_cont_result, result to call message continuations with
+ * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
+ */
+static int remove_session (struct HTTP_PeerContext * pc, struct Session * ps,  int call_msg_cont, int call_msg_cont_result)
 {
 {
-  struct sockaddr_in  *addrin;
-  struct sockaddr_in6 *addrin6;
+  struct HTTP_Message * msg;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: removing %s session with id %u\n", ps, (ps->direction == INBOUND) ? "inbound" : "outbound",ps->session_id);
+  GNUNET_free_non_null (ps->addr);
+  GNUNET_SERVER_mst_destroy (ps->msgtok);
+  GNUNET_free(ps->url);
+
+  msg = ps->pending_msgs_head;
+  while (msg!=NULL)
+  {
+    if ((call_msg_cont == GNUNET_YES) && (msg->transmit_cont!=NULL))
+    {
+      msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,call_msg_cont_result);
+    }
+    GNUNET_free(msg);
+    GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_head,msg);
+  }
 
 
-  struct Session * ses = GNUNET_malloc ( sizeof( struct Session) );
-  ses->addr = GNUNET_malloc ( sizeof (struct sockaddr_in) );
+  GNUNET_CONTAINER_DLL_remove(pc->head,pc->tail,ps);
+  GNUNET_free(ps);
+  ps = NULL;
+  return GNUNET_OK;
+}
 
 
-  ses->next = NULL;
-  ses->plugin = plugin;
+static struct Session * get_Session (void * cls, struct HTTP_PeerContext *pc, const void * addr, size_t addr_len)
+{
+  struct Session * cc = pc->head;
+  struct Session * con = NULL;
+  unsigned int count = 0;
 
 
-  memcpy(ses->addr, address, sizeof (struct sockaddr_in));
-  if ( AF_INET == address->sin_family)
+  GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
+  while (cc!=NULL)
   {
   {
-    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);
+    if (addr_len == cc->addrlen)
+    {
+      if (0 == memcmp(cc->addr, addr, addr_len))
+      {
+        /* connection can not be used, since it is disconnected */
+        if ((cc->recv_force_disconnect==GNUNET_NO) && (cc->send_force_disconnect==GNUNET_NO))
+          con = cc;
+        break;
+      }
+    }
+    count++;
+    cc=cc->next;
   }
   }
-  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;
+  return con;
 }
 
 }
 
+
 /**
  * Callback called by MHD when a connection is terminated
  */
 /**
  * Callback called by MHD when a connection is terminated
  */
-static void requestCompletedCallback (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
+static void mhd_termination_cb (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
 {
 {
-  struct Session * cs;
+  struct Session * ps = *httpSessionCache;
+  if (ps == NULL)
+    return;
+  struct HTTP_PeerContext * pc = ps->peercontext;
 
 
-  cs = *httpSessionCache;
-  if (cs != NULL)
+  if (connection==ps->recv_endpoint)
   {
   {
-    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;
+#if DEBUG_CONNECTIONS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection from peer `%s' was terminated\n", ps, GNUNET_i2s(&pc->identity));
+#endif
+    ps->recv_active = GNUNET_NO;
+    ps->recv_connected = GNUNET_NO;
+    ps->recv_endpoint = NULL;
   }
   }
-  return;
+  if (connection==ps->send_endpoint)
+  {
+
+    ps->send_active = GNUNET_NO;
+    ps->send_connected = GNUNET_NO;
+    ps->send_endpoint = NULL;
+#if DEBUG_CONNECTIONS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound connection from peer `%s' was terminated\n", ps, GNUNET_i2s(&pc->identity));
+#endif
+  }
+
+  /* if both connections disconnected, remove session */
+  if ((ps->send_connected == GNUNET_NO) && (ps->recv_connected == GNUNET_NO))
+  {
+    remove_session(pc,ps,GNUNET_YES,GNUNET_SYSERR);
+  }
+}
+
+static void mhd_write_mst_cb (void *cls,
+                              void *client,
+                              const struct GNUNET_MessageHeader *message)
+{
+
+  struct Session *ps  = cls;
+  struct HTTP_PeerContext *pc = ps->peercontext;
+  GNUNET_assert(ps != NULL);
+  GNUNET_assert(pc != NULL);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
+             ps,
+             ntohs(message->type),
+              ntohs(message->size),
+             GNUNET_i2s(&(ps->peercontext)->identity),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
+
+  pc->plugin->env->receive (ps->peercontext->plugin->env->cls,
+                           &pc->identity,
+                           message, 1, ps,
+                           ps->addr,
+                           ps->addrlen);
 }
 
 }
 
+static void curl_receive_mst_cb  (void *cls,
+                                void *client,
+                                const struct GNUNET_MessageHeader *message)
+{
+  struct Session *ps  = cls;
+  struct HTTP_PeerContext *pc = ps->peercontext;
+  GNUNET_assert(ps != NULL);
+  GNUNET_assert(pc != NULL);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
+              ntohs(message->type),
+              ntohs(message->size),
+              GNUNET_i2s(&(pc->identity)),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
+
+  pc->plugin->env->receive (pc->plugin->env->cls,
+                            &pc->identity,
+                            message, 1, ps,
+                            ps->addr,
+                            ps->addrlen);
+}
+
+
 /**
 /**
- * Check if we are allowed to connect to the given IP.
+ * Check if ip is allowed to connect.
  */
 static int
  */
 static int
-acceptPolicyCallback (void *cls,
+mhd_accept_cb (void *cls,
                       const struct sockaddr *addr, socklen_t addr_len)
 {
                       const struct sockaddr *addr, socklen_t addr_len)
 {
+#if 0
+  struct Plugin *plugin = cls;
+#endif
   /* Every connection is accepted, nothing more to do here */
   /* Every connection is accepted, nothing more to do here */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connect!\n");
   return MHD_YES;
 }
 
   return MHD_YES;
 }
 
+int mhd_send_callback (void *cls, uint64_t pos, char *buf, int max)
+{
+  int bytes_read = 0;
+
+  struct Session * ps = cls;
+  struct HTTP_PeerContext * pc;
+  struct HTTP_Message * msg;
+  int res;res=5;
+
+  GNUNET_assert (ps!=NULL);
+  pc = ps->peercontext;
+  msg = ps->pending_msgs_tail;
+  if (ps->send_force_disconnect==GNUNET_YES)
+  {
+#if DEBUG_CONNECTIONS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound forced to disconnect\n",ps);
+#endif
+    return -1;
+  }
+
+  if (msg!=NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"mhd_send_callback %X: queue msg size: %u, max %u pos %u msg->pos %u\n",ps,msg->size,max,pos,msg->pos);
+    if ((msg->size-msg->pos) <= max)
+    {
+      memcpy(buf,&msg->buf[msg->pos],(msg->size-msg->pos));
+      bytes_read = msg->size-msg->pos;
+      msg->pos+=(msg->size-msg->pos);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"mhd_send_callback %X: complete: size %u pos %u bytes read %u \n",ps,msg->size,msg->pos,bytes_read);
+    }
+    else
+    {
+      memcpy(buf,&msg->buf[msg->pos],max);
+      msg->pos+=max;
+      bytes_read = max;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"mhd_send_callback %X: partial: size %u pos %u bytes read %u \n",ps,msg->size,msg->pos,bytes_read);
+    }
 
 
+    if (msg->pos==msg->size)
+    {
+      struct GNUNET_MessageHeader * tmp = (struct GNUNET_MessageHeader *) msg->buf;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"MHD SENT MESSAGE %u bytes msg->type %u msg->size %u\n", bytes_read, ntohs(tmp->type), ntohs(tmp->size));
+      if (NULL!=msg->transmit_cont)
+        msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
+      res = remove_http_message(ps,msg);
+    }
+  }
+  return bytes_read;
+}
 
 /**
  * Process GET or PUT request received via MHD.  For
 
 /**
  * Process GET or PUT request received via MHD.  For
@@ -365,355 +604,832 @@ acceptPolicyCallback (void *cls,
  * already exists and create a new one if not.
  */
 static int
  * already exists and create a new one if not.
  */
 static int
-accessHandlerCallback (void *cls,
-                       struct MHD_Connection *session,
+mdh_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)
 {
                        const char *url,
                        const char *method,
                        const char *version,
                        const char *upload_data,
                        size_t * upload_data_size, void **httpSessionCache)
 {
+  struct Plugin *plugin = cls;
   struct MHD_Response *response;
   struct MHD_Response *response;
-  struct Session * cs;
-  struct Session * cs_temp;
   const union MHD_ConnectionInfo * conn_info;
   const union MHD_ConnectionInfo * conn_info;
+
   struct sockaddr_in  *addrin;
   struct sockaddr_in6 *addrin6;
   struct sockaddr_in  *addrin;
   struct sockaddr_in6 *addrin6;
-  char * address = NULL;
+
+  char address[INET6_ADDRSTRLEN+14];
   struct GNUNET_PeerIdentity pi_in;
   struct GNUNET_PeerIdentity pi_in;
+  size_t id_num = 0;
+
+  struct IPv4HttpAddress ipv4addr;
+  struct IPv6HttpAddress ipv6addr;
+
+  struct HTTP_PeerContext *pc;
+  struct Session *ps;
+  struct Session *ps_tmp;
+
   int res = GNUNET_NO;
   int res = GNUNET_NO;
-  size_t bytes_recv;
-  struct GNUNET_MessageHeader *gn_msg;
   int send_error_to_client;
   int send_error_to_client;
+  void * addr;
+  size_t addr_len;
 
 
-  gn_msg = NULL;
+  GNUNET_assert(cls !=NULL);
   send_error_to_client = GNUNET_NO;
   send_error_to_client = GNUNET_NO;
-  if ( NULL == *httpSessionCache)
+
+  if (NULL == *httpSessionCache)
   {
   {
-    /* check url for peer identity */
-    res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
+    /* check url for peer identity , if invalid send HTTP 404*/
+    size_t len = strlen(&url[1]);
+    char * peer = GNUNET_malloc(104+1);
+
+    if ((len>104) && (url[104]==';'))
+    {
+        char * id = GNUNET_malloc((len-104)+1);
+        strcpy(id,&url[105]);
+        memcpy(peer,&url[1],103);
+        peer[103] = '\0';
+        id_num = strtoul ( id, NULL , 10);
+        GNUNET_free(id);
+    }
+    res = GNUNET_CRYPTO_hash_from_string (peer, &(pi_in.hashPubKey));
+    GNUNET_free(peer);
     if ( GNUNET_SYSERR == res )
     {
     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);
       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);
+      res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
       MHD_destroy_response (response);
       MHD_destroy_response (response);
+      if (res == MHD_YES)
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, sent HTTP 1.1/404\n");
+      else
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, could not send error\n");
       return res;
     }
       return res;
     }
+  }
+  else
+  {
+    ps = *httpSessionCache;
+    pc = ps->peercontext;
+  }
+
+  if (NULL == *httpSessionCache)
+  {
+    /* get peer context */
+    pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &pi_in.hashPubKey);
+    /* Peer unknown */
+    if (pc==NULL)
+    {
+      pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
+      pc->plugin = plugin;
+      pc->session_id_counter=1;
+      memcpy(&pc->identity, &pi_in, sizeof(struct GNUNET_PeerIdentity));
+      GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+    }
 
 
-    conn_info = MHD_get_connection_info(session, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
+    conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
     /* Incoming IPv4 connection */
     if ( AF_INET == conn_info->client_addr->sin_family)
     {
     /* 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);
       addrin = conn_info->client_addr;
       inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
+      memcpy(&ipv4addr.ipv4_addr,&(addrin->sin_addr),sizeof(struct in_addr));
+      ipv4addr.u_port = addrin->sin_port;
+      addr = &ipv4addr;
+      addr_len = sizeof(struct IPv4HttpAddress);
     }
     /* Incoming IPv6 connection */
     if ( AF_INET6 == conn_info->client_addr->sin_family)
     {
     }
     /* 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);
       addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
       inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
+      memcpy(&ipv6addr.ipv6_addr,&(addrin6->sin6_addr),sizeof(struct in6_addr));
+      ipv6addr.u6_port = addrin6->sin6_port;
+      addr = &ipv6addr;
+      addr_len = sizeof(struct IPv6HttpAddress);
     }
     }
-    /* 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;
+    //ps = get_Session(plugin, pc, addr, addr_len);
+    ps = NULL;
+    /* only inbound sessions here */
 
 
-        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 )
+    ps_tmp = pc->head;
+    while (ps_tmp!=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 )
+      if ((ps_tmp->direction==INBOUND) && (ps_tmp->session_id == id_num) && (id_num!=0))
       {
       {
-        cs_temp = cs_temp->next;
+        if ((ps_tmp->recv_force_disconnect!=GNUNET_YES) && (ps_tmp->send_force_disconnect!=GNUNET_YES))
+        ps=ps_tmp;
+        break;
       }
       }
-      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);
+      ps_tmp=ps_tmp->next;
     }
     }
-    /* Set closure */
-    if (*httpSessionCache == NULL)
+
+    if (ps==NULL)
     {
     {
-      *httpSessionCache = cs;
+      ps = GNUNET_malloc(sizeof (struct Session));
+      ps->addr = GNUNET_malloc(addr_len);
+      memcpy(ps->addr,addr,addr_len);
+      ps->addrlen = addr_len;
+      ps->direction=INBOUND;
+      ps->pending_msgs_head = NULL;
+      ps->pending_msgs_tail = NULL;
+      ps->send_connected=GNUNET_NO;
+      ps->send_active=GNUNET_NO;
+      ps->recv_connected=GNUNET_NO;
+      ps->recv_active=GNUNET_NO;
+      ps->peercontext=pc;
+      ps->session_id =id_num;
+      ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
+      GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
     }
     }
-    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;
+
+    *httpSessionCache = ps;
+    if (ps->msgtok==NULL)
+      ps->msgtok = GNUNET_SERVER_mst_create (&mhd_write_mst_cb, ps);
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: HTTP Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",
+                ps,
+                method,
+                GNUNET_i2s(&pc->identity),
+                http_plugin_address_to_string(NULL, ps->addr, ps->addrlen));
   }
   }
+
   /* Is it a PUT or a GET request */
   /* Is it a PUT or a GET request */
-  if ( 0 == strcmp (MHD_HTTP_METHOD_PUT, method) )
+  if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
   {
   {
-    /* New  */
-    if ((*upload_data_size == 0) && (cs->is_put_in_progress == GNUNET_NO))
+    if (ps->recv_force_disconnect)
     {
     {
-      /* not yet ready */
-      cs->is_put_in_progress = GNUNET_YES;
-      cs->is_active = GNUNET_YES;
-      return MHD_YES;
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection was forced to disconnect\n",ps);
+#endif
+      ps->recv_active = GNUNET_NO;
+      return MHD_NO;
     }
     }
-    if ( *upload_data_size > 0 )
+    if ((*upload_data_size == 0) && (ps->recv_active==GNUNET_NO))
     {
     {
-      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);
-        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);
-        GNUNET_free (gn_msg);
-        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) );
+      ps->recv_endpoint = mhd_connection;
+      ps->recv_connected = GNUNET_YES;
+      ps->recv_active = GNUNET_YES;
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound PUT connection connected\n",ps);
+#endif
       return MHD_YES;
     }
       return MHD_YES;
     }
-    if ((*upload_data_size == 0) && (cs->is_put_in_progress == GNUNET_YES))
+
+    /* Transmission of all data complete */
+    if ((*upload_data_size == 0) && (ps->recv_active == 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);
       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 );
+      res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Sent HTTP/1.1: 200 OK as PUT Response\n",ps);
+#endif
       MHD_destroy_response (response);
       MHD_destroy_response (response);
-      return res;
+      ps->recv_active=GNUNET_NO;
+      return MHD_YES;
     }
     }
+
+    /* Recieving data */
+    if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES))
+    {
+      res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
+      (*upload_data_size) = 0;
+      return MHD_YES;
+    }
+    else
+      return MHD_NO;
   }
   if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
   {
   }
   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);
+    if (ps->send_force_disconnect)
+    {
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound connection was  forced to disconnect\n",ps);
+#endif
+      ps->send_active = GNUNET_NO;
+      return MHD_NO;
+    }
+    ps->send_connected = GNUNET_YES;
+    ps->send_active = GNUNET_YES;
+    ps->send_endpoint = mhd_connection;
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound GET connection connected\n",ps);
+#endif
+    response = MHD_create_response_from_callback(-1,32 * 1024, &mhd_send_callback, ps, NULL);
+    res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
     MHD_destroy_response (response);
     MHD_destroy_response (response);
-    return res;
+    return MHD_YES;
   }
   return MHD_NO;
 }
 
 
   }
   return MHD_NO;
 }
 
 
+/**
+ * Call MHD to process pending ipv4 requests and then go back
+ * and schedule the next run.
+ */
+static void http_server_daemon_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+/**
+ * Call MHD to process pending ipv6 requests and then go back
+ * and schedule the next run.
+ */
+static void http_server_daemon_v6_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_server_daemon_prepare (void * cls, struct MHD_Daemon *daemon_handle)
+{
+  struct Plugin *plugin = cls;
+  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;
+
+  GNUNET_assert(cls !=NULL);
+  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)
+    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);
+  if (daemon_handle == plugin->http_server_daemon_v4)
+  {
+    ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
+                                       GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                       GNUNET_SCHEDULER_NO_TASK,
+                                       tv,
+                                       wrs,
+                                       wws,
+                                       &http_server_daemon_v4_run,
+                                       plugin);
+  }
+  if (daemon_handle == plugin->http_server_daemon_v6)
+  {
+    ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
+                                       GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                       GNUNET_SCHEDULER_NO_TASK,
+                                       tv,
+                                       wrs,
+                                       wws,
+                                       &http_server_daemon_v6_run,
+                                       plugin);
+  }
+  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 http_server_daemon_v4_run (void *cls,
+                             const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct Plugin *plugin = cls;
+
+  GNUNET_assert(cls !=NULL);
+  if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
+    plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
+
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+  GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v4));
+  plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
+  return;
+}
+
+
 /**
  * Call MHD to process pending requests and then go back
  * and schedule the next run.
  */
 /**
  * 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);
+static void http_server_daemon_v6_run (void *cls,
+                             const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct Plugin *plugin = cls;
+
+  GNUNET_assert(cls !=NULL);
+  if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+    plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+
+  GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v6));
+  plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
+  return;
+}
+
+/**
+ * Function setting up curl handle and selecting message to send
+ * @param cls plugin
+ * @param ses session to send data to
+ * @param con connection
+ * @return bytes sent to peer
+ */
+static ssize_t send_check_connections (void *cls, struct Session *ps);
+
+static size_t curl_get_header_function( void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  struct Session * ps = stream;
+
+  char * tmp;
+  size_t len = size * nmemb;
+  long http_result = 0;
+  int res;
+  /* Getting last http result code */
+  if (ps->recv_connected==GNUNET_NO)
+  {
+    GNUNET_assert(NULL!=ps);
+    res = curl_easy_getinfo(ps->recv_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
+    if (CURLE_OK == res)
+    {
+      if (http_result == 200)
+      {
+        ps->recv_connected = GNUNET_YES;
+        ps->recv_active = GNUNET_YES;
+#if DEBUG_CONNECTIONS
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: connected to recieve data\n",ps);
+#endif
+        // Calling send_check_connections again since receive is established
+        send_check_connections (ps->peercontext->plugin, ps);
+      }
+    }
+  }
+
+  tmp = NULL;
+  if ((size * nmemb) < SIZE_MAX)
+    tmp = GNUNET_malloc (len+1);
+
+  if ((tmp != NULL) && (len > 0))
+  {
+    memcpy(tmp,ptr,len);
+    if (len>=2)
+    {
+      if (tmp[len-2] == 13)
+        tmp[len-2]= '\0';
+    }
+#if DEBUG_HTTP
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s' %u \n",tmp, http_result);
+#endif
+  }
+  if (NULL != tmp)
+    GNUNET_free (tmp);
+
+  return size * nmemb;
+}
+
+static size_t curl_put_header_function( void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  struct Session * ps = stream;
+
+  char * tmp;
+  size_t len = size * nmemb;
+  long http_result = 0;
+  int res;
+
+  /* Getting last http result code */
+  GNUNET_assert(NULL!=ps);
+  res = curl_easy_getinfo(ps->send_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
+  if (CURLE_OK == res)
+  {
+    if ((http_result == 100) && (ps->send_connected==GNUNET_NO))
+    {
+      ps->send_connected = GNUNET_YES;
+      ps->send_active = GNUNET_YES;
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: connected to send data\n",ps);
+#endif
+    }
+    if ((http_result == 200) && (ps->send_connected==GNUNET_YES))
+    {
+      ps->send_connected = GNUNET_NO;
+      ps->send_active = GNUNET_NO;
+#if DEBUG_CONNECTIONS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: sending disconnected\n",ps);
+#endif
+    }
+  }
+
+  tmp = NULL;
+  if ((size * nmemb) < SIZE_MAX)
+    tmp = GNUNET_malloc (len+1);
+
+  if ((tmp != NULL) && (len > 0))
+  {
+    memcpy(tmp,ptr,len);
+    if (len>=2)
+    {
+      if (tmp[len-2] == 13)
+        tmp[len-2]= '\0';
+    }
+#if DEBUG_HTTP
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s' %u \n",tmp, http_result);
+#endif
+  }
+  if (NULL != tmp)
+    GNUNET_free (tmp);
+
+  return size * nmemb;
+}
 
 /**
 
 /**
- * Function that queries MHD's select sets and
- * starts the task waiting for them.
+ * Callback method used with libcurl
+ * Method is called when libcurl needs to read data during sending
+ * @param stream pointer where to write data
+ * @param size size of an individual element
+ * @param nmemb count of elements that can be written to the buffer
+ * @param ptr source pointer, passed to the libcurl handle
+ * @return bytes written to stream
  */
  */
-static GNUNET_SCHEDULER_TaskIdentifier
-http_daemon_prepare (struct MHD_Daemon *daemon_handle)
+static size_t curl_send_cb(void *stream, size_t size, size_t nmemb, void *ptr)
 {
 {
-  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;
+  struct Session * ps = ptr;
+  struct HTTP_Message * msg = ps->pending_msgs_tail;
+  size_t bytes_sent;
+  size_t len;
 
 
-  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;
+  if (ps->pending_msgs_tail == NULL)
+  {
+#if DEBUG_CONNECTIONS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: No Message to send, pausing connection\n",ps);
+#endif
+    ps->send_active = GNUNET_NO;
+    return CURL_READFUNC_PAUSE;
+  }
+
+  msg = ps->pending_msgs_tail;
+  /* data to send */
+  if (msg->pos < msg->size)
+  {
+    /* data fit in buffer */
+    if ((msg->size - msg->pos) <= (size * nmemb))
+    {
+      len = (msg->size - msg->pos);
+      memcpy(stream, &msg->buf[msg->pos], len);
+      msg->pos += len;
+      bytes_sent = len;
+    }
+    else
+    {
+      len = size*nmemb;
+      memcpy(stream, &msg->buf[msg->pos], len);
+      msg->pos += len;
+      bytes_sent = len;
+    }
+  }
+  /* no data to send */
   else
   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;
+  {
+    bytes_sent = 0;
+  }
+
+  if ( msg->pos == msg->size)
+  {
+#if DEBUG_CONNECTIONS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Message with %u bytes sent, removing message from queue \n",ps, msg->pos);
+#endif
+    /* Calling transmit continuation  */
+    if (( NULL != ps->pending_msgs_tail) && (NULL != ps->pending_msgs_tail->transmit_cont))
+      msg->transmit_cont (ps->pending_msgs_tail->transmit_cont_cls,&(ps->peercontext)->identity,GNUNET_OK);
+    remove_http_message(ps, msg);
+  }
+  return bytes_sent;
 }
 
 /**
 }
 
 /**
- * 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)
+* Callback method used with libcurl
+* Method is called when libcurl needs to write data during sending
+* @param stream pointer where to write data
+* @param size size of an individual element
+* @param nmemb count of elements that can be written to the buffer
+* @param ptr destination pointer, passed to the libcurl handle
+* @return bytes read from stream
+*/
+static size_t curl_receive_cb( void *stream, size_t size, size_t nmemb, void *ptr)
 {
 {
-  struct MHD_Daemon *daemon_handle = cls;
+  struct Session * ps = ptr;
+#if DEBUG_CONNECTIONS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes received\n",ps, size*nmemb);
+#endif
 
 
-  if (daemon_handle == http_daemon_v4)
-    http_task_v4 = GNUNET_SCHEDULER_NO_TASK;
+  struct GNUNET_MessageHeader * msg = stream;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes msg->type %u msg->size %u\n",ps, size*nmemb, ntohs(msg->type), ntohs(msg->size));
 
 
-  if (daemon_handle == http_daemon_v6)
-    http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+  // GNUNET_SERVER_mst_receive(ps->msgtok, ps, stream, size*nmemb, GNUNET_NO, GNUNET_NO);
+  return (size * nmemb);
 
 
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    return;
+}
 
 
+/**
+ * Function setting up file descriptors and scheduling task to run
+ * @param cls closure
+ * @param ses session to send data to
+ * @return bytes sent to peer
+ */
+static size_t send_schedule(void *cls, struct Session* ses );
 
 
 
 
-  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)
+/**
+ * Function setting up curl handle and selecting message to send
+ * @param cls plugin
+ * @param ses session to send data to
+ * @param con connection
+ * @return bytes sent to peer
+ */
+static ssize_t send_check_connections (void *cls, struct Session *ps)
 {
 {
-  struct Session  * ses = ptr;
-  struct CBC * cbc = &(ses->cbc);
+  struct Plugin *plugin = cls;
+  int bytes_sent = 0;
+  CURLMcode mret;
+  struct HTTP_Message * msg;
+  struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
 
 
-  if (cbc->len > (size * nmemb))
-    return CURL_READFUNC_ABORT;
+  GNUNET_assert(cls !=NULL);
 
 
-  if (( cbc->pos == cbc->len) && (cbc->len < (size * nmemb)))
-    return 0;
-  memcpy(stream, cbc->buf, cbc->len);
-  cbc->pos = cbc->len;
-  return cbc->len;
-}
+  if (ps->direction == OUTBOUND)
+  {
+    /* RECV DIRECTION */
+    /* Check if session is connected to receive data, otherwise connect to peer */
+    if (ps->recv_connected == GNUNET_NO)
+    {
+        if (ps->recv_endpoint == NULL)
+        {
+          ps->recv_endpoint = curl_easy_init();
+#if DEBUG_CURL
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L);
+#endif
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_URL, ps->url);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_HEADERFUNCTION, &curl_get_header_function);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEHEADER, ps);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_READDATA, ps);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEDATA, ps);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_PRIVATE, ps);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
+        curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
+
+        mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint);
+        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_schedule (plugin, NULL);
+#if DEBUG_CONNECTIONS
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound not connected, initiating connection\n",ps);
+#endif
+      }
+    }
 
 
+    /* waiting for receive direction */
+    if (ps->recv_connected==GNUNET_NO)
+      return 0;
 
 
-static size_t send_prepare(struct Session* session );
+    /* SEND DIRECTION */
+    /* Check if session is connected to send data, otherwise connect to peer */
+    if ((ps->send_connected == GNUNET_YES) && (ps->send_endpoint!= NULL))
+    {
+      if (ps->send_active == GNUNET_YES)
+      {
+#if DEBUG_CONNECTIONS
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound active, enqueueing message\n",ps);
+#endif
+        return bytes_sent;
+      }
+      if (ps->send_active == GNUNET_NO)
+      {
+#if DEBUG_CONNECTIONS
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound paused, unpausing existing connection and enqueueing message\n",ps);
+#endif
+        curl_easy_pause(ps->send_endpoint,CURLPAUSE_CONT);
+        ps->send_active=GNUNET_YES;
+        return bytes_sent;
+      }
+    }
+    /* not connected, initiate connection */
+    if ((ps->send_connected==GNUNET_NO) && (NULL == ps->send_endpoint))
+      ps->send_endpoint = curl_easy_init();
+    GNUNET_assert (ps->send_endpoint != NULL);
+    GNUNET_assert (NULL != ps->pending_msgs_tail);
+#if DEBUG_CONNECTIONS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound not connected, initiating connection\n",ps);
+#endif
+    ps->send_active = GNUNET_NO;
+    msg = ps->pending_msgs_tail;
+
+  #if DEBUG_CURL
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_VERBOSE, 1L);
+  #endif
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_URL, ps->url);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_PUT, 1L);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_HEADERFUNCTION, &curl_put_header_function);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEHEADER, ps);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_PRIVATE, ps);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
+    curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
+
+    mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint);
+    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_schedule (plugin, NULL);
+    return bytes_sent;
+  }
+  if (ps->direction == INBOUND)
+  {
+    GNUNET_assert (NULL != ps->pending_msgs_tail);
+    bytes_sent = 0;
+    msg = ps->pending_msgs_tail;
+    if ((ps->recv_connected==GNUNET_YES) && (ps->send_connected==GNUNET_YES))
+        bytes_sent = msg->size;
+    return bytes_sent;
+  }
+  return 0;
+}
 
 static void send_execute (void *cls,
              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 
 static void send_execute (void *cls,
              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  struct Plugin *plugin = cls;
+  static unsigned int handles_last_run;
   int running;
   struct CURLMsg *msg;
   CURLMcode mret;
   int running;
   struct CURLMsg *msg;
   CURLMcode mret;
-  struct Session * cs = cls;
-
- // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"send_execute\n");
+  struct Session *ps = NULL;
+  struct HTTP_PeerContext *pc = NULL;
+  struct HTTP_Message * cur_msg = NULL;
+  long http_result;
 
 
-  http_task_send = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_assert(cls !=NULL);
+  plugin->http_server_task_send = GNUNET_SCHEDULER_NO_TASK;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return;
 
   do
     {
       running = 0;
   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)
+      mret = curl_multi_perform (plugin->multi_handle, &running);
+      if (running < handles_last_run)
         {
           do
             {
 
         {
           do
             {
 
-              msg = curl_multi_info_read (multi_handle, &running);
-              GNUNET_break (msg != NULL);
+              msg = curl_multi_info_read (plugin->multi_handle, &running);
               if (msg == NULL)
                 break;
               if (msg == NULL)
                 break;
+              /* get session for affected curl handle */
+              GNUNET_assert ( msg->easy_handle != NULL );
+              curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char *) &ps);
+              GNUNET_assert ( ps != NULL );
+              pc = ps->peercontext;
+              GNUNET_assert ( pc != NULL );
               switch (msg->msg)
                 {
               switch (msg->msg)
                 {
+
                 case CURLMSG_DONE:
                   if ( (msg->data.result != CURLE_OK) &&
                        (msg->data.result != CURLE_GOT_NOTHING) )
                 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",
-                               cs->ip,
-                               __FILE__,
-                               __LINE__,
-                               curl_easy_strerror (msg->data.result));
+                  {
+                    /* sending msg failed*/
+                    if (msg->easy_handle == ps->send_endpoint)
+                    {
+#if DEBUG_CONNECTIONS
+                      GNUNET_log(GNUNET_ERROR_TYPE_INFO,
+                                 _("Connection %X: HTTP PUT to peer `%s' (`%s') failed: `%s' `%s'\n"),
+                                 ps,
+                                 GNUNET_i2s(&pc->identity),
+                                 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
+                                 "curl_multi_perform",
+                                 curl_easy_strerror (msg->data.result));
+#endif
+                      ps->send_connected = GNUNET_NO;
+                      ps->send_active = GNUNET_NO;
+                      curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
+                      curl_easy_cleanup(ps->send_endpoint);
+                      ps->send_endpoint=NULL;
+                      cur_msg = ps->pending_msgs_tail;
+                      if (( NULL != cur_msg) && ( NULL != cur_msg->transmit_cont))
+                        cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
+                    }
+                    /* GET connection failed */
+                    if (msg->easy_handle == ps->recv_endpoint)
+                    {
+#if DEBUG_CONNECTIONS
+                      GNUNET_log(GNUNET_ERROR_TYPE_INFO,
+                           _("Connection %X: HTTP GET to peer `%s' (`%s') failed: `%s' `%s'\n"),
+                           ps,
+                           GNUNET_i2s(&pc->identity),
+                           http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
+                           "curl_multi_perform",
+                           curl_easy_strerror (msg->data.result));
+#endif
+                      ps->recv_connected = GNUNET_NO;
+                      ps->recv_active = GNUNET_NO;
+                      curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
+                      curl_easy_cleanup(ps->recv_endpoint);
+                      ps->recv_endpoint=NULL;
+                    }
+                  }
                   else
                   else
+                  {
+                    if (msg->easy_handle == ps->send_endpoint)
+                    {
+                      GNUNET_assert (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_result));
+#if DEBUG_CONNECTIONS
+                      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                                  "Connection %X: HTTP PUT connection to peer `%s' (`%s') was closed with HTTP code %u\n",
+                                   ps,
+                                   GNUNET_i2s(&pc->identity),
+                                   http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
+                                   http_result);
+#endif
+                      /* Calling transmit continuation  */
+                      cur_msg = ps->pending_msgs_tail;
+                      if (( NULL != cur_msg) && (NULL != cur_msg->transmit_cont))
+                      {
+                        /* HTTP 1xx : Last message before here was informational */
+                        if ((http_result >=100) && (http_result < 200))
+                          cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
+                        /* HTTP 2xx: successful operations */
+                        if ((http_result >=200) && (http_result < 300))
+                          cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
+                        /* HTTP 3xx..5xx: error */
+                        if ((http_result >=300) && (http_result < 600))
+                          cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
+                      }
+                      ps->send_connected = GNUNET_NO;
+                      ps->send_active = GNUNET_NO;
+                      curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
+                      curl_easy_cleanup(ps->send_endpoint);
+                      ps->send_endpoint =NULL;
+                    }
+                    if (msg->easy_handle == ps->recv_endpoint)
                     {
                     {
-                    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                                "Send to %s completed.\n", cs->ip);
-                    /* Calling transmit continuation */
-                    if ( NULL != cs->transmit_cont)
-                      cs->transmit_cont (NULL,&cs->sender,GNUNET_OK);
-
-                    curl_easy_cleanup(cs->curl_handle);
-                    cs->curl_handle=NULL;
+#if DEBUG_CONNECTIONS
+                      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                                  "Connection %X: HTTP GET connection to peer `%s' (`%s') was closed with HTTP code %u\n",
+                                   ps,
+                                   GNUNET_i2s(&pc->identity),
+                                   http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
+                                   http_result);
+#endif
+                      ps->recv_connected = GNUNET_NO;
+                      ps->recv_active = GNUNET_NO;
+                      curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
+                      curl_easy_cleanup(ps->recv_endpoint);
+                      ps->recv_endpoint=NULL;
                     }
                     }
+                  }
+                  if ((ps->recv_connected == GNUNET_NO) && (ps->send_connected == GNUNET_NO))
+                    remove_session (pc, ps, GNUNET_YES, GNUNET_SYSERR);
                   return;
                 default:
                   break;
                   return;
                 default:
                   break;
@@ -722,14 +1438,21 @@ static void send_execute (void *cls,
             }
           while ( (running > 0) );
         }
             }
           while ( (running > 0) );
         }
+      handles_last_run = running;
     }
   while (mret == CURLM_CALL_MULTI_PERFORM);
     }
   while (mret == CURLM_CALL_MULTI_PERFORM);
-  send_prepare(cls);
+  send_schedule(plugin, cls);
 }
 
 
 }
 
 
-static size_t send_prepare(struct Session* session )
+/**
+ * Function setting up file descriptors and scheduling task to run
+ * @param ses session to send data to
+ * @return bytes sent to peer
+ */
+static size_t send_schedule(void *cls, struct Session* ses )
 {
 {
+  struct Plugin *plugin = cls;
   fd_set rs;
   fd_set ws;
   fd_set es;
   fd_set rs;
   fd_set ws;
   fd_set es;
@@ -739,12 +1462,12 @@ static size_t send_prepare(struct Session* session )
   long to;
   CURLMcode mret;
 
   long to;
   CURLMcode mret;
 
-//  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"send_prepare\n");
+  GNUNET_assert(cls !=NULL);
   max = -1;
   FD_ZERO (&rs);
   FD_ZERO (&ws);
   FD_ZERO (&es);
   max = -1;
   FD_ZERO (&rs);
   FD_ZERO (&ws);
   FD_ZERO (&es);
-  mret = curl_multi_fdset (multi_handle, &rs, &ws, &es, &max);
+  mret = curl_multi_fdset (plugin->multi_handle, &rs, &ws, &es, &max);
   if (mret != CURLM_OK)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   if (mret != CURLM_OK)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -753,7 +1476,7 @@ static size_t send_prepare(struct Session* session )
                   curl_multi_strerror (mret));
       return -1;
     }
                   curl_multi_strerror (mret));
       return -1;
     }
-  mret = curl_multi_timeout (multi_handle, &to);
+  mret = curl_multi_timeout (plugin->multi_handle, &to);
   if (mret != CURLM_OK)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   if (mret != CURLM_OK)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -767,14 +1490,14 @@ static size_t send_prepare(struct Session* session )
   gws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
   gws = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
-  http_task_send = GNUNET_SCHEDULER_add_select (plugin->env->sched,
+  plugin->http_server_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,
                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                                    GNUNET_SCHEDULER_NO_TASK,
                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
                                    grs,
                                    gws,
                                    &send_execute,
-                                   session);
+                                   plugin);
   GNUNET_NETWORK_fdset_destroy (gws);
   GNUNET_NETWORK_fdset_destroy (grs);
 
   GNUNET_NETWORK_fdset_destroy (gws);
   GNUNET_NETWORK_fdset_destroy (grs);
 
@@ -785,25 +1508,35 @@ static size_t send_prepare(struct Session* session )
 
 /**
  * Function that can be used by the transport service to transmit
 
 /**
  * Function that can be used by the transport service to transmit
- * a message using the plugin.
+ * a message using the plugin.   Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself.  This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
  *
  * @param cls closure
  * @param target who should receive this message
  *
  * @param cls closure
  * @param target who should receive this message
- * @param priority how important is the message
  * @param msgbuf the message to transmit
  * @param msgbuf_size number of bytes in 'msgbuf'
  * @param msgbuf the message to transmit
  * @param msgbuf_size number of bytes in 'msgbuf'
- * @param timeout when should we time out
+ * @param priority how important is the message (most plugins will
+ *                 ignore message priority and just FIFO)
+ * @param timeout how long to wait at most for the transmission (does not
+ *                require plugins to discard the message after the timeout,
+ *                just advisory for the desired delay; most plugins will ignore
+ *                this as well)
  * @param session which session must be used (or NULL for "any")
  * @param addr the address to use (can be NULL if the plugin
  *                is "on its own" (i.e. re-use existing TCP connection))
  * @param addrlen length of the address in bytes
  * @param force_address GNUNET_YES if the plugin MUST use the given address,
  * @param session which session must be used (or NULL for "any")
  * @param addr the address to use (can be NULL if the plugin
  *                is "on its own" (i.e. re-use existing TCP connection))
  * @param addrlen length of the address in bytes
  * @param force_address GNUNET_YES if the plugin MUST use the given address,
- *                otherwise the plugin may use other addresses or
- *                existing connections (if available)
+ *                GNUNET_NO means the plugin may use any other address and
+ *                GNUNET_SYSERR means that only reliable existing
+ *                bi-directional connections should be used (regardless
+ *                of address)
  * @param cont continuation to call once the message has
  *        been transmitted (or if the transport is ready
  *        for the next transmission call; or if the
  * @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...)
+ *        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
  * @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
@@ -811,97 +1544,154 @@ static size_t send_prepare(struct Session* session )
  */
 static ssize_t
 http_plugin_send (void *cls,
  */
 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 to,
+                  struct Session *session,
+                  const void *addr,
+                  size_t addrlen,
+                  int force_address,
+                  GNUNET_TRANSPORT_TransmitContinuation cont,
+                  void *cont_cls)
 {
 {
-  struct Session* ses;
-  struct Session* ses_temp;
-  int bytes_sent = 0;
-  CURLMcode mret;
-  char * url;
-
-  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)
+  struct Plugin *plugin = cls;
+  struct HTTP_Message *msg;
+
+  struct HTTP_PeerContext * pc;
+  struct Session * ps = NULL;
+  struct Session * ps_tmp = NULL;
+
+  GNUNET_assert(cls !=NULL);
+
+  char * force = GNUNET_malloc(40);
+  if (force_address == GNUNET_YES)
+    strcpy(force,"forced addr.");
+  if (force_address == GNUNET_NO)
+    strcpy(force,"any addr.");
+  if (force_address == GNUNET_SYSERR)
+    strcpy(force,"reliable bi-direc. address addr.");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to `%s' using %s (%s) and session: %X\n",
+                                      msgbuf_size,
+                                      GNUNET_i2s(target),
+                                      force,
+                                      http_plugin_address_to_string(NULL, addr, addrlen),
+                                      session);
+  GNUNET_free(force);
+
+  pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
+  /* Peer unknown */
+  if (pc==NULL)
   {
   {
-    /* create new session object */
+    pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
+    pc->plugin = plugin;
+    pc->session_id_counter=1;
+    memcpy(&pc->identity, target, sizeof(struct GNUNET_PeerIdentity));
+    GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+  }
 
 
-    /*FIXME: what is const void * really? Assuming struct sockaddr_in * ! */
-    ses = create_session((struct sockaddr_in *) addr, target);
-    ses->is_active = GNUNET_YES;
-    ses->transmit_cont = cont;
+  /* Search for existing session using the passed address */
+  if  ((addr!=NULL) && (addrlen != 0))
+  {
+    ps = get_Session(plugin, pc, addr, addrlen);
+  }
+  if (ps != NULL)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Found existing connection to peer %s with given address, using %X\n", GNUNET_i2s(target), ps);
 
 
-    /* Insert session into linked list */
-    if ( plugin->sessions == NULL)
-    {
-      plugin->sessions = ses;
-      plugin->session_count = 1;
-    }
-    ses_temp = plugin->sessions;
-    while ( ses_temp->next != NULL )
-    {
-      ses_temp = ses_temp->next;
-    }
-    if (ses_temp != ses )
+  /* Search for existing session using the passed session */
+  if ((ps==NULL) && (force_address != GNUNET_YES))
+  {
+    ps_tmp = pc->head;
+    while (ps_tmp!=NULL)
     {
     {
-      ses_temp->next = ses;
-      plugin->session_count++;
+      if ((ps_tmp==session) && (ps_tmp->recv_force_disconnect==GNUNET_NO) && (ps_tmp->send_force_disconnect==GNUNET_NO) &&
+          (ps_tmp->recv_connected==GNUNET_YES) && (ps_tmp->send_connected==GNUNET_YES))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Found existing connection to peer %s with given session, using inbound session %X\n", GNUNET_i2s(target), ps_tmp);
+        ps = ps_tmp;
+        break;
+      }
+      ps_tmp=ps_tmp->next;
     }
     }
-    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)
+  /* session not existing, address not forced -> looking for other session */
+  if ((ps==NULL) && (force_address != GNUNET_YES))
   {
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Getting cURL handle failed\n");
-    return -1;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection, but free to choose existing, searching for existing connection to peer %s\n", GNUNET_i2s(target));
+    /* Choosing different session to peer when possible */
+    struct Session * tmp = pc->head;
+    while (tmp!=NULL)
+    {
+      if ((tmp->recv_connected) && (tmp->send_connected) && (tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
+      {
+        ps = tmp;
+      }
+      tmp = tmp->next;
+    }
+    if (ps != NULL)
+     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection to peer %s, selected connection %X\n", GNUNET_i2s(target),ps);
+    else
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection to peer %s, no connection found\n", GNUNET_i2s(target));
   }
 
   }
 
-  url = GNUNET_malloc( 7 + strlen(ses->ip) + 7 + strlen ((char *) &(ses->hash)) + 1);
-  /* FIXME: use correct port number */
-  GNUNET_asprintf(&url,"http://%s:%u/%s",ses->ip,12389, (char *) &(ses->hash));
-
-  if ( NULL != cont)
-    ses->transmit_cont = cont;
-
-  (ses->cbc).len = msgbuf_size;
-  (ses->cbc).buf = buf;
-  memcpy(ses->cbc.buf,msgbuf,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(ses->curl_handle, CURLOPT_TIMEOUT, (timeout.value / 1000 ));
-  curl_easy_setopt(ses->curl_handle, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
-
-  mret = curl_multi_add_handle(multi_handle, ses->curl_handle);
-  if (mret != CURLM_OK)
+  /* session not existing, but address forced -> creating new session */
+  if ((ps==NULL) || ((ps==NULL) && (force_address == GNUNET_YES)))
   {
   {
-    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;
+    if ((addr!=NULL) && (addrlen!=0))
+    {
+      if (force_address == GNUNET_YES)
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection & forced address: creating new connection to peer %s\n", GNUNET_i2s(target));
+      if (force_address != GNUNET_YES)
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection: creating new connection to peer %s\n", GNUNET_i2s(target));
+
+      ps = GNUNET_malloc(sizeof (struct Session));
+      if ((addrlen!=0) && (addr!=NULL))
+      {
+      ps->addr = GNUNET_malloc(addrlen);
+      memcpy(ps->addr,addr,addrlen);
+      ps->addrlen = addrlen;
+      }
+      else
+      {
+        ps->addr = NULL;
+        ps->addrlen = 0;
+      }
+      ps->direction=OUTBOUND;
+      ps->recv_connected = GNUNET_NO;
+      ps->recv_force_disconnect = GNUNET_NO;
+      ps->send_connected = GNUNET_NO;
+      ps->send_force_disconnect = GNUNET_NO;
+      ps->pending_msgs_head = NULL;
+      ps->pending_msgs_tail = NULL;
+      ps->peercontext=pc;
+      ps->session_id = pc->session_id_counter;
+      pc->session_id_counter++;
+      ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
+      if (ps->msgtok == NULL)
+        ps->msgtok = GNUNET_SERVER_mst_create (&curl_receive_mst_cb, ps);
+      GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing session & and no address given: no way to send this message to peer `%s'!\n", GNUNET_i2s(target));
+      return -1;
+    }
   }
   }
-  bytes_sent = send_prepare (ses );
-  GNUNET_free ( url );
-  return bytes_sent;
+
+  /* create msg */
+  msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
+  msg->next = NULL;
+  msg->size = msgbuf_size;
+  msg->pos = 0;
+  msg->buf = (char *) &msg[1];
+  msg->transmit_cont = cont;
+  msg->transmit_cont_cls = cont_cls;
+  memcpy (msg->buf,msgbuf, msgbuf_size);
+  GNUNET_CONTAINER_DLL_insert(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
+
+  return send_check_connections (plugin, ps);
 }
 
 
 }
 
 
@@ -918,9 +1708,50 @@ static void
 http_plugin_disconnect (void *cls,
                             const struct GNUNET_PeerIdentity *target)
 {
 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
+
+  struct Plugin *plugin = cls;
+  struct HTTP_PeerContext *pc = NULL;
+  struct Session *ps = NULL;
+
+  pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
+  if (pc==NULL)
+    return;
+
+  ps = pc->head;
+
+  while (ps!=NULL)
+  {
+    if (ps->direction==OUTBOUND)
+    {
+      if (ps->send_endpoint!=NULL)
+      {
+        curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
+        curl_easy_cleanup(ps->send_endpoint);
+        ps->send_endpoint=NULL;
+        ps->send_force_disconnect = GNUNET_YES;
+      }
+      if (ps->recv_endpoint!=NULL)
+      {
+       curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
+       curl_easy_cleanup(ps->recv_endpoint);
+       ps->recv_endpoint=NULL;
+       ps->recv_force_disconnect = GNUNET_YES;
+      }
+    }
+    if (ps->direction==INBOUND)
+    {
+      ps->recv_force_disconnect = GNUNET_YES;
+      ps->send_force_disconnect = GNUNET_YES;
+    }
+    while (ps->pending_msgs_head!=NULL)
+    {
+      remove_http_message(ps, ps->pending_msgs_head);
+    }
+    ps->recv_active = GNUNET_NO;
+    ps->send_active = GNUNET_NO;
+    ps=ps->next;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"All connections to peer `%s' terminated\n", GNUNET_i2s(target));
 }
 
 
 }
 
 
@@ -948,8 +1779,44 @@ http_plugin_address_pretty_printer (void *cls,
                                         GNUNET_TRANSPORT_AddressStringCallback
                                         asc, void *asc_cls)
 {
                                         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);
+  const struct IPv4HttpAddress *t4;
+  const struct IPv6HttpAddress *t6;
+  struct sockaddr_in a4;
+  struct sockaddr_in6 a6;
+  char * address;
+  char * ret;
+  unsigned int port;
+  unsigned int res;
+
+  GNUNET_assert(cls !=NULL);
+  if (addrlen == sizeof (struct IPv6HttpAddress))
+  {
+    address = GNUNET_malloc (INET6_ADDRSTRLEN);
+    t6 = addr;
+    a6.sin6_addr = t6->ipv6_addr;
+    inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
+    port = ntohs(t6->u6_port);
+  }
+  else if (addrlen == sizeof (struct IPv4HttpAddress))
+  {
+    address = GNUNET_malloc (INET_ADDRSTRLEN);
+    t4 = addr;
+    a4.sin_addr.s_addr =  t4->ipv4_addr;
+    inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
+    port = ntohs(t4->u_port);
+  }
+  else
+  {
+    /* invalid address */
+    GNUNET_break_op (0);
+    asc (asc_cls, NULL);
+    return;
+  }
+  res = GNUNET_asprintf(&ret,"http://%s:%u/",address,port);
+  GNUNET_free (address);
+  GNUNET_assert(res != 0);
+
+  asc (asc_cls, ret);
 }
 
 
 }
 
 
@@ -968,13 +1835,45 @@ http_plugin_address_pretty_printer (void *cls,
  */
 static int
 http_plugin_address_suggested (void *cls,
  */
 static int
 http_plugin_address_suggested (void *cls,
-                                  void *addr, size_t addrlen)
+                               const void *addr, size_t addrlen)
 {
 {
-  /* struct Plugin *plugin = 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");
+  struct Plugin *plugin = cls;
+  struct IPv4HttpAddress *v4;
+  struct IPv6HttpAddress *v6;
+  unsigned int port;
+
+  GNUNET_assert(cls !=NULL);
+  if ((addrlen != sizeof (struct IPv4HttpAddress)) &&
+      (addrlen != sizeof (struct IPv6HttpAddress)))
+    {
+      return GNUNET_SYSERR;
+    }
+  if (addrlen == sizeof (struct IPv4HttpAddress))
+    {
+      v4 = (struct IPv4HttpAddress *) addr;
+      if (INADDR_LOOPBACK == ntohl(v4->ipv4_addr))
+      {
+        return GNUNET_SYSERR;
+      }
+      port = ntohs (v4->u_port);
+      if (port != plugin->port_inbound)
+      {
+        return GNUNET_SYSERR;
+      }
+    }
+  else
+    {
+      v6 = (struct IPv6HttpAddress *) addr;
+      if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
+        {
+          return GNUNET_SYSERR;
+        }
+      port = ntohs (v6->u6_port);
+      if (port != plugin->port_inbound)
+      {
+        return GNUNET_SYSERR;
+      }
+    }
   return GNUNET_OK;
 }
 
   return GNUNET_OK;
 }
 
@@ -995,11 +1894,143 @@ http_plugin_address_to_string (void *cls,
                                    const void *addr,
                                    size_t addrlen)
 {
                                    const void *addr,
                                    size_t addrlen)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Plugin: http_plugin_address_to_string\n");
-  GNUNET_break (0);
-  return NULL;
+  const struct IPv4HttpAddress *t4;
+  const struct IPv6HttpAddress *t6;
+  struct sockaddr_in a4;
+  struct sockaddr_in6 a6;
+  char * address;
+  char * ret;
+  uint16_t port;
+  unsigned int res;
+
+  if (addrlen == sizeof (struct IPv6HttpAddress))
+    {
+      address = GNUNET_malloc (INET6_ADDRSTRLEN);
+      t6 = addr;
+      a6.sin6_addr = t6->ipv6_addr;
+      inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
+      port = ntohs(t6->u6_port);
+    }
+  else if (addrlen == sizeof (struct IPv4HttpAddress))
+    {
+      address = GNUNET_malloc (INET_ADDRSTRLEN);
+      t4 = addr;
+      a4.sin_addr.s_addr =  t4->ipv4_addr;
+      inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
+      port = ntohs(t4->u_port);
+    }
+  else
+    {
+      /* invalid address */
+      return NULL;
+    }
+  res = GNUNET_asprintf(&ret,"%s:%u",address,port);
+  GNUNET_free (address);
+  GNUNET_assert(res != 0);
+  return ret;
+}
+
+/**
+ * Add the IP of our network interface to the list of
+ * our external IP addresses.
+ *
+ * @param cls the 'struct Plugin*'
+ * @param name name of the interface
+ * @param isDefault do we think this may be our default interface
+ * @param addr address of the interface
+ * @param addrlen number of bytes in addr
+ * @return GNUNET_OK to continue iterating
+ */
+static int
+process_interfaces (void *cls,
+                    const char *name,
+                    int isDefault,
+                    const struct sockaddr *addr, socklen_t addrlen)
+{
+  struct Plugin *plugin = cls;
+  struct IPv4HttpAddress * t4;
+  struct IPv6HttpAddress * t6;
+  int af;
+
+  GNUNET_assert(cls !=NULL);
+  af = addr->sa_family;
+  if (af == AF_INET)
+    {
+      t4 = GNUNET_malloc(sizeof(struct IPv4HttpAddress));
+      if (INADDR_LOOPBACK == ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr))
+      {
+        /* skip loopback addresses */
+        return GNUNET_OK;
+      }
+      t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+      t4->u_port = htons (plugin->port_inbound);
+      plugin->env->notify_address(plugin->env->cls,"http",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
+
+    }
+  else if (af == AF_INET6)
+    {
+      t6 = GNUNET_malloc(sizeof(struct IPv6HttpAddress));
+      if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
+        {
+          /* skip link local addresses */
+          return GNUNET_OK;
+        }
+      if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))
+        {
+          /* skip loopback addresses */
+          return GNUNET_OK;
+        }
+      memcpy (&t6->ipv6_addr,
+              &((struct sockaddr_in6 *) addr)->sin6_addr,
+              sizeof (struct in6_addr));
+      t6->u6_port = htons (plugin->port_inbound);
+      plugin->env->notify_address(plugin->env->cls,"http",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
+    }
+  return GNUNET_OK;
+}
+
+int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value)
+{
+  struct HTTP_PeerContext * pc = value;
+  struct Session * ps = pc->head;
+  struct Session * tmp = NULL;
+  struct HTTP_Message * msg = NULL;
+  struct HTTP_Message * msg_tmp = NULL;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity));
+
+  while (ps!=NULL)
+  {
+    tmp = ps->next;
+
+    GNUNET_free_non_null (ps->addr);
+    GNUNET_free(ps->url);
+    if (ps->msgtok != NULL)
+      GNUNET_SERVER_mst_destroy (ps->msgtok);
+
+    msg = ps->pending_msgs_head;
+    while (msg!=NULL)
+    {
+      msg_tmp = msg->next;
+      GNUNET_free(msg);
+      msg = msg_tmp;
+    }
+    if (ps->direction==OUTBOUND)
+    {
+      if (ps->send_endpoint!=NULL)
+        curl_easy_cleanup(ps->send_endpoint);
+      if (ps->recv_endpoint!=NULL)
+        curl_easy_cleanup(ps->recv_endpoint);
+    }
+
+    GNUNET_free(ps);
+    ps=tmp;
+  }
+  GNUNET_free(pc);
+  return GNUNET_YES;
 }
 
 }
 
+
 /**
  * Exit point from the plugin.
  */
 /**
  * Exit point from the plugin.
  */
@@ -1008,64 +2039,52 @@ libgnunet_plugin_transport_http_done (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
 {
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
-  struct Session * cs;
-  struct Session * cs_next;
   CURLMcode mret;
 
   CURLMcode mret;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unloading http plugin...\n");
+  GNUNET_assert(cls !=NULL);
 
 
-  if ( http_task_v4 != GNUNET_SCHEDULER_NO_TASK)
+  if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
   {
   {
-    GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_v4);
-    http_task_v4 = GNUNET_SCHEDULER_NO_TASK;
+    GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
+    plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
   }
 
   }
 
-  if ( http_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+  if ( plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
   {
   {
-    GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_v6);
-    http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+    GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
+    plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
   }
 
   }
 
-  if ( http_task_send != GNUNET_SCHEDULER_NO_TASK)
+  if ( plugin->http_server_task_send != GNUNET_SCHEDULER_NO_TASK)
   {
   {
-    GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_send);
-    http_task_send = GNUNET_SCHEDULER_NO_TASK;
+    GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_send);
+    plugin->http_server_task_send = GNUNET_SCHEDULER_NO_TASK;
   }
 
   }
 
-  if (http_daemon_v4 != NULL)
+  if (plugin->http_server_daemon_v4 != NULL)
   {
   {
-    MHD_stop_daemon (http_daemon_v4);
-    http_daemon_v4 = NULL;
+    MHD_stop_daemon (plugin->http_server_daemon_v4);
+    plugin->http_server_daemon_v4 = NULL;
   }
   }
-  if (http_daemon_v6 != NULL)
+  if (plugin->http_server_daemon_v6 != NULL)
   {
   {
-    MHD_stop_daemon (http_daemon_v6);
-    http_daemon_v6 = NULL;
+    MHD_stop_daemon (plugin->http_server_daemon_v6);
+    plugin->http_server_daemon_v6 = NULL;
   }
 
   }
 
-  mret = curl_multi_cleanup(multi_handle);
+  /* free all peer information */
+  GNUNET_CONTAINER_multihashmap_iterate (plugin->peers,
+                                         &remove_peer_context_Iterator,
+                                         NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (plugin->peers);
+
+  mret = curl_multi_cleanup(plugin->multi_handle);
   if ( CURLM_OK != mret)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed");
 
   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); */
   GNUNET_free (plugin);
   GNUNET_free (api);
   GNUNET_free (plugin);
   GNUNET_free (api);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unload http plugin complete...\n");
   return NULL;
 }
 
   return NULL;
 }
 
@@ -1077,30 +2096,18 @@ void *
 libgnunet_plugin_transport_http_init (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
 libgnunet_plugin_transport_http_init (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+  struct Plugin *plugin;
   struct GNUNET_TRANSPORT_PluginFunctions *api;
   struct GNUNET_TRANSPORT_PluginFunctions *api;
-  struct GNUNET_SERVICE_Context *service;
-  unsigned int timeout;
   struct GNUNET_TIME_Relative gn_timeout;
   long long unsigned int port;
 
   struct GNUNET_TIME_Relative gn_timeout;
   long long unsigned int port;
 
+  GNUNET_assert(cls !=NULL);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting http plugin...\n");
 
   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 = GNUNET_malloc (sizeof (struct Plugin));
   plugin->env = env;
-  plugin->sessions = NULL;
-  plugin->service = service;
+  plugin->peers = NULL;
+
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
   api->send = &http_plugin_send;
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
   api->send = &http_plugin_send;
@@ -1109,10 +2116,8 @@ libgnunet_plugin_transport_http_init (void *cls)
   api->check_address = &http_plugin_address_suggested;
   api->address_to_string = &http_plugin_address_to_string;
 
   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 */
   /* Hashing our identity to use it in URLs */
-  GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &my_ascii_hash_ident);
+  GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &plugin->my_ascii_hash_ident);
 
   /* Reading port number from config file */
   if ((GNUNET_OK !=
 
   /* Reading port number from config file */
   if ((GNUNET_OK !=
@@ -1130,47 +2135,53 @@ libgnunet_plugin_transport_http_init (void *cls)
       libgnunet_plugin_transport_http_done (api);
       return NULL;
     }
       libgnunet_plugin_transport_http_done (api);
       return NULL;
     }
-
+  GNUNET_assert ((port > 0) && (port <= 65535));
+  plugin->port_inbound = port;
   gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
   gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
-  timeout = ( gn_timeout.value / 1000);
-  if ((http_daemon_v4 == NULL) && (http_daemon_v6 == NULL) && (port != 0))
+  if ((plugin->http_server_daemon_v4 == NULL) && (plugin->http_server_daemon_v6 == NULL) && (port != 0))
     {
     {
-    http_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
+    plugin->http_server_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
                                        port,
                                        port,
-                                       &acceptPolicyCallback,
-                                       NULL , &accessHandlerCallback, NULL,
+                                       &mhd_accept_cb,
+                                       plugin , &mdh_access_cb, plugin,
                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
                                        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_TIMEOUT, (gn_timeout.value / 1000),
                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
-                                       MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
+                                       MHD_OPTION_NOTIFY_COMPLETED, &mhd_termination_cb, NULL,
                                        MHD_OPTION_END);
                                        MHD_OPTION_END);
-    http_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
+    plugin->http_server_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
                                        port,
                                        port,
-                                       &acceptPolicyCallback,
-                                       NULL , &accessHandlerCallback, NULL,
+                                       &mhd_accept_cb,
+                                       plugin , &mdh_access_cb, plugin,
                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
                                        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_TIMEOUT, (gn_timeout.value / 1000),
                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
-                                       MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
+                                       MHD_OPTION_NOTIFY_COMPLETED, &mhd_termination_cb, NULL,
                                        MHD_OPTION_END);
     }
                                        MHD_OPTION_END);
     }
-  if (http_daemon_v4 != NULL)
-    http_task_v4 = http_daemon_prepare (http_daemon_v4);
-  if (http_daemon_v6 != NULL)
-    http_task_v6 = http_daemon_prepare (http_daemon_v6);
+  if (plugin->http_server_daemon_v4 != NULL)
+    plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
+  if (plugin->http_server_daemon_v6 != NULL)
+    plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
 
 
-  if (http_task_v4 != GNUNET_SCHEDULER_NO_TASK)
+  if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 on port %u\n",port);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 on port %u\n",port);
-  if (http_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+  else if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 on port %u\n",port);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 on port %u\n",port);
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No MHD was started, transport plugin not functional!\n");
+    libgnunet_plugin_transport_http_done (api);
+    return NULL;
+  }
 
   /* Initializing cURL */
 
   /* Initializing cURL */
-  multi_handle = curl_multi_init();
-  if ( NULL == multi_handle )
+  curl_global_init(CURL_GLOBAL_ALL);
+  plugin->multi_handle = curl_multi_init();
+
+  if ( NULL == plugin->multi_handle )
   {
     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
                      "http",
   {
     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
                      "http",
@@ -1179,7 +2190,11 @@ libgnunet_plugin_transport_http_init (void *cls)
     libgnunet_plugin_transport_http_done (api);
     return NULL;
   }
     libgnunet_plugin_transport_http_done (api);
     return NULL;
   }
+
+  plugin->peers = GNUNET_CONTAINER_multihashmap_create (10);
+  GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
+
   return api;
 }
 
   return api;
 }
 
-/* end of plugin_transport_template.c */
+/* end of plugin_transport_http.c */