(no commit message)
[oweals/gnunet.git] / src / transport / plugin_transport_http.c
index 74d9fac94d2a54a4d87d560bec01c7ab49bce74f..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
@@ -28,7 +28,6 @@
 #include "gnunet_constants.h"
 #include "gnunet_protocols.h"
 #include "gnunet_connection_lib.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_service_lib.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_transport_service.h"
 
 #define DEBUG_CURL GNUNET_NO
 #define DEBUG_HTTP GNUNET_NO
 
 #define DEBUG_CURL GNUNET_NO
 #define DEBUG_HTTP GNUNET_NO
-#define HTTP_CONNECT_TIMEOUT_DBG 10
+#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
@@ -134,7 +136,7 @@ struct HTTP_Message
    * buffer length
    */
   size_t size;
    * buffer length
    */
   size_t size;
-  
+
   /**
    * Continuation function to call once the transmission buffer
    * has again space available.  NULL if there is no
   /**
    * Continuation function to call once the transmission buffer
    * has again space available.  NULL if there is no
@@ -149,137 +151,147 @@ struct HTTP_Message
 };
 
 
 };
 
 
-struct HTTP_Connection_out
+struct HTTP_PeerContext
 {
 {
-  struct HTTP_Connection_out * next;
-
-  struct HTTP_Connection_out * prev;
-
-  void * addr;
-  size_t addrlen;
-
-  struct HTTP_Message * pending_msgs_head;
-  struct HTTP_Message * pending_msgs_tail;
-
-  char * url;
-  unsigned int connected;
-  unsigned int send_paused;
-
   /**
   /**
-   * curl handle for this ransmission
+   * peer's identity
    */
    */
-  CURL *curl_handle;
-  struct Session * session;
-};
-
-struct HTTP_Connection_in
-{
-  struct HTTP_Connection_in * next;
-
-  struct HTTP_Connection_in * prev;
-
-  void * addr;
-  size_t addrlen;
-
-  unsigned int connected;
-  unsigned int send_paused;
+  struct GNUNET_PeerIdentity identity;
 
 
-  struct GNUNET_SERVER_MessageStreamTokenizer * msgtok;
+  /**
+   * Pointer to the global plugin struct.
+   */
+  struct Plugin *plugin;
 
 
-  struct Session * session;
+  /**
+   * Linked list of connections with this peer
+   * head
+   */
+  struct Session * head;
 
   /**
 
   /**
-   * Is there a HTTP/PUT in progress?
+   * Linked list of connections with this peer
+   * tail
    */
    */
-  int is_put_in_progress;
+  struct Session * tail;
 
   /**
 
   /**
-   * Is the http request invalid?
+   * id for next session
    */
    */
-  int is_bad_request;
+  size_t session_id_counter;
 };
 
 
 };
 
 
-/**
- * Session handle for connections.
- */
 struct Session
 {
 struct Session
 {
-
   /**
    * API requirement.
    */
   struct SessionHeader header;
 
   /**
   /**
    * API requirement.
    */
   struct SessionHeader header;
 
   /**
-   * Stored in a linked list.
+   * next session in linked list
    */
    */
-  struct Session *next;
+  struct Session * next;
 
   /**
 
   /**
-   * Pointer to the global plugin struct.
+   * previous session in linked list
    */
    */
-  struct Plugin *plugin;
+  struct Session * prev;
 
   /**
 
   /**
-   * To whom are we talking to (set to our identity
-   * if we are still waiting for the welcome message)
+   * address of this session
    */
    */
-  struct GNUNET_PeerIdentity identity;
+  void * addr;
+
+  /**
+   * address length
+   */
+  size_t addrlen;
 
   /**
 
   /**
-   * Sender's ip address to distinguish between incoming connections
+   * target url
    */
    */
-  void * addr_in;
+  char * url;
 
 
-  size_t addr_in_len;
+  /**
+   * Message queue for outbound messages
+   * head of queue
+   */
+  struct HTTP_Message * pending_msgs_head;
 
 
-  void * addr_out;
+  /**
+   * Message queue for outbound messages
+   * tail of queue
+   */
+  struct HTTP_Message * pending_msgs_tail;
 
 
-  size_t addr_out_len;
+  /**
+   * partner peer this connection belongs to
+   */
+  struct HTTP_PeerContext * peercontext;
 
   /**
 
   /**
-   * Did we initiate the connection (GNUNET_YES) or the other peer (GNUNET_NO)?
+   * message stream tokenizer for incoming data
    */
    */
-  int is_client;
+  struct GNUNET_SERVER_MessageStreamTokenizer *msgtok;
 
   /**
 
   /**
-   * At what time did we reset last_received last?
+   * session direction
+   * outbound: OUTBOUND (GNUNET_YES)
+   * inbound : INBOUND (GNUNET_NO)
    */
    */
-  struct GNUNET_TIME_Absolute last_quota_update;
+  unsigned int direction;
 
   /**
 
   /**
-   * How many bytes have we received since the "last_quota_update"
-   * timestamp?
+   * is session connected to send data?
    */
    */
-  uint64_t last_received;
+  unsigned int send_connected;
 
   /**
 
   /**
-   * Number of bytes per ms that this peer is allowed
-   * to send to us.
+   * is send connection active?
    */
    */
-  uint32_t quota;
+  unsigned int send_active;
 
   /**
 
   /**
-   * Encoded hash
+   * connection disconnect forced (e.g. from transport)
    */
    */
-  struct GNUNET_CRYPTO_HashAsciiEncoded hash;
+  unsigned int send_force_disconnect;
 
   /**
 
   /**
-   * curl handle for outbound transmissions
+   * is session connected to receive data?
    */
    */
-  CURL *curl_handle;
+  unsigned int recv_connected;
 
   /**
 
   /**
-   * Message tokenizer for incoming data
+   * is receive connection active?
    */
    */
-  //struct GNUNET_SERVER_MessageStreamTokenizer * msgtok;
+  unsigned int recv_active;
 
 
-  struct HTTP_Connection_out *outbound_connections_head;
-  struct HTTP_Connection_out *outbound_connections_tail;
+  /**
+   * connection disconnect forced (e.g. from transport)
+   */
+  unsigned int recv_force_disconnect;
 
 
-  struct HTTP_Connection_in *inbound_connections_head;
-  struct HTTP_Connection_in *inbound_connections_tail;
+  /**
+   * id for next session
+   * NOTE: 0 is not an ID, zero is not defined. A correct ID is always > 0
+   */
+  size_t session_id;
+
+  /**
+   * 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;
 };
 
 /**
 };
 
 /**
@@ -294,10 +306,7 @@ struct Plugin
 
   unsigned int port_inbound;
 
 
   unsigned int port_inbound;
 
-  /**
-   * Hashmap for all existing sessions.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *sessions;
+  struct GNUNET_CONTAINER_MultiHashMap *peers;
 
   /**
    * Daemon for listening for new IPv4 connections.
 
   /**
    * Daemon for listening for new IPv4 connections.
@@ -338,236 +347,196 @@ struct Plugin
 
 
 /**
 
 
 /**
- * Create a new session
+ * 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 addr_in address the peer is using inbound
- * @param addr_out address the peer is using outbound
- * @param peer identity
- * @return created session object
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
  */
  */
-static struct Session * 
-create_session (void * cls, 
-               char * addr_in, 
-               size_t addrlen_in,
-               char * addr_out, 
-               size_t addrlen_out, 
-               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 Plugin *plugin = cls;
 {
   struct Plugin *plugin = cls;
-  struct Session * cs = GNUNET_malloc ( sizeof( struct Session) );
+  char *url = NULL;
 
 
-  GNUNET_assert(cls !=NULL);
-  if (addrlen_in != 0)
-  {
-    cs->addr_in = GNUNET_malloc (addrlen_in);
-    cs->addr_in_len = addrlen_in;
-    memcpy(cs->addr_in,addr_in,addrlen_in);
-  }
+  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);
 
 
-  if (addrlen_out != 0)
-  {
-    cs->addr_out = GNUNET_malloc (addrlen_out);
-    cs->addr_out_len = addrlen_out;
-    memcpy(cs->addr_out,addr_out,addrlen_out);
-  }
-  cs->plugin = plugin;
-  memcpy(&cs->identity, peer, sizeof (struct GNUNET_PeerIdentity));
-  GNUNET_CRYPTO_hash_to_enc(&cs->identity.hashPubKey,&(cs->hash));
-  cs->outbound_connections_head = NULL;
-  cs->outbound_connections_tail = NULL;
-  return cs;
+  return url;
 }
 
 /**
 }
 
 /**
- * Check if session for this peer is already existing, otherwise create it
- * @param cls the plugin used
- * @param p peer to get session for
- * @return session found or created
+ * 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 struct Session * session_get (void * cls, const struct GNUNET_PeerIdentity *p)
+static int remove_http_message (struct Session * ps, struct HTTP_Message * msg)
 {
 {
-  struct Plugin *plugin = cls;
-  struct Session *cs;
-  unsigned int res;
-
-  cs = GNUNET_CONTAINER_multihashmap_get (plugin->sessions, &p->hashPubKey);
-  if (cs == NULL)
-  {
-    cs = create_session(plugin, NULL, 0, NULL, 0, p);
-    res = GNUNET_CONTAINER_multihashmap_put ( plugin->sessions,
-                                        &cs->identity.hashPubKey,
-                                        cs,
-                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-    if (res == GNUNET_OK)
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "New Session `%s' inserted\n", GNUNET_i2s(p));
-  }
-  return cs;
+  GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
+  GNUNET_free(msg);
+  return GNUNET_OK;
 }
 
 }
 
-static char * create_url(void * cls, const void * addr, size_t addrlen)
+/**
+ * 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 Plugin *plugin = cls;
-  char *address;
-  char *url = NULL;
+  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);
 
 
-  GNUNET_assert ((addr!=NULL) && (addrlen != 0));
-  if (addrlen == (sizeof (struct IPv4HttpAddress)))
+  msg = ps->pending_msgs_head;
+  while (msg!=NULL)
   {
   {
-    address = GNUNET_malloc(INET_ADDRSTRLEN + 1);
-    inet_ntop(AF_INET, &((struct IPv4HttpAddress *) addr)->ipv4_addr,address,INET_ADDRSTRLEN);
-    GNUNET_asprintf (&url,
-                     "http://%s:%u/%s",
-                     address,
-                     ntohs(((struct IPv4HttpAddress *) addr)->u_port),
-                     (char *) (&plugin->my_ascii_hash_ident));
-    GNUNET_free(address);
-  }
-  else if (addrlen == (sizeof (struct IPv6HttpAddress)))
-  {
-    address = GNUNET_malloc(INET6_ADDRSTRLEN + 1);
-    inet_ntop(AF_INET6, &((struct IPv6HttpAddress *) addr)->ipv6_addr,address,INET6_ADDRSTRLEN);
-    GNUNET_asprintf(&url,
-                    "http://%s:%u/%s",
-                    address,
-                    ntohs(((struct IPv6HttpAddress *) addr)->u6_port),
-                    (char *) (&plugin->my_ascii_hash_ident));
-    GNUNET_free(address);
+    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);
   }
   }
-  return url;
+
+  GNUNET_CONTAINER_DLL_remove(pc->head,pc->tail,ps);
+  GNUNET_free(ps);
+  ps = NULL;
+  return GNUNET_OK;
 }
 
 }
 
-/**
- * Check if session already knows this address for a outbound connection to this peer
- * If address not in session, add it to the session
- * @param cls the plugin used
- * @param p the session
- * @param addr address
- * @param addr_len address length
- * @return the found or created address
- */
-static struct HTTP_Connection_out * session_check_outbound_address (void * cls, struct Session *cs, const void * addr, size_t addr_len)
+static struct Session * get_Session (void * cls, struct HTTP_PeerContext *pc, const void * addr, size_t addr_len)
 {
 {
-  struct Plugin *plugin = cls;
-  struct HTTP_Connection_out * cc = cs->outbound_connections_head;
-  struct HTTP_Connection_out * con = NULL;
+  struct Session * cc = pc->head;
+  struct Session * con = NULL;
+  unsigned int count = 0;
 
   GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
 
   GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
-
   while (cc!=NULL)
   {
     if (addr_len == cc->addrlen)
     {
       if (0 == memcmp(cc->addr, addr, addr_len))
       {
   while (cc!=NULL)
   {
     if (addr_len == cc->addrlen)
     {
       if (0 == memcmp(cc->addr, addr, addr_len))
       {
-        con = cc;
+        /* 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;
       }
     }
         break;
       }
     }
+    count++;
     cc=cc->next;
   }
     cc=cc->next;
   }
-
-  if (con==NULL)
-  {
-    con = GNUNET_malloc(sizeof(struct HTTP_Connection_out) + addr_len);
-    con->addrlen = addr_len;
-    con->addr=&con[1];
-    con->url=create_url(plugin, addr, addr_len);
-    con->connected = GNUNET_NO;
-    con->session = cs;
-    memcpy(con->addr, addr, addr_len);
-    GNUNET_CONTAINER_DLL_insert(cs->outbound_connections_head,cs->outbound_connections_tail,con);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Created new connection %X to peer `%s'\n",con,GNUNET_i2s(&cs->identity));
-  }
   return con;
 }
 
 
 /**
   return con;
 }
 
 
 /**
- * Check if session already knows this address for a inbound connection to this peer
- * If address not in session, add it to the session
- * @param cls the plugin used
- * @param p the session
- * @param addr address
- * @param addr_len address length
- * @return the found or created address
+ * Callback called by MHD when a connection is terminated
  */
  */
-static struct HTTP_Connection_in * session_check_inbound_address (void * cls, struct Session *cs, const void * addr, size_t addr_len)
+static void mhd_termination_cb (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
 {
 {
-  //struct Plugin *plugin = cls;
-  struct HTTP_Connection_in * cc = cs->inbound_connections_head;
-  struct HTTP_Connection_in * con = NULL;
-
-  GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
+  struct Session * ps = *httpSessionCache;
+  if (ps == NULL)
+    return;
+  struct HTTP_PeerContext * pc = ps->peercontext;
 
 
-  while (cc!=NULL)
+  if (connection==ps->recv_endpoint)
   {
   {
-    if (addr_len == cc->addrlen)
-    {
-      if (0 == memcmp(cc->addr, addr, addr_len))
-      {
-        con = cc;
-        break;
-      }
-    }
-    cc=cc->next;
+#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;
   }
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No connection info for this address was found\n",GNUNET_i2s(&cs->identity));
-  if (con==NULL)
+  if (connection==ps->send_endpoint)
   {
   {
-    con = GNUNET_malloc(sizeof(struct HTTP_Connection_in) + addr_len);
-    con->addrlen = addr_len;
-    con->addr=&con[1];
-    con->connected = GNUNET_NO;
-    con->session = cs;
-    memcpy(con->addr, addr, addr_len);
-    GNUNET_CONTAINER_DLL_insert(cs->inbound_connections_head,cs->inbound_connections_tail,con);
+
+    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
   }
   }
-  return con;
-}
 
 
+  /* 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);
+  }
+}
 
 
-/**
- * Callback called by MHD when a connection is terminated
- */
-static void requestCompletedCallback (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
+static void mhd_write_mst_cb (void *cls,
+                              void *client,
+                              const struct GNUNET_MessageHeader *message)
 {
 {
-  struct HTTP_Connection_in * con;
 
 
-  con = *httpSessionCache;
-  if (con == NULL)
-    return;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection from peer `%s' was terminated\n",GNUNET_i2s(&con->session->identity));
-  /* session set to inactive */
-  con->is_put_in_progress = GNUNET_NO;
-  con->is_bad_request = GNUNET_NO;
-}
+  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 messageTokenizerCallback (void *cls,
-                                      void *client,
-                                      const struct GNUNET_MessageHeader *message)
+static void curl_receive_mst_cb  (void *cls,
+                                void *client,
+                                const struct GNUNET_MessageHeader *message)
 {
 {
-  struct HTTP_Connection_in * con = cls;
-  GNUNET_assert(con != NULL);
+  struct Session *ps  = cls;
+  struct HTTP_PeerContext *pc = ps->peercontext;
+  GNUNET_assert(ps != NULL);
+  GNUNET_assert(pc != NULL);
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received message with type %u and size %u from `%s'\n",
-             ntohs(message->type),
+              "Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
+              ntohs(message->type),
               ntohs(message->size),
               ntohs(message->size),
-             GNUNET_i2s(&(con->session->identity)));
-  con->session->plugin->env->receive (con->session->plugin->env->cls,
-                           &con->session->identity,
-                           message, 1, con->session,
-                           con->addr,
-                           con->addrlen);
+              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 ip is allowed to connect.
  */
 static int
 /**
  * Check if ip is allowed to connect.
  */
 static int
-acceptPolicyCallback (void *cls,
+mhd_accept_cb (void *cls,
                       const struct sockaddr *addr, socklen_t addr_len)
 {
 #if 0
                       const struct sockaddr *addr, socklen_t addr_len)
 {
 #if 0
@@ -577,10 +546,53 @@ acceptPolicyCallback (void *cls,
   return MHD_YES;
 }
 
   return MHD_YES;
 }
 
-int server_read_callback (void *cls, uint64_t pos, char *buf, int max)
+int mhd_send_callback (void *cls, uint64_t pos, char *buf, int max)
 {
 {
-  int bytes_read = -1;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server_read_callback\n");
+  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;
 }
 
   return bytes_read;
 }
 
@@ -592,7 +604,7 @@ int server_read_callback (void *cls, uint64_t pos, char *buf, int max)
  * 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,
+mdh_access_cb (void *cls,
                        struct MHD_Connection *mhd_connection,
                        const char *url,
                        const char *method,
                        struct MHD_Connection *mhd_connection,
                        const char *url,
                        const char *method,
@@ -602,25 +614,47 @@ accessHandlerCallback (void *cls,
 {
   struct Plugin *plugin = cls;
   struct MHD_Response *response;
 {
   struct Plugin *plugin = cls;
   struct MHD_Response *response;
-  struct Session * cs;
-  struct HTTP_Connection_in * con;
   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[INET6_ADDRSTRLEN+14];
   struct GNUNET_PeerIdentity pi_in;
   char address[INET6_ADDRSTRLEN+14];
   struct GNUNET_PeerIdentity pi_in;
-  int res = GNUNET_NO;
-  int send_error_to_client;
+  size_t id_num = 0;
+
   struct IPv4HttpAddress ipv4addr;
   struct IPv6HttpAddress ipv6addr;
 
   struct IPv4HttpAddress ipv4addr;
   struct IPv6HttpAddress ipv6addr;
 
+  struct HTTP_PeerContext *pc;
+  struct Session *ps;
+  struct Session *ps_tmp;
+
+  int res = GNUNET_NO;
+  int send_error_to_client;
+  void * addr;
+  size_t addr_len;
+
   GNUNET_assert(cls !=NULL);
   send_error_to_client = GNUNET_NO;
   GNUNET_assert(cls !=NULL);
   send_error_to_client = GNUNET_NO;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"accessHandlerCallback\n");
+
   if (NULL == *httpSessionCache)
   {
     /* check url for peer identity , if invalid send HTTP 404*/
   if (NULL == *httpSessionCache)
   {
     /* check url for peer identity , if invalid send HTTP 404*/
-    res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
+    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 )
     {
       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
     if ( GNUNET_SYSERR == res )
     {
       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
@@ -635,70 +669,132 @@ accessHandlerCallback (void *cls,
   }
   else
   {
   }
   else
   {
-    con = *httpSessionCache;
-    cs = con->session;
+    ps = *httpSessionCache;
+    pc = ps->peercontext;
   }
 
   }
 
-  /* Is it a PUT or a GET request */
-  if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
+  if (NULL == *httpSessionCache)
   {
   {
-    if (NULL == *httpSessionCache)
+    /* get peer context */
+    pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &pi_in.hashPubKey);
+    /* Peer unknown */
+    if (pc==NULL)
     {
     {
-      /* get session for peer identity */
-      cs = session_get (plugin ,&pi_in);
+      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(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
-      /* Incoming IPv4 connection */
-      if ( AF_INET == conn_info->client_addr->sin_family)
-      {
-        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;
-        con = session_check_inbound_address (plugin, cs, (const void *) &ipv4addr, sizeof (struct IPv4HttpAddress));
-      }
-      /* Incoming IPv6 connection */
-      if ( AF_INET6 == conn_info->client_addr->sin_family)
+    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)
+    {
+      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)
+    {
+      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);
+    }
+
+
+    //ps = get_Session(plugin, pc, addr, addr_len);
+    ps = NULL;
+    /* only inbound sessions here */
+
+    ps_tmp = pc->head;
+    while (ps_tmp!=NULL)
+    {
+      if ((ps_tmp->direction==INBOUND) && (ps_tmp->session_id == id_num) && (id_num!=0))
       {
       {
-        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 in_addr));
-        ipv6addr.u6_port = addrin6->sin6_port;
-        con = session_check_inbound_address (plugin, cs, &ipv6addr, sizeof (struct IPv6HttpAddress));
+        if ((ps_tmp->recv_force_disconnect!=GNUNET_YES) && (ps_tmp->send_force_disconnect!=GNUNET_YES))
+        ps=ps_tmp;
+        break;
       }
       }
-      /* Set closure and update current session*/
-
-      *httpSessionCache = con;
-      if (con->msgtok==NULL)
-        con->msgtok = GNUNET_SERVER_mst_create (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, &messageTokenizerCallback, con);
+      ps_tmp=ps_tmp->next;
+    }
 
 
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",method, GNUNET_i2s(&cs->identity),address);
+    if (ps==NULL)
+    {
+      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);
     }
 
     }
 
-    if ((*upload_data_size == 0) && (con->is_put_in_progress==GNUNET_NO))
+    *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 */
+  if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
+  {
+    if (ps->recv_force_disconnect)
+    {
+#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) && (ps->recv_active==GNUNET_NO))
     {
     {
-      con->is_put_in_progress = GNUNET_YES;
+      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;
     }
 
     /* Transmission of all data complete */
       return MHD_YES;
     }
 
     /* Transmission of all data complete */
-    if ((*upload_data_size == 0) && (con->is_put_in_progress == GNUNET_YES))
+    if ((*upload_data_size == 0) && (ps->recv_active == GNUNET_YES))
     {
     {
-        response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
-        res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 200 OK as PUT Response\n",HTTP_PUT_RESPONSE, strlen (HTTP_PUT_RESPONSE), res );
-        MHD_destroy_response (response);
-        return MHD_YES;
-
-      con->is_put_in_progress = GNUNET_NO;
-      con->is_bad_request = GNUNET_NO;
-      return res;
+      response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
+      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);
+      ps->recv_active=GNUNET_NO;
+      return MHD_YES;
     }
 
     /* Recieving data */
     }
 
     /* Recieving data */
-    if ((*upload_data_size > 0) && (con->is_put_in_progress == GNUNET_YES))
+    if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES))
     {
     {
-      res = GNUNET_SERVER_mst_receive(con->msgtok, con, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
+      res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
       (*upload_data_size) = 0;
       return MHD_YES;
     }
       (*upload_data_size) = 0;
       return MHD_YES;
     }
@@ -707,30 +803,24 @@ accessHandlerCallback (void *cls,
   }
   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);
-
-    /* check url for peer identity , if invalid send HTTP 404*/
-    res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
-
-    if ( GNUNET_SYSERR == res )
+    if (ps->send_force_disconnect)
     {
     {
-      response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
-      res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, 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;
+#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;
     }
     }
-
-    response = MHD_create_response_from_callback(-1,32 * 1024, &server_read_callback, cs, NULL);
-    res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
+    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;
 }
@@ -862,24 +952,95 @@ static void http_server_daemon_v6_run (void *cls,
 }
 
 /**
 }
 
 /**
- * Removes a message from the linked list of messages
- * @param ses session to remove message from
- * @param msg message to remove
- * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
+ * 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 int remove_http_message(struct HTTP_Connection_out * con, struct HTTP_Message * msg)
+static size_t curl_get_header_function( void *ptr, size_t size, size_t nmemb, void *stream)
 {
 {
-  GNUNET_CONTAINER_DLL_remove(con->pending_msgs_head,con->pending_msgs_tail,msg);
-  GNUNET_free(msg);
-  return GNUNET_OK;
-}
+  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);
 
 
-static size_t header_function( void *ptr, size_t size, size_t nmemb, void *stream)
+  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;
   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 = NULL;
   if ((size * nmemb) < SIZE_MAX)
@@ -894,7 +1055,7 @@ static size_t header_function( void *ptr, size_t size, size_t nmemb, void *strea
         tmp[len-2]= '\0';
     }
 #if DEBUG_HTTP
         tmp[len-2]= '\0';
     }
 #if DEBUG_HTTP
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s'\n",tmp);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s' %u \n",tmp, http_result);
 #endif
   }
   if (NULL != tmp)
 #endif
   }
   if (NULL != tmp)
@@ -912,21 +1073,23 @@ static size_t header_function( void *ptr, size_t size, size_t nmemb, void *strea
  * @param ptr source pointer, passed to the libcurl handle
  * @return bytes written to stream
  */
  * @param ptr source pointer, passed to the libcurl handle
  * @return bytes written to stream
  */
-static size_t send_read_callback(void *stream, size_t size, size_t nmemb, void *ptr)
+static size_t curl_send_cb(void *stream, size_t size, size_t nmemb, void *ptr)
 {
 {
-  struct HTTP_Connection_out * con = ptr;
-  struct HTTP_Message * msg = con->pending_msgs_tail;
+  struct Session * ps = ptr;
+  struct HTTP_Message * msg = ps->pending_msgs_tail;
   size_t bytes_sent;
   size_t len;
 
   size_t bytes_sent;
   size_t len;
 
-  if (con->pending_msgs_tail == NULL)
+  if (ps->pending_msgs_tail == NULL)
   {
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection: %X: No Message to send, pausing connection\n",con);
-    con->send_paused = GNUNET_YES;
+#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;
   }
 
     return CURL_READFUNC_PAUSE;
   }
 
-  msg = con->pending_msgs_tail;
+  msg = ps->pending_msgs_tail;
   /* data to send */
   if (msg->pos < msg->size)
   {
   /* data to send */
   if (msg->pos < msg->size)
   {
@@ -954,11 +1117,13 @@ static size_t send_read_callback(void *stream, size_t size, size_t nmemb, void *
 
   if ( msg->pos == msg->size)
   {
 
   if ( msg->pos == msg->size)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection: %X: Message with %u bytes sent, removing message from queue \n",con, msg->pos);
+#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  */
     /* Calling transmit continuation  */
-    if (( NULL != con->pending_msgs_tail) && (NULL != con->pending_msgs_tail->transmit_cont))
-      msg->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&(con->session)->identity,GNUNET_OK);
-    remove_http_message(con, msg);
+    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;
 }
   }
   return bytes_sent;
 }
@@ -972,35 +1137,39 @@ static size_t send_read_callback(void *stream, size_t size, size_t nmemb, void *
 * @param ptr destination pointer, passed to the libcurl handle
 * @return bytes read from stream
 */
 * @param ptr destination pointer, passed to the libcurl handle
 * @return bytes read from stream
 */
-static size_t send_write_callback( void *stream, size_t size, size_t nmemb, void *ptr)
+static size_t curl_receive_cb( void *stream, size_t size, size_t nmemb, void *ptr)
 {
 {
-  char * data = NULL;
+  struct Session * ps = ptr;
+#if DEBUG_CONNECTIONS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes received\n",ps, size*nmemb);
+#endif
 
 
-  if ((size * nmemb) < SIZE_MAX)
-    data = GNUNET_malloc(size*nmemb +1);
-  if (data != NULL)
-  {
-    memcpy( data, stream, size*nmemb);
-    data[size*nmemb] = '\0';
-    free (data);
-  }
+  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));
+
+  // GNUNET_SERVER_mst_receive(ps->msgtok, ps, stream, size*nmemb, GNUNET_NO, GNUNET_NO);
   return (size * nmemb);
 
 }
 
 /**
  * Function setting up file descriptors and scheduling task to run
   return (size * nmemb);
 
 }
 
 /**
  * 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 );
 
  * @param ses session to send data to
  * @return bytes sent to peer
  */
 static size_t send_schedule(void *cls, struct Session* ses );
 
+
+
 /**
  * Function setting up curl handle and selecting message to send
 /**
  * Function setting up curl handle and selecting message to send
+ * @param cls plugin
  * @param ses session to send data to
  * @param ses session to send data to
+ * @param con connection
  * @return bytes sent to peer
  */
  * @return bytes sent to peer
  */
-static ssize_t send_initiate (void *cls, struct Session* ses , struct HTTP_Connection_out *con)
+static ssize_t send_check_connections (void *cls, struct Session *ps)
 {
   struct Plugin *plugin = cls;
   int bytes_sent = 0;
 {
   struct Plugin *plugin = cls;
   int bytes_sent = 0;
@@ -1008,62 +1177,122 @@ static ssize_t send_initiate (void *cls, struct Session* ses , struct HTTP_Conne
   struct HTTP_Message * msg;
   struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
 
   struct HTTP_Message * msg;
   struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
 
-  /* already connected, no need to initiate connection */
-  if ((con->connected == GNUNET_YES) && (con->curl_handle != NULL) && (con->send_paused == GNUNET_NO))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection: %X: active, enqueueing message\n",con);
-    return bytes_sent;
-  }
-
-  if ((con->connected == GNUNET_YES) && (con->curl_handle != NULL) && (con->send_paused == GNUNET_YES))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection: %X: paused, unpausing existing connection and enqueueing message\n",con);
-    curl_easy_pause(con->curl_handle,CURLPAUSE_CONT);
-    con->send_paused=GNUNET_NO;
-    return bytes_sent;
-  }
-
-  /* not connected, initiate connection */
   GNUNET_assert(cls !=NULL);
 
   GNUNET_assert(cls !=NULL);
 
-  if ( NULL == con->curl_handle)
-    con->curl_handle = curl_easy_init();
-  GNUNET_assert (con->curl_handle != NULL);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection: %X: not existing, creating new connection\n",con);
+  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
+      }
+    }
 
 
-  GNUNET_assert (NULL != con->pending_msgs_tail);
-  msg = con->pending_msgs_tail;
+    /* waiting for receive direction */
+    if (ps->recv_connected==GNUNET_NO)
+      return 0;
 
 
-#if DEBUG_CURL
-  curl_easy_setopt(con->curl_handle, CURLOPT_VERBOSE, 1L);
+    /* 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
 #endif
-  curl_easy_setopt(con->curl_handle, CURLOPT_URL, con->url);
-  curl_easy_setopt(con->curl_handle, CURLOPT_PUT, 1L);
-  curl_easy_setopt(con->curl_handle, CURLOPT_HEADERFUNCTION, &header_function);
-  curl_easy_setopt(con->curl_handle, CURLOPT_WRITEHEADER, con);
-  curl_easy_setopt(con->curl_handle, CURLOPT_READFUNCTION, send_read_callback);
-  curl_easy_setopt(con->curl_handle, CURLOPT_READDATA, con);
-  curl_easy_setopt(con->curl_handle, CURLOPT_WRITEFUNCTION, send_write_callback);
-  curl_easy_setopt(con->curl_handle, CURLOPT_READDATA, con);
-  curl_easy_setopt(con->curl_handle, CURLOPT_TIMEOUT, (long) timeout.value);
-  curl_easy_setopt(con->curl_handle, CURLOPT_PRIVATE, con);
-  curl_easy_setopt(con->curl_handle, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT_DBG);
-  curl_easy_setopt(con->curl_handle, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
-
-  mret = curl_multi_add_handle(plugin->multi_handle, con->curl_handle);
-  if (mret != CURLM_OK)
+        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_log (GNUNET_ERROR_TYPE_ERROR,
-                _("%s failed at %s:%d: `%s'\n"),
-                "curl_multi_add_handle", __FILE__, __LINE__,
-                curl_multi_strerror (mret));
-    return -1;
+    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;
   }
   }
-
-  con->connected = GNUNET_YES;
-
-  bytes_sent = send_schedule (plugin, ses);
-  return bytes_sent;
+  return 0;
 }
 
 static void send_execute (void *cls,
 }
 
 static void send_execute (void *cls,
@@ -1074,8 +1303,9 @@ static void send_execute (void *cls,
   int running;
   struct CURLMsg *msg;
   CURLMcode mret;
   int running;
   struct CURLMsg *msg;
   CURLMcode mret;
-  struct HTTP_Connection_out * con = NULL;
-  struct Session * cs = NULL;
+  struct Session *ps = NULL;
+  struct HTTP_PeerContext *pc = NULL;
+  struct HTTP_Message * cur_msg = NULL;
   long http_result;
 
   GNUNET_assert(cls !=NULL);
   long http_result;
 
   GNUNET_assert(cls !=NULL);
@@ -1093,15 +1323,14 @@ static void send_execute (void *cls,
             {
 
               msg = curl_multi_info_read (plugin->multi_handle, &running);
             {
 
               msg = curl_multi_info_read (plugin->multi_handle, &running);
-              GNUNET_break (msg != NULL);
               if (msg == NULL)
                 break;
               /* get session for affected curl handle */
               GNUNET_assert ( msg->easy_handle != NULL );
               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 *) &con);
-              GNUNET_assert ( con != NULL );
-              cs = con->session;
-              GNUNET_assert ( cs != 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)
                 {
 
@@ -1109,51 +1338,98 @@ static void send_execute (void *cls,
                   if ( (msg->data.result != CURLE_OK) &&
                        (msg->data.result != CURLE_GOT_NOTHING) )
                   {
                   if ( (msg->data.result != CURLE_OK) &&
                        (msg->data.result != CURLE_GOT_NOTHING) )
                   {
-                    GNUNET_log(GNUNET_ERROR_TYPE_INFO,
-                               _("%s failed for `%s' connection %X at %s:%d: `%s'\n"),
-                               "curl_multi_perform",
-                               GNUNET_i2s(&cs->identity),con,
-                               __FILE__,
-                               __LINE__,
-                               curl_easy_strerror (msg->data.result));
                     /* sending msg failed*/
                     /* sending msg failed*/
-                    con->connected = GNUNET_NO;
-                    curl_easy_cleanup(con->curl_handle);
-                    con->curl_handle=NULL;
-                    if (( NULL != con->pending_msgs_tail) && ( NULL != con->pending_msgs_tail->transmit_cont))
-                      con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&con->session->identity,GNUNET_SYSERR);
-
+                    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
                   {
-                    GNUNET_assert (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_result));
-                    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                                "Send to peer `%s' completed with code %u\n", GNUNET_i2s(&cs->identity), http_result );
-
-                    curl_easy_cleanup(con->curl_handle);
-                    con->connected = GNUNET_NO;
-                    con->curl_handle=NULL;
-
-                    /* Calling transmit continuation  */
-                    if (( NULL != con->pending_msgs_tail) && (NULL != con->pending_msgs_tail->transmit_cont))
+                    if (msg->easy_handle == ps->send_endpoint)
                     {
                     {
-                      /* HTTP 1xx : Last message before here was informational */
-                      if ((http_result >=100) && (http_result < 200))
-                        con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&cs->identity,GNUNET_OK);
-                      /* HTTP 2xx: successful operations */
-                      if ((http_result >=200) && (http_result < 300))
-                        con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&cs->identity,GNUNET_OK);
-                      /* HTTP 3xx..5xx: error */
-                      if ((http_result >=300) && (http_result < 600))
-                        con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&cs->identity,GNUNET_SYSERR);
+                      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)
+                    {
+#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 (con->pending_msgs_tail != NULL)
-                  {
-                    if (con->pending_msgs_tail->pos>0)
-                      remove_http_message(con, con->pending_msgs_tail);
-                    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message could not be removed from session `%s'\n", GNUNET_i2s(&cs->identity));
-                  }
+                  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;
@@ -1232,25 +1508,35 @@ static size_t send_schedule(void *cls, struct Session* ses )
 
 /**
  * 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 to 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
@@ -1271,22 +1557,128 @@ http_plugin_send (void *cls,
                   void *cont_cls)
 {
   struct Plugin *plugin = cls;
                   void *cont_cls)
 {
   struct Plugin *plugin = cls;
-  char *address;
-  char *url;
-  struct Session *cs;
   struct HTTP_Message *msg;
   struct HTTP_Message *msg;
-  struct HTTP_Connection_out *con;
-  //unsigned int ret;
+
+  struct HTTP_PeerContext * pc;
+  struct Session * ps = NULL;
+  struct Session * ps_tmp = NULL;
 
   GNUNET_assert(cls !=NULL);
 
   GNUNET_assert(cls !=NULL);
-  url = NULL;
-  address = NULL;
 
 
-  /* get session from hashmap */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to %s, %u\n", msgbuf_size, GNUNET_i2s(target),addrlen);
-  cs = session_get(plugin, target);
-  con = session_check_outbound_address(plugin, cs, addr, addrlen);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to peer `%s'\n",msgbuf_size,GNUNET_i2s(&cs->identity));
+  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)
+  {
+    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);
+  }
+
+  /* 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);
+
+  /* Search for existing session using the passed session */
+  if ((ps==NULL) && (force_address != GNUNET_YES))
+  {
+    ps_tmp = pc->head;
+    while (ps_tmp!=NULL)
+    {
+      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;
+    }
+  }
+
+  /* session not existing, address not forced -> looking for other session */
+  if ((ps==NULL) && (force_address != GNUNET_YES))
+  {
+    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));
+  }
+
+  /* session not existing, but address forced -> creating new session */
+  if ((ps==NULL) || ((ps==NULL) && (force_address == GNUNET_YES)))
+  {
+    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;
+    }
+  }
 
   /* create msg */
   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
 
   /* create msg */
   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
@@ -1297,20 +1689,9 @@ http_plugin_send (void *cls,
   msg->transmit_cont = cont;
   msg->transmit_cont_cls = cont_cls;
   memcpy (msg->buf,msgbuf, msgbuf_size);
   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);
 
 
-  /* must use this address */
-  if (force_address == GNUNET_YES)
-  {
-    /* enqueue in connection message queue */
-    GNUNET_CONTAINER_DLL_insert(con->pending_msgs_head,con->pending_msgs_tail,msg);
-  }
-  /* can use existing connection to send */
-  else
-  {
-    /* enqueue in connection message queue */
-    GNUNET_CONTAINER_DLL_insert(con->pending_msgs_head,con->pending_msgs_tail,msg);
-  }
-  return send_initiate (plugin, cs, con);
+  return send_check_connections (plugin, ps);
 }
 
 
 }
 
 
@@ -1327,26 +1708,50 @@ static void
 http_plugin_disconnect (void *cls,
                             const struct GNUNET_PeerIdentity *target)
 {
 http_plugin_disconnect (void *cls,
                             const struct GNUNET_PeerIdentity *target)
 {
+
   struct Plugin *plugin = cls;
   struct Plugin *plugin = cls;
-  struct HTTP_Connection_out *con;
-  struct Session *cs;
+  struct HTTP_PeerContext *pc = NULL;
+  struct Session *ps = NULL;
 
 
-  /* get session from hashmap */
-  cs = session_get(plugin, target);
-  con = cs->outbound_connections_head;
+  pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
+  if (pc==NULL)
+    return;
 
 
-  while (con!=NULL)
+  ps = pc->head;
+
+  while (ps!=NULL)
   {
   {
-    if (con->curl_handle!=NULL)
-      curl_easy_cleanup(con->curl_handle);
-    con->curl_handle=NULL;
-    con->connected = GNUNET_NO;
-    while (con->pending_msgs_head!=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(con, con->pending_msgs_head);
+      remove_http_message(ps, ps->pending_msgs_head);
     }
     }
-    con=con->next;
+    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));
 }
 
 
 }
 
 
@@ -1495,10 +1900,9 @@ http_plugin_address_to_string (void *cls,
   struct sockaddr_in6 a6;
   char * address;
   char * ret;
   struct sockaddr_in6 a6;
   char * address;
   char * ret;
-  unsigned int port;
+  uint16_t port;
   unsigned int res;
 
   unsigned int res;
 
-  GNUNET_assert(cls !=NULL);
   if (addrlen == sizeof (struct IPv6HttpAddress))
     {
       address = GNUNET_malloc (INET6_ADDRSTRLEN);
   if (addrlen == sizeof (struct IPv6HttpAddress))
     {
       address = GNUNET_malloc (INET6_ADDRSTRLEN);
@@ -1584,40 +1988,49 @@ process_interfaces (void *cls,
     }
   return GNUNET_OK;
 }
     }
   return GNUNET_OK;
 }
-int hashMapFreeIterator (void *cls, const GNUNET_HashCode *key, void *value)
+
+int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value)
 {
 {
-  struct Session * cs = value;
-  struct HTTP_Connection_out * con = cs->outbound_connections_head;
-  struct HTTP_Connection_out * tmp_con = cs->outbound_connections_head;
+  struct HTTP_PeerContext * pc = value;
+  struct Session * ps = pc->head;
+  struct Session * tmp = NULL;
   struct HTTP_Message * msg = NULL;
   struct HTTP_Message * msg = NULL;
-  struct HTTP_Message * tmp_msg = NULL;
+  struct HTTP_Message * msg_tmp = NULL;
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing session for peer `%s'\n",GNUNET_i2s(&cs->identity));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity));
 
 
-  /* freeing connections */
-  while (con!=NULL)
+  while (ps!=NULL)
   {
   {
-    GNUNET_free(con->url);
-    if (con->curl_handle!=NULL)
-      curl_easy_cleanup(con->curl_handle);
-    con->curl_handle = NULL;
-    msg = con->pending_msgs_head;
+    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)
     {
     while (msg!=NULL)
     {
-      tmp_msg=msg->next;
+      msg_tmp = msg->next;
       GNUNET_free(msg);
       GNUNET_free(msg);
-      msg = tmp_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);
     }
     }
-    tmp_con=con->next;
-    GNUNET_free(con);
-    con=tmp_con;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"All sessions freed \n");
 
 
-  GNUNET_free (cs);
+    GNUNET_free(ps);
+    ps=tmp;
+  }
+  GNUNET_free(pc);
   return GNUNET_YES;
 }
 
   return GNUNET_YES;
 }
 
+
 /**
  * Exit point from the plugin.
  */
 /**
  * Exit point from the plugin.
  */
@@ -1630,7 +2043,6 @@ libgnunet_plugin_transport_http_done (void *cls)
 
   GNUNET_assert(cls !=NULL);
 
 
   GNUNET_assert(cls !=NULL);
 
-
   if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
   {
     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
   if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
   {
     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
@@ -1660,12 +2072,11 @@ libgnunet_plugin_transport_http_done (void *cls)
     plugin->http_server_daemon_v6 = NULL;
   }
 
     plugin->http_server_daemon_v6 = NULL;
   }
 
-  /* free all sessions */
-  GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions,
-                                         &hashMapFreeIterator,
+  /* free all peer information */
+  GNUNET_CONTAINER_multihashmap_iterate (plugin->peers,
+                                         &remove_peer_context_Iterator,
                                          NULL);
                                          NULL);
-
-  GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions);
+  GNUNET_CONTAINER_multihashmap_destroy (plugin->peers);
 
   mret = curl_multi_cleanup(plugin->multi_handle);
   if ( CURLM_OK != mret)
 
   mret = curl_multi_cleanup(plugin->multi_handle);
   if ( CURLM_OK != mret)
@@ -1695,7 +2106,7 @@ libgnunet_plugin_transport_http_init (void *cls)
 
   plugin = GNUNET_malloc (sizeof (struct Plugin));
   plugin->env = env;
 
   plugin = GNUNET_malloc (sizeof (struct Plugin));
   plugin->env = env;
-  plugin->sessions = NULL;
+  plugin->peers = NULL;
 
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
 
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
@@ -1731,23 +2142,23 @@ libgnunet_plugin_transport_http_init (void *cls)
     {
     plugin->http_server_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
                                        port,
     {
     plugin->http_server_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
                                        port,
-                                       &acceptPolicyCallback,
-                                       plugin , &accessHandlerCallback, plugin,
+                                       &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_TIMEOUT, (gn_timeout.value / 1000),
                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
                                        MHD_OPTION_CONNECTION_TIMEOUT, (gn_timeout.value / 1000),
                                        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);
     plugin->http_server_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
                                        port,
                                        MHD_OPTION_END);
     plugin->http_server_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
                                        port,
-                                       &acceptPolicyCallback,
-                                       plugin , &accessHandlerCallback, plugin,
+                                       &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_TIMEOUT, (gn_timeout.value / 1000),
                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
                                        MHD_OPTION_CONNECTION_TIMEOUT, (gn_timeout.value / 1000),
                                        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);
     }
   if (plugin->http_server_daemon_v4 != NULL)
                                        MHD_OPTION_END);
     }
   if (plugin->http_server_daemon_v4 != NULL)
@@ -1780,7 +2191,7 @@ libgnunet_plugin_transport_http_init (void *cls)
     return NULL;
   }
 
     return NULL;
   }
 
-  plugin->sessions = GNUNET_CONTAINER_multihashmap_create (10);
+  plugin->peers = GNUNET_CONTAINER_multihashmap_create (10);
   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
 
   return api;
   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
 
   return api;