gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r16851 - gnunet/src/transport


From: gnunet
Subject: [GNUnet-SVN] r16851 - gnunet/src/transport
Date: Wed, 14 Sep 2011 18:46:38 +0200

Author: wachs
Date: 2011-09-14 18:46:38 +0200 (Wed, 14 Sep 2011)
New Revision: 16851

Added:
   gnunet/src/transport/plugin_transport_http.h
   gnunet/src/transport/plugin_transport_http_client.c
   gnunet/src/transport/plugin_transport_http_new.c
   gnunet/src/transport/plugin_transport_http_server.c
Log:
http plugin revisited


Added: gnunet/src/transport/plugin_transport_http.h
===================================================================
--- gnunet/src/transport/plugin_transport_http.h                                
(rev 0)
+++ gnunet/src/transport/plugin_transport_http.h        2011-09-14 16:46:38 UTC 
(rev 16851)
@@ -0,0 +1,245 @@
+/*
+     This file is part of GNUnet
+     (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff 
(and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http.h
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_constants.h"
+#include "gnunet_protocols.h"
+#include "gnunet_connection_lib.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 "gnunet_transport_plugin.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_nat_lib.h"
+#include "microhttpd.h"
+#include <curl/curl.h>
+
+
+#define DEBUG_HTTP GNUNET_YES
+#define VERBOSE_SERVER GNUNET_YES
+#define VERBOSE_CLIENT GNUNET_YES
+
+#if BUILD_HTTPS
+#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init
+#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done
+#else
+#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init
+#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done
+#endif
+
+
+#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 3)
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+  /**
+   * Our environment.
+   */
+  struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+  /**
+   * List of open sessions.
+   */
+  struct Session *head;
+
+  struct Session *tail;
+
+  /**
+   * NAT handle & address management
+   */
+  struct GNUNET_NAT_Handle *nat;
+
+  /**
+   * ipv4 DLL head
+   */
+  struct IPv4HttpAddressWrapper *ipv4_addr_head;
+
+  /**
+   * ipv4 DLL tail
+   */
+  struct IPv4HttpAddressWrapper *ipv4_addr_tail;
+
+  /**
+   * ipv6 DLL head
+   */
+  struct IPv6HttpAddressWrapper *ipv6_addr_head;
+
+  /**
+   * ipv6 DLL tail
+   */
+  struct IPv6HttpAddressWrapper *ipv6_addr_tail;
+
+
+  /* Plugin configuration */
+
+  char *name;
+
+  char *protocol;
+
+  int ipv4;
+
+  int ipv6;
+
+  uint16_t port;
+
+  int max_connections;
+
+  /*
+   * Server handles
+   */
+
+  struct MHD_Daemon *server_v4;
+
+  struct MHD_Daemon *server_v6;
+
+  char *crypto_init;
+  char *key;
+  char *cert;
+
+  /*
+   * Client handles
+   */
+
+  /**
+   * cURL Multihandle
+   */
+  CURLM *client_mh;
+
+};
+
+/**
+ * Session handle for connections.
+ */
+struct Session
+{
+
+  /**
+   * Stored in a linked list.
+   */
+  struct Session *next;
+
+  /**
+   * Stored in a linked list.
+   */
+  struct Session *prev;
+
+  /**
+   * Pointer to the global plugin struct.
+   */
+  struct Plugin *plugin;
+
+  /**
+   * The client (used to identify this connection)
+   */
+  /* void *client; */
+
+  /**
+   * Continuation function to call once the transmission buffer
+   * has again space available.  NULL if there is no
+   * continuation to call.
+   */
+  GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
+
+
+  void *addr;
+
+  size_t addrlen;
+
+  /**
+   * Closure for transmit_cont.
+   */
+  void *transmit_cont_cls;
+
+  /**
+   * To whom are we talking to (set to our identity
+   * if we are still waiting for the welcome message)
+   */
+  struct GNUNET_PeerIdentity target;
+
+  /**
+   * At what time did we reset last_received last?
+   */
+  //struct GNUNET_TIME_Absolute last_quota_update;
+
+  /**
+   * How many bytes have we received since the "last_quota_update"
+   * timestamp?
+   */
+  //uint64_t last_received;
+
+  /**
+   * Number of bytes per ms that this peer is allowed
+   * to send to us.
+   */
+  //uint32_t quota;
+
+
+  int inbound;
+
+  void *client_put;
+  void *client_get;
+
+
+};
+
+const char *
+http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen);
+
+int
+client_disconnect (struct Session *s);
+
+int
+client_connect (struct Session *s);
+
+int
+client_send (struct Session *s, const char *msgbuf, size_t msgbuf_size);
+
+int
+client_start (struct Plugin *plugin);
+
+void
+client_stop (struct Plugin *plugin);
+
+int
+server_disconnect (struct Session *s);
+
+int
+server_send (struct Session *s, const char *msgbuf, size_t msgbuf_size);
+
+int
+server_start (struct Plugin *plugin);
+
+void
+server_stop (struct Plugin *plugin);
+
+/* end of plugin_transport_http.h */

Added: gnunet/src/transport/plugin_transport_http_client.c
===================================================================
--- gnunet/src/transport/plugin_transport_http_client.c                         
(rev 0)
+++ gnunet/src/transport/plugin_transport_http_client.c 2011-09-14 16:46:38 UTC 
(rev 16851)
@@ -0,0 +1,236 @@
+/*
+     This file is part of GNUnet
+     (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff 
(and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http_client.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "plugin_transport_http.h"
+
+#if VERBOSE_CLIENT
+/**
+ * Function to log curl debug messages with GNUNET_log
+ * @param curl handle
+ * @param type curl_infotype
+ * @param data data
+ * @param size size
+ * @param cls  closure
+ * @return 0
+ */
+static int
+client_log (CURL * curl, curl_infotype type, char *data, size_t size, void 
*cls)
+{
+  if (type == CURLINFO_TEXT)
+  {
+    char text[size + 2];
+
+    memcpy (text, data, size);
+    if (text[size - 1] == '\n')
+      text[size] = '\0';
+    else
+    {
+      text[size] = '\n';
+      text[size + 1] = '\0';
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client: %X - %s", cls, text);
+  }
+  return 0;
+}
+#endif
+
+int
+client_disconnect (struct Session *s)
+{
+  int res = GNUNET_OK;
+  CURLMcode mret;
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, s->plugin->name,
+                   "Deleting outbound session peer `%s'\n",
+                   GNUNET_i2s (&s->target));
+#endif
+
+  mret = curl_multi_remove_handle (s->plugin->client_mh, s->client_put);
+  if (mret != CURLM_OK)
+  {
+    curl_easy_cleanup (s->client_put);
+    res = GNUNET_SYSERR;
+    GNUNET_break (0);
+  }
+  curl_easy_cleanup (s->client_put);
+
+  mret = curl_multi_remove_handle (s->plugin->client_mh, s->client_get);
+  if (mret != CURLM_OK)
+  {
+    curl_easy_cleanup (s->client_get);
+    res = GNUNET_SYSERR;
+    GNUNET_break (0);
+  }
+  curl_easy_cleanup (s->client_get);
+
+  return res;
+}
+
+int
+client_send (struct Session *s, const char *msgbuf, size_t msgbuf_size)
+{
+  return GNUNET_OK;
+}
+
+int
+client_connect (struct Session *s)
+{
+  int res = GNUNET_OK;
+  char *url;
+  CURLMcode mret;
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, s->plugin->name,
+                   "Initiating outbound session peer `%s'\n",
+                   GNUNET_i2s (&s->target));
+#endif
+
+  s->inbound = GNUNET_NO;
+
+  /* create url */
+  GNUNET_asprintf (&url, "%s://%s/", s->plugin->protocol,
+                   http_plugin_address_to_string (NULL, s->addr, s->addrlen));
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, s->plugin->name, "URL `%s'\n", 
url);
+#endif
+
+  /* create get connection */
+  s->client_get = curl_easy_init ();
+#if VERBOSE_CLIENT
+  curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L);
+  curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log);
+  curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get);
+#endif
+#if BUILD_HTTPS
+  curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+  curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0);
+  curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+  curl_easy_setopt (s->client_get, CURLOPT_URL, url);
+  //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, 
&curl_get_header_cb);
+  //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps);
+  //curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, curl_send_cb);
+  //curl_easy_setopt (s->client_get, CURLOPT_READDATA, ps);
+  //curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, curl_receive_cb);
+  //curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, ps);
+  curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT,
+                    (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+  //curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, ps);
+  curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT,
+                    (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
+  curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE,
+                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+#if CURL_TCP_NODELAY
+  curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1);
+#endif
+
+  /* create put connection */
+  s->client_put = curl_easy_init ();
+#if VERBOSE_CLIENT
+  curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L);
+  curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log);
+  curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put);
+#endif
+#if BUILD_HTTPS
+  curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+  curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0);
+  curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+  curl_easy_setopt (s->client_put, CURLOPT_URL, url);
+  curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L);
+  //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, 
&curl_put_header_cb);
+  //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps);
+  //curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, curl_send_cb);
+  //curl_easy_setopt (s->client_put, CURLOPT_READDATA, ps);
+  //curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, curl_receive_cb);
+  //curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, ps);
+  curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT,
+                    (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+  //curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, ps);
+  curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT,
+                    (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
+  curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE,
+                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+#if CURL_TCP_NODELAY
+  curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1);
+#endif
+
+  GNUNET_free (url);
+
+  mret = curl_multi_add_handle (s->plugin->client_mh, s->client_get);
+  if (mret != CURLM_OK)
+  {
+    curl_easy_cleanup (s->client_get);
+    res = GNUNET_SYSERR;
+    GNUNET_break (0);
+  }
+
+  mret = curl_multi_add_handle (s->plugin->client_mh, s->client_put);
+  if (mret != CURLM_OK)
+  {
+    curl_multi_remove_handle (s->plugin->client_mh, s->client_get);
+    curl_easy_cleanup (s->client_get);
+    curl_easy_cleanup (s->client_put);
+    res = GNUNET_SYSERR;
+    GNUNET_break (0);
+  }
+
+  /* Perform connect */
+
+  return res;
+}
+
+int
+client_start (struct Plugin *plugin)
+{
+  int res = GNUNET_OK;
+
+  curl_global_init (CURL_GLOBAL_ALL);
+  plugin->client_mh = curl_multi_init ();
+
+  if (NULL == plugin->client_mh)
+  {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                     _
+                     ("Could not initialize curl multi handle, failed to start 
%s plugin!\n"),
+                     plugin->name);
+    res = GNUNET_SYSERR;
+  }
+  return res;
+}
+
+void
+client_stop (struct Plugin *plugin)
+{
+  curl_multi_cleanup (plugin->client_mh);
+  curl_global_cleanup ();
+}
+
+
+
+/* end of plugin_transport_http_client.c */

Added: gnunet/src/transport/plugin_transport_http_new.c
===================================================================
--- gnunet/src/transport/plugin_transport_http_new.c                            
(rev 0)
+++ gnunet/src/transport/plugin_transport_http_new.c    2011-09-14 16:46:38 UTC 
(rev 16851)
@@ -0,0 +1,963 @@
+/*
+     This file is part of GNUnet
+     (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff 
(and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "plugin_transport_http.h"
+
+/**
+ * After how long do we expire an address that we
+ * learned from another peer if it is not reconfirmed
+ * by anyone?
+ */
+#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_HOURS, 6)
+
+/**
+ * Network format for IPv4 addresses.
+ */
+struct IPv4HttpAddress
+{
+  /**
+   * IPv4 address, in network byte order.
+   */
+  uint32_t ipv4_addr GNUNET_PACKED;
+
+  /**
+   * Port number, in network byte order.
+   */
+  uint16_t port GNUNET_PACKED;
+};
+
+/**
+ * Wrapper to manage IPv4 addresses
+ */
+struct IPv4HttpAddressWrapper
+{
+  /**
+   * Linked list next
+   */
+  struct IPv4HttpAddressWrapper *next;
+
+  /**
+   * Linked list previous
+   */
+  struct IPv4HttpAddressWrapper *prev;
+
+  struct IPv4HttpAddress *addr;
+};
+
+/**
+ * Network format for IPv6 addresses.
+ */
+struct IPv6HttpAddress
+{
+  /**
+   * IPv6 address.
+   */
+  struct in6_addr ipv6_addr GNUNET_PACKED;
+
+  /**
+   * Port number, in network byte order.
+   */
+  uint16_t port GNUNET_PACKED;
+
+};
+
+/**
+ * Wrapper for IPv4 addresses.
+ */
+struct IPv6HttpAddressWrapper
+{
+  /**
+   * Linked list next
+   */
+  struct IPv6HttpAddressWrapper *next;
+
+  /**
+   * Linked list previous
+   */
+  struct IPv6HttpAddressWrapper *prev;
+
+  struct IPv6HttpAddress *addr;
+};
+
+
+/**
+ * Context for address to string conversion.
+ */
+struct PrettyPrinterContext
+{
+  /**
+   * Function to call with the result.
+   */
+  GNUNET_TRANSPORT_AddressStringCallback asc;
+
+  /**
+   * Plugin
+   */
+  struct Plugin *plugin;
+
+  /**
+   * Clsoure for 'asc'.
+   */
+  void *asc_cls;
+
+  /**
+   * Port to add after the IP address.
+   */
+  uint16_t port;
+};
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin;
+
+
+
+/**
+ * Append our port and forward the result.
+ *
+ * @param cls the 'struct PrettyPrinterContext*'
+ * @param hostname hostname part of the address
+ */
+static void
+append_port (void *cls, const char *hostname)
+{
+  struct PrettyPrinterContext *ppc = cls;
+  char *ret;
+
+  if (hostname == NULL)
+  {
+    ppc->asc (ppc->asc_cls, NULL);
+    GNUNET_free (ppc);
+    return;
+  }
+  GNUNET_asprintf (&ret, "%s://%s:%d", ppc->plugin->protocol, hostname,
+                   ppc->plugin->port);
+  ppc->asc (ppc->asc_cls, ret);
+  GNUNET_free (ret);
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ *        the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+http_plugin_address_pretty_printer (void *cls, const char *type,
+                                    const void *addr, size_t addrlen,
+                                    int numeric,
+                                    struct GNUNET_TIME_Relative timeout,
+                                    GNUNET_TRANSPORT_AddressStringCallback asc,
+                                    void *asc_cls)
+{
+  GNUNET_assert (cls != NULL);
+  struct PrettyPrinterContext *ppc;
+  const void *sb;
+  size_t sbs;
+  struct sockaddr_in a4;
+  struct sockaddr_in6 a6;
+  const struct IPv4HttpAddress *t4;
+  const struct IPv6HttpAddress *t6;
+  uint16_t port;
+
+  if (addrlen == sizeof (struct IPv6HttpAddress))
+  {
+    t6 = addr;
+    memset (&a6, 0, sizeof (a6));
+    a6.sin6_family = AF_INET6;
+    a6.sin6_port = t6->port;
+    memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
+    port = ntohs (t6->port);
+    sb = &a6;
+    sbs = sizeof (a6);
+  }
+  else if (addrlen == sizeof (struct IPv4HttpAddress))
+  {
+    t4 = addr;
+    memset (&a4, 0, sizeof (a4));
+    a4.sin_family = AF_INET;
+    a4.sin_port = t4->port;
+    a4.sin_addr.s_addr = t4->ipv4_addr;
+    port = ntohs (t4->ipv4_addr);
+    sb = &a4;
+    sbs = sizeof (a4);
+  }
+  else
+  {
+    /* invalid address */
+    GNUNET_break_op (0);
+    asc (asc_cls, NULL);
+    return;
+  }
+  ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
+  ppc->asc = asc;
+  ppc->asc_cls = asc_cls;
+  ppc->port = port;
+  ppc->plugin = cls;
+  GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+}
+
+
+
+/**
+ * Another peer has suggested an address for this
+ * peer and transport plugin.  Check that this could be a valid
+ * address.  If so, consider adding it to the list
+ * of addresses.
+ *
+ * @param cls closure
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ *         and transport
+ */
+static int
+http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
+{
+  struct Plugin *plugin = cls;
+  struct IPv4HttpAddress *v4;
+  struct IPv6HttpAddress *v6;
+  struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head;
+  struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head;
+
+  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;
+    while (w_tv4 != NULL)
+    {
+      if (0 ==
+          memcmp (&w_tv4->addr->ipv4_addr, &v4->ipv4_addr, sizeof (uint32_t)))
+        break;
+      w_tv4 = w_tv4->next;
+    }
+    if (w_tv4 != NULL)
+      return GNUNET_OK;
+    else
+      return GNUNET_SYSERR;
+  }
+  if (addrlen == sizeof (struct IPv6HttpAddress))
+  {
+    v6 = (struct IPv6HttpAddress *) addr;
+    while (w_tv6 != NULL)
+    {
+      if (0 ==
+          memcmp (&w_tv6->addr->ipv6_addr, &v6->ipv6_addr,
+                  sizeof (struct in6_addr)))
+        break;
+      w_tv6 = w_tv6->next;
+    }
+    if (w_tv6 != NULL)
+      return GNUNET_OK;
+    else
+      return GNUNET_SYSERR;
+  }
+  return GNUNET_SYSERR;
+}
+
+/**
+ * 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
+ */
+const char *
+http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+  const struct IPv4HttpAddress *t4;
+  const struct IPv6HttpAddress *t6;
+  struct sockaddr_in a4;
+  struct sockaddr_in6 a6;
+  char *address;
+  static char rbuf[INET6_ADDRSTRLEN + 13];
+  uint16_t port;
+  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->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->port);
+  }
+  else
+  {
+    /* invalid address */
+    return NULL;
+  }
+
+  GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13));
+
+  res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s:%u", address, port);
+
+  GNUNET_free (address);
+  GNUNET_assert (res != 0);
+  return rbuf;
+}
+
+struct Session *
+lookup_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity 
*target,
+                const void *addr, size_t addrlen, int force_address)
+{
+  struct Session *s = NULL;
+  struct Session *t = NULL;
+  int e_peer;
+  int e_addr;
+
+  t = plugin->head;
+  if (t == NULL)
+    return NULL;
+  while (t->next != NULL)
+  {
+    e_peer = GNUNET_NO;
+    e_addr = GNUNET_NO;
+    if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity)))
+    {
+      e_peer = GNUNET_YES;
+      if (addrlen == t->addrlen)
+      {
+        if (0 == memcmp (addr, &t->addr, addrlen))
+          e_addr = GNUNET_YES;
+      }
+    }
+
+    if ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO))
+    {
+      s = t;
+      break;
+    }
+    else if ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) &&
+             (e_addr == GNUNET_YES))
+    {
+      s = t;
+      break;
+    }
+    else if ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR))
+    {
+      s = t;
+      break;
+    }
+    t = t->next;
+  }
+
+  return s;
+}
+
+void
+delete_session (struct Session *s)
+{
+  GNUNET_free (s->addr);
+  GNUNET_free (s);
+}
+
+struct Session *
+create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity 
*target,
+                const void *addr, size_t addrlen,
+                GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+  struct Session *s = NULL;
+
+  s = GNUNET_malloc (sizeof (struct Session));
+  memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity));
+  s->plugin = plugin;
+  s->addr = GNUNET_malloc (addrlen);
+  memcpy (s->addr, addr, addrlen);
+  s->addrlen = addrlen;
+  s->transmit_cont = cont;
+  s->transmit_cont_cls = cont_cls;
+  s->next = NULL;
+
+  return s;
+}
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin.   Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself.  This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param target who should receive this message
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ *                 ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ *                require plugins to discard the message after the timeout,
+ *                just advisory for the desired delay; most plugins will ignore
+ *                this as well)
+ * @param 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,
+ *                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
+ *        peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ *         -1 on hard errors (i.e. address invalid); 0 is a legal value
+ *         and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+http_plugin_send (void *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 Plugin *plugin = cls;
+
+  GNUNET_assert (plugin != NULL);
+
+  int res = GNUNET_SYSERR;
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                   "Sending %u bytes to peer `%s'\n", msgbuf_size,
+                   GNUNET_i2s (target));
+#endif
+
+  struct Session *s = NULL;
+
+  /* look for existing connection */
+  s = lookup_session (plugin, target, addr, addrlen, force_address);
+
+  /* create new connection */
+  if (s == NULL)
+  {
+#if DEBUG_HTTP
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                     "Initiiating new connection to peer `%s'\n",
+                     GNUNET_i2s (target));
+#endif
+    s = create_session (plugin, target, addr, addrlen, cont, cont_cls);
+    GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
+    // initiate new connection
+    client_connect (s);
+  }
+  else if (s->inbound == GNUNET_NO)
+    res = client_send (s, msgbuf, msgbuf_size);
+  else if (s->inbound == GNUNET_YES)
+    res = server_send (s, msgbuf, msgbuf_size);
+
+  return res;
+}
+
+
+/**
+ * Function that can be used to force the plugin to disconnect
+ * from the given peer and cancel all previous transmissions
+ * (and their continuationc).
+ *
+ * @param cls closure
+ * @param target peer from which to disconnect
+ */
+static void
+http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+  struct Plugin *plugin = cls;
+  struct Session *next = NULL;
+  struct Session *s = plugin->head;
+
+  while (s != NULL)
+  {
+    next = s->next;
+    if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity)))
+    {
+      if (s->inbound == GNUNET_NO)
+        GNUNET_assert (GNUNET_OK == client_disconnect (s));
+      else
+        GNUNET_assert (GNUNET_OK == server_disconnect (s));
+      GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
+      delete_session (s);
+    }
+    s = next;
+  }
+}
+
+/**
+ * Function called by the NAT subsystem suggesting another peer wants
+ * to connect to us via connection reversal.  Try to connect back to the
+ * given IP.
+ *
+ * @param cls closure
+ * @param addr address to try
+ * @param addrlen number of bytes in addr
+ */
+static void
+nat_connection_reversal (void *cls, const struct sockaddr *addr,
+                         socklen_t addrlen)
+{
+
+}
+
+static void
+nat_add_address (void *cls, int add_remove, const struct sockaddr *addr,
+                 socklen_t addrlen)
+{
+  struct Plugin *plugin = cls;
+  struct IPv4HttpAddress *t4 = NULL;
+  struct IPv4HttpAddressWrapper *w_t4 = NULL;
+  struct IPv6HttpAddress *t6 = NULL;
+  struct IPv6HttpAddressWrapper *w_t6 = NULL;
+  int af;
+
+  af = addr->sa_family;
+  switch (af)
+  {
+  case AF_INET:
+    w_t4 = plugin->ipv4_addr_head;
+    while (w_t4 != NULL)
+    {
+      int res = memcmp (&w_t4->addr->ipv4_addr,
+                        &((struct sockaddr_in *) addr)->sin_addr,
+                        sizeof (struct in_addr));
+
+      if (0 == res)
+        break;
+      w_t4 = w_t4->next;
+    }
+    if (w_t4 == NULL)
+    {
+      w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper));
+      t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddress));
+      memcpy (&t4->ipv4_addr, &((struct sockaddr_in *) addr)->sin_addr,
+              sizeof (struct in_addr));
+      t4->port = htons (plugin->port);
+
+      w_t4->addr = t4;
+
+      GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head,
+                                   plugin->ipv4_addr_tail, w_t4);
+    }
+    plugin->env->notify_address (plugin->env->cls, add_remove, w_t4->addr,
+                                 sizeof (struct IPv4HttpAddress));
+
+    break;
+  case AF_INET6:
+    w_t6 = plugin->ipv6_addr_head;
+    while (w_t6)
+    {
+      int res = memcmp (&w_t6->addr->ipv6_addr,
+                        &((struct sockaddr_in6 *) addr)->sin6_addr,
+                        sizeof (struct in6_addr));
+
+      if (0 == res)
+        break;
+      w_t6 = w_t6->next;
+    }
+    if (w_t6 == NULL)
+    {
+      w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper));
+      t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddress));
+
+      memcpy (&t6->ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
+              sizeof (struct in6_addr));
+      t6->port = htons (plugin->port);
+
+      w_t6->addr = t6;
+
+      GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head,
+                                   plugin->ipv6_addr_tail, w_t6);
+    }
+    plugin->env->notify_address (plugin->env->cls, add_remove, w_t6->addr,
+                                 sizeof (struct IPv6HttpAddress));
+    break;
+  default:
+    return;
+  }
+
+}
+
+static void
+nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
+                    socklen_t addrlen)
+{
+  struct Plugin *plugin = cls;
+  struct IPv4HttpAddressWrapper *w_t4 = NULL;
+  struct IPv6HttpAddressWrapper *w_t6 = NULL;
+  int af;
+
+  af = addr->sa_family;
+  switch (af)
+  {
+  case AF_INET:
+    w_t4 = plugin->ipv4_addr_head;
+    while (w_t4 != NULL)
+    {
+      int res = memcmp (&w_t4->addr->ipv4_addr,
+                        &((struct sockaddr_in *) addr)->sin_addr,
+                        sizeof (struct in_addr));
+
+      if (0 == res)
+        break;
+      w_t4 = w_t4->next;
+    }
+    if (w_t4 == NULL)
+      return;
+    plugin->env->notify_address (plugin->env->cls, add_remove, w_t4->addr,
+                                 sizeof (struct IPv4HttpAddress));
+
+    GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, 
plugin->ipv4_addr_tail,
+                                 w_t4);
+    GNUNET_free (w_t4->addr);
+    GNUNET_free (w_t4);
+    break;
+  case AF_INET6:
+    w_t6 = plugin->ipv6_addr_head;
+    while (w_t6 != NULL)
+    {
+      int res = memcmp (&w_t6->addr->ipv6_addr,
+                        &((struct sockaddr_in6 *) addr)->sin6_addr,
+                        sizeof (struct in6_addr));
+
+      if (0 == res)
+        break;
+      w_t6 = w_t6->next;
+    }
+    if (w_t6 == NULL)
+      return;
+    plugin->env->notify_address (plugin->env->cls, add_remove, w_t6->addr,
+                                 sizeof (struct IPv6HttpAddress));
+
+    GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, 
plugin->ipv6_addr_tail,
+                                 w_t6);
+    GNUNET_free (w_t6->addr);
+    GNUNET_free (w_t6);
+    break;
+  default:
+    return;
+  }
+
+}
+
+/**
+ * Our external IP address/port mapping has changed.
+ *
+ * @param cls closure, the 'struct LocalAddrList'
+ * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO 
to mean
+ *     the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of the address
+ */
+static void
+nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
+                       socklen_t addrlen)
+{
+  GNUNET_assert (cls != NULL);
+  struct Plugin *plugin = cls;
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   "NPMC called %s to address `%s'\n",
+                   (add_remove == GNUNET_NO) ? "remove" : "add",
+                   GNUNET_a2s (addr, addrlen));
+#endif
+  /* convert 'addr' to our internal format */
+  switch (add_remove)
+  {
+  case GNUNET_YES:
+    nat_add_address (cls, add_remove, addr, addrlen);
+    break;
+  case GNUNET_NO:
+    nat_remove_address (cls, add_remove, addr, addrlen);
+    break;
+  }
+}
+
+
+static void
+start_report_addresses (struct Plugin *plugin)
+{
+  int res = GNUNET_OK;
+  struct sockaddr **addrs;
+  socklen_t *addrlens;
+
+  res =
+      GNUNET_SERVICE_get_server_addresses (plugin->name, plugin->env->cfg,
+                                           &addrs, &addrlens);
+
+  if (res != GNUNET_SYSERR)
+  {
+    plugin->nat =
+        GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
+                             (unsigned int) res,
+                             (const struct sockaddr **) addrs, addrlens,
+                             &nat_port_map_callback, &nat_connection_reversal,
+                             plugin);
+    while (res > 0)
+    {
+      res--;
+      GNUNET_assert (addrs[res] != NULL);
+      GNUNET_free (addrs[res]);
+    }
+    GNUNET_free_non_null (addrs);
+    GNUNET_free_non_null (addrlens);
+  }
+  else
+  {
+    plugin->nat =
+        GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL,
+                             NULL, &nat_connection_reversal, plugin);
+  }
+}
+
+static void
+stop_report_addresses (struct Plugin *plugin)
+{
+  /* Stop NAT handle */
+  GNUNET_NAT_unregister (plugin->nat);
+
+  /* Clean up addresses */
+  struct IPv4HttpAddressWrapper *w_t4;
+  struct IPv6HttpAddressWrapper *w_t6;
+
+  while (plugin->ipv4_addr_head != NULL)
+  {
+    w_t4 = plugin->ipv4_addr_head;
+    GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, 
plugin->ipv4_addr_tail,
+                                 w_t4);
+    GNUNET_free (w_t4->addr);
+    GNUNET_free (w_t4);
+  }
+
+  while (plugin->ipv6_addr_head != NULL)
+  {
+    w_t6 = plugin->ipv6_addr_head;
+    GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, 
plugin->ipv6_addr_tail,
+                                 w_t6);
+    GNUNET_free (w_t6->addr);
+    GNUNET_free (w_t6);
+  }
+}
+
+static int
+configure_plugin (struct Plugin *plugin)
+{
+  int res = GNUNET_OK;
+
+  /* Use IPv4? */
+  if (GNUNET_CONFIGURATION_have_value
+      (plugin->env->cfg, plugin->name, "USE_IPv4"))
+  {
+    plugin->ipv4 =
+        GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
+                                              "USE_IPv4");
+  }
+  else
+    plugin->ipv4 = GNUNET_YES;
+
+  /* Use IPv6? */
+  if (GNUNET_CONFIGURATION_have_value
+      (plugin->env->cfg, plugin->name, "USE_IPv6"))
+  {
+    plugin->ipv6 =
+        GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
+                                              "USE_IPv6");
+  }
+  else
+    plugin->ipv6 = GNUNET_YES;
+
+  if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO))
+  {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                     _
+                     ("Neither IPv4 nor IPv6 are enabled! Fix in 
configuration\n"),
+                     plugin->name);
+    res = GNUNET_SYSERR;
+  }
+  /* Reading port number from config file */
+  unsigned long long port;
+
+  if ((GNUNET_OK !=
+       GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
+                                              "PORT", &port)) || (port > 
65535))
+  {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                     _("Port is required! Fix in configuration\n"),
+                     plugin->name);
+    res = GNUNET_SYSERR;
+  }
+  plugin->port = port;
+
+  return res;
+}
+
+/**
+ * Entry point for the plugin.
+ */
+void *
+LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
+{
+  struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+  struct GNUNET_TRANSPORT_PluginFunctions *api;
+  struct Plugin *plugin;
+  int res;
+
+  plugin = GNUNET_malloc (sizeof (struct Plugin));
+  plugin->env = env;
+  api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+  api->cls = plugin;
+  api->send = &http_plugin_send;
+  api->disconnect = &http_plugin_disconnect;
+  api->address_pretty_printer = &http_plugin_address_pretty_printer;
+  api->check_address = &http_plugin_address_suggested;
+  api->address_to_string = &http_plugin_address_to_string;
+
+#if BUILD_HTTPS
+  plugin->name = "transport-https";
+  plugin->protocol = "https";
+#else
+  plugin->name = "transport-http";
+  plugin->protocol = "http";
+#endif
+  /* Configure plugin from configuration */
+
+  res = configure_plugin (plugin);
+  if (res == GNUNET_SYSERR)
+  {
+    GNUNET_free (plugin);
+    GNUNET_free (api);
+    return NULL;
+  }
+
+  /* Start client */
+  res = client_start (plugin);
+  if (res == GNUNET_SYSERR)
+  {
+    GNUNET_free (plugin);
+    GNUNET_free (api);
+    return NULL;
+  }
+
+  /* Start server */
+  res = server_start (plugin);
+  if (res == GNUNET_SYSERR)
+  {
+    server_stop (plugin);
+    client_stop (plugin);
+
+    GNUNET_free (plugin);
+    GNUNET_free (api);
+    return NULL;
+  }
+
+  /* Report addresses to transport service */
+  start_report_addresses (plugin);
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   "Plugin `%s' loaded\n", plugin->name);
+#endif
+
+  return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ */
+void *
+LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
+{
+  struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+  struct Plugin *plugin = api->cls;
+  struct Session *s = NULL;
+
+  /* Stop reporting addresses to transport service */
+  stop_report_addresses (plugin);
+
+  /* cleaning up sessions */
+  s = plugin->head;
+  while (s != NULL)
+  {
+    struct Session *t = s->next;
+
+    if (s->inbound == GNUNET_NO)
+      GNUNET_assert (GNUNET_OK == client_disconnect (s));
+    else
+      GNUNET_assert (GNUNET_OK == server_disconnect (s));
+
+    GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
+    delete_session (s);
+    s = t;
+  }
+
+  /* Stop server */
+  server_stop (plugin);
+
+  /* Stop client */
+  client_stop (plugin);
+
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   "Plugin `%s' unloaded\n", plugin->name);
+#endif
+
+  GNUNET_free (plugin);
+  GNUNET_free (api);
+
+  return NULL;
+}
+
+/* end of plugin_transport_http.c */

Added: gnunet/src/transport/plugin_transport_http_server.c
===================================================================
--- gnunet/src/transport/plugin_transport_http_server.c                         
(rev 0)
+++ gnunet/src/transport/plugin_transport_http_server.c 2011-09-14 16:46:38 UTC 
(rev 16851)
@@ -0,0 +1,374 @@
+/*
+     This file is part of GNUnet
+     (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff 
(and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "plugin_transport_http.h"
+
+static void
+server_log (void *arg, const char *fmt, va_list ap)
+{
+  char text[1024];
+
+  vsnprintf (text, sizeof (text), fmt, ap);
+  va_end (ap);
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "server: %s\n", text);
+}
+
+/**
+ * Check if incoming connection is accepted.
+ * NOTE: Here every connection is accepted
+ * @param cls plugin as closure
+ * @param addr address of incoming connection
+ * @param addr_len address length of incoming connection
+ * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
+ *
+ */
+static int
+server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len)
+{
+  return 0;
+}
+
+
+/**
+ * Callback called by MHD when it needs data to send
+ * @param cls current session
+ * @param pos position in buffer
+ * @param buf the buffer to write data to
+ * @param max max number of bytes available in buffer
+ * @return bytes written to buffer
+ */
+#if 0
+static ssize_t
+server_send_cb (void *cls, uint64_t pos, char *buf, size_t max)
+{
+
+  return 0;
+}
+#endif
+
+
+#if BUILD_HTTPS
+static char *
+server_load_file (const char *file)
+{
+  struct GNUNET_DISK_FileHandle *gn_file;
+  struct stat fstat;
+  char *text = NULL;
+
+  if (0 != STAT (file, &fstat))
+    return NULL;
+  text = GNUNET_malloc (fstat.st_size + 1);
+  gn_file =
+      GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
+                             GNUNET_DISK_PERM_USER_READ);
+  if (gn_file == NULL)
+  {
+    GNUNET_free (text);
+    return NULL;
+  }
+  if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size))
+  {
+    GNUNET_free (text);
+    GNUNET_DISK_file_close (gn_file);
+    return NULL;
+  }
+  text[fstat.st_size] = '\0';
+  GNUNET_DISK_file_close (gn_file);
+  return text;
+}
+#endif
+
+
+#if BUILD_HTTPS
+
+static int
+server_load_certificate (struct Plugin *plugin)
+{
+  int res = GNUNET_OK;
+
+  char *key_file;
+  char *cert_file;
+
+  /* Get crypto init string from config
+   * If not present just use default values */
+  GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
+                                         "CRYPTO_INIT", &plugin->crypto_init);
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
+                                               "KEY_FILE", &key_file))
+  {
+    key_file = "https_key.key";
+  }
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
+                                               "CERT_FILE", &cert_file))
+  {
+    cert_file = "https_cert.crt";
+  }
+
+  /* read key & certificates from file */
+#if VERBOSE_SERVER
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Loading TLS certificate from key-file `%s' cert-file`%s'\n",
+              key_file, cert_file);
+#endif
+
+  plugin->key = server_load_file (key_file);
+  plugin->cert = server_load_file (cert_file);
+
+  if ((plugin->key == NULL) || (plugin->cert == NULL))
+  {
+    struct GNUNET_OS_Process *cert_creation;
+
+    GNUNET_free_non_null (plugin->key);
+    plugin->key = NULL;
+    GNUNET_free_non_null (plugin->cert);
+    plugin->cert = NULL;
+
+#if VERBOSE_SERVER
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "No usable TLS certificate found, creating certificate\n");
+#endif
+    errno = 0;
+    cert_creation =
+        GNUNET_OS_start_process (NULL, NULL,
+                                 "gnunet-transport-certificate-creation",
+                                 "gnunet-transport-certificate-creation",
+                                 key_file, cert_file, NULL);
+    if (cert_creation == NULL)
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                       _
+                       ("Could not create a new TLS certificate, program 
`gnunet-transport-certificate-creation' could not be started!\n"));
+      GNUNET_free (key_file);
+      GNUNET_free (cert_file);
+
+      GNUNET_free_non_null (plugin->key);
+      GNUNET_free_non_null (plugin->cert);
+      GNUNET_free_non_null (plugin->crypto_init);
+
+      return GNUNET_SYSERR;
+    }
+    GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
+    GNUNET_OS_process_close (cert_creation);
+
+    plugin->key = server_load_file (key_file);
+    plugin->cert = server_load_file (cert_file);
+  }
+
+  if ((plugin->key == NULL) || (plugin->cert == NULL))
+  {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+                     _
+                     ("No usable TLS certificate found and creating one 
failed!\n"),
+                     "transport-https");
+    GNUNET_free (key_file);
+    GNUNET_free (cert_file);
+
+    GNUNET_free_non_null (plugin->key);
+    GNUNET_free_non_null (plugin->cert);
+    GNUNET_free_non_null (plugin->crypto_init);
+
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (key_file);
+  GNUNET_free (cert_file);
+#if DEBUG_HTTP
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n");
+#endif
+
+  return res;
+}
+#endif
+
+
+/**
+ * Process GET or PUT request received via MHD.  For
+ * GET, queue response that will send back our pending
+ * messages.  For PUT, process incoming data and send
+ * to GNUnet core.  In either case, check if a session
+ * already exists and create a new one if not.
+ */
+static int
+server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
+                  const char *url, const char *method, const char *version,
+                  const char *upload_data, size_t * upload_data_size,
+                  void **httpSessionCache)
+{
+  return 0;
+}
+
+static void
+server_disconnect_cb (void *cls, struct MHD_Connection *connection,
+                      void **httpSessionCache)
+{
+}
+
+int
+server_disconnect (struct Session *s)
+{
+  return GNUNET_OK;
+}
+
+int
+server_send (struct Session *s, const char *msgbuf, size_t msgbuf_size)
+{
+  return GNUNET_OK;
+}
+
+int
+server_start (struct Plugin *plugin)
+{
+  int res = GNUNET_OK;
+
+#if BUILD_HTTPS
+  res = server_load_certificate (plugin);
+  if (res == GNUNET_SYSERR)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TABORT\n");
+    return res;
+  }
+#endif
+
+  plugin->server_v4 = NULL;
+  if (plugin->ipv4 == GNUNET_YES)
+  {
+    plugin->server_v4 = MHD_start_daemon (
+#if VERBOSE_SERVER
+                                           MHD_USE_DEBUG |
+#endif
+#if BUILD_HTTPS
+                                           MHD_USE_SSL |
+#endif
+                                           MHD_NO_FLAG, plugin->port,
+                                           &server_accept_cb, plugin,
+                                           &server_access_cb, plugin,
+                                           //MHD_OPTION_SOCK_ADDR,
+                                           //(struct sockaddr_in *)
+                                           //plugin->bind4_address,
+                                           MHD_OPTION_CONNECTION_LIMIT,
+                                           (unsigned int)
+                                           plugin->max_connections,
+#if BUILD_HTTPS
+                                           MHD_OPTION_HTTPS_PRIORITIES,
+                                           plugin->crypto_init,
+                                           MHD_OPTION_HTTPS_MEM_KEY,
+                                           plugin->key,
+                                           MHD_OPTION_HTTPS_MEM_CERT,
+                                           plugin->cert,
+#endif
+                                           MHD_OPTION_CONNECTION_TIMEOUT,
+                                           (unsigned int) 3,
+                                           MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+                                           (size_t) (2 *
+                                                     
GNUNET_SERVER_MAX_MESSAGE_SIZE),
+                                           MHD_OPTION_NOTIFY_COMPLETED,
+                                           &server_disconnect_cb, plugin,
+                                           MHD_OPTION_EXTERNAL_LOGGER,
+                                           server_log, NULL, MHD_OPTION_END);
+    if (plugin->server_v4 == NULL)
+      res = GNUNET_SYSERR;
+  }
+  plugin->server_v6 = NULL;
+  if (plugin->ipv6 == GNUNET_YES)
+  {
+    plugin->server_v6 = MHD_start_daemon (
+#if VERBOSE_SERVER
+                                           MHD_USE_DEBUG |
+#endif
+#if BUILD_HTTPS
+                                           MHD_USE_SSL |
+#endif
+                                           MHD_USE_IPv6, plugin->port,
+                                           &server_accept_cb, plugin,
+                                           &server_access_cb, plugin,
+                                           //MHD_OPTION_SOCK_ADDR,
+                                           //tmp,
+                                           MHD_OPTION_CONNECTION_LIMIT,
+                                           (unsigned int)
+                                           plugin->max_connections,
+#if BUILD_HTTPS
+                                           MHD_OPTION_HTTPS_PRIORITIES,
+                                           plugin->crypto_init,
+                                           MHD_OPTION_HTTPS_MEM_KEY,
+                                           plugin->key,
+                                           MHD_OPTION_HTTPS_MEM_CERT,
+                                           plugin->cert,
+#endif
+                                           MHD_OPTION_CONNECTION_TIMEOUT,
+                                           (unsigned int) 3,
+                                           MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+                                           (size_t) (2 *
+                                                     
GNUNET_SERVER_MAX_MESSAGE_SIZE),
+                                           MHD_OPTION_NOTIFY_COMPLETED,
+                                           &server_disconnect_cb, plugin,
+                                           MHD_OPTION_EXTERNAL_LOGGER,
+                                           server_log, NULL, MHD_OPTION_END);
+
+    if (plugin->server_v6 == NULL)
+      res = GNUNET_SYSERR;
+  }
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   "%s server component started on port %u\n", plugin->name,
+                   plugin->port);
+#endif
+  return res;
+}
+
+void
+server_stop (struct Plugin *plugin)
+{
+
+  if (plugin->server_v4 != NULL)
+  {
+    MHD_stop_daemon (plugin->server_v4);
+    plugin->server_v4 = NULL;
+  }
+  if (plugin->server_v6 != NULL)
+  {
+    MHD_stop_daemon (plugin->server_v6);
+    plugin->server_v6 = NULL;
+  }
+
+#if BUILD_HTTPS
+  GNUNET_free_non_null (plugin->crypto_init);
+  GNUNET_free_non_null (plugin->cert);
+  GNUNET_free_non_null (plugin->key);
+#endif
+
+#if DEBUG_HTTP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+                   "%s server component stopped\n", plugin->name);
+#endif
+}
+
+
+
+/* end of plugin_transport_http.c */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]