gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-twister] branch master updated: initial import of GN


From: gnunet
Subject: [GNUnet-SVN] [taler-twister] branch master updated: initial import of GNS proxy, minus Socks5 and TLS support
Date: Sat, 20 Jan 2018 12:24:16 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository twister.

The following commit(s) were added to refs/heads/master by this push:
     new 1234fa2  initial import of GNS proxy, minus Socks5 and TLS support
1234fa2 is described below

commit 1234fa22095d521c88cf5f8bc4f4abdb09366732
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Jan 20 12:24:08 2018 +0100

    initial import of GNS proxy, minus Socks5 and TLS support
---
 src/twister/taler-twister.c | 1512 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1512 insertions(+)

diff --git a/src/twister/taler-twister.c b/src/twister/taler-twister.c
new file mode 100644
index 0000000..bfbe894
--- /dev/null
+++ b/src/twister/taler-twister.c
@@ -0,0 +1,1512 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2012-2014 GNUnet e.V.
+     Copyright (C) 2018 Taler Systems SA
+
+     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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @author Martin Schanzenbach
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ * @file src/twister/taler-twister.c
+ * @brief HTTP proxy that acts as a man in the middle making changes to
+ *        requests or responses
+ */
+#include "platform.h"
+#include <microhttpd.h>
+#if HAVE_CURL_CURL_H
+#include <curl/curl.h>
+#elif HAVE_GNURL_CURL_H
+#include <gnurl/curl.h>
+#endif
+#include <gnunet/gnunet_util_lib.h>
+
+
+/**
+ * Default Socks5 listen port.
+ */
+#define GNUNET_GNS_PROXY_PORT 7777
+
+/**
+ * Maximum supported length for a URI.
+ * Should die. @deprecated
+ */
+#define MAX_HTTP_URI_LENGTH 2048
+
+/**
+ * Size of the buffer for the data upload / download.  Must be
+ * enough for curl, thus CURL_MAX_WRITE_SIZE is needed here (16k).
+ */
+#define IO_BUFFERSIZE CURL_MAX_WRITE_SIZE
+
+/**
+ * Size of the read/write buffers for Socks.   Uses
+ * 256 bytes for the hostname (at most), plus a few
+ * bytes overhead for the messages.
+ */
+#define SOCKS_BUFFERSIZE (256 + 32)
+
+/**
+ * Port for plaintext HTTP.
+ */
+#define HTTP_PORT 80
+
+/**
+ * After how long do we clean up unused MHD SSL/TLS instances?
+ */
+#define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MINUTES, 5)
+
+/**
+ * After how long do we clean up Socks5 handles that failed to show any 
activity
+ * with their respective MHD instance?
+ */
+#define HTTP_HANDSHAKE_TIMEOUT GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 15)
+
+
+/**
+ * Log curl error.
+ *
+ * @param level log level
+ * @param fun name of curl_easy-function that gave the error
+ * @param rc return code from curl
+ */
+#define LOG_CURL_EASY(level,fun,rc) GNUNET_log(level, _("%s failed at %s:%d: 
`%s'\n"), fun, __FILE__, __LINE__, curl_easy_strerror (rc))
+
+
+/* *********************** Datastructures for HTTP handling ****************** 
*/
+
+
+/**
+ * A header list
+ */
+struct HttpResponseHeader
+{
+  /**
+   * DLL
+   */
+  struct HttpResponseHeader *next;
+
+  /**
+   * DLL
+   */
+  struct HttpResponseHeader *prev;
+
+  /**
+   * Header type
+   */
+  char *type;
+
+  /**
+   * Header value
+   */
+  char *value;
+};
+
+
+/**
+ * A structure for socks requests
+ */
+struct Socks5Request
+{
+
+  /**
+   * DLL.
+   */
+  struct Socks5Request *next;
+
+  /**
+   * DLL.
+   */
+  struct Socks5Request *prev;
+
+  /**
+   * Client socket read task
+   */
+  struct GNUNET_SCHEDULER_Task * rtask;
+
+  /**
+   * Client socket write task
+   */
+  struct GNUNET_SCHEDULER_Task * wtask;
+
+  /**
+   * Read buffer
+   */
+  char rbuf[SOCKS_BUFFERSIZE];
+
+  /**
+   * Write buffer
+   */
+  char wbuf[SOCKS_BUFFERSIZE];
+
+  /**
+   * Buffer we use for moving data between MHD and curl (in both directions).
+   */
+  char io_buf[IO_BUFFERSIZE];
+
+  /**
+   * MHD response object for this request.
+   */
+  struct MHD_Response *response;
+
+  /**
+   * The URL to fetch
+   */
+  char *url;
+
+  /**
+   * Handle to cURL
+   */
+  CURL *curl;
+
+  /**
+   * HTTP request headers for the curl request.
+   */
+  struct curl_slist *headers;
+
+  /**
+   * DNS->IP mappings resolved through GNS
+   */
+  struct curl_slist *hosts;
+
+  /**
+   * HTTP response code to give to MHD for the response.
+   */
+  unsigned int response_code;
+
+  /**
+   * Number of bytes already in read buffer
+   */
+  size_t rbuf_len;
+
+  /**
+   * Number of bytes already in write buffer
+   */
+  size_t wbuf_len;
+
+  /**
+   * Number of bytes already in the IO buffer.
+   */
+  size_t io_len;
+
+  /**
+   * Once known, what's the target address for the connection?
+   */
+  struct sockaddr_storage destination_address;
+
+  /**
+   * Headers from response
+   */
+  struct HttpResponseHeader *header_head;
+
+  /**
+   * Headers from response
+   */
+  struct HttpResponseHeader *header_tail;
+
+};
+
+
+
+/* *********************** Globals **************************** */
+
+
+/**
+ * The port the proxy is running on (default 7777)
+ */
+static unsigned long long port = GNUNET_GNS_PROXY_PORT;
+
+/**
+ * The cURL download task (curl multi API).
+ */
+static struct GNUNET_SCHEDULER_Task * curl_download_task;
+
+/**
+ * The cURL multi handle
+ */
+static CURLM *curl_multi;
+
+/**
+ * The daemon handle
+ */
+static struct MHD_Daemon *daemon;
+
+/**
+ * The task ID
+ */
+static struct GNUNET_SCHEDULER_Task *httpd_task;
+
+/**
+ * DLL of active socks requests.
+ */
+static struct Socks5Request *s5r_head;
+
+/**
+ * DLL of active socks requests.
+ */
+static struct Socks5Request *s5r_tail;
+
+/**
+ * Response we return on cURL failures.
+ */
+static struct MHD_Response *curl_failure_response;
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/* ************************* Global helpers ********************* */
+
+
+/**
+ * Run MHD now, we have extra data ready for the callback.
+ *
+ * @param hd the daemon to run now.
+ */
+static void
+run_mhd_now (struct MhdHttpList *hd);
+
+
+/* ************************* HTTP handling with cURL *********************** */
+
+static void
+curl_download_prepare ();
+
+/**
+ * Callback for MHD response generation.  This function is called from
+ * MHD whenever MHD expects to get data back.  Copies data from the
+ * io_buf, if available.
+ *
+ * @param cls closure with our `struct Socks5Request`
+ * @param pos in buffer
+ * @param buf where to copy data
+ * @param max available space in @a buf
+ * @return number of bytes written to @a buf
+ */
+static ssize_t
+mhd_content_cb (void *cls,
+                uint64_t pos,
+                char* buf,
+                size_t max)
+{
+  struct Socks5Request *s5r = cls;
+  size_t bytes_to_copy;
+
+  if ( (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
+       (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) )
+  {
+    /* we're still not done with the upload, do not yet
+       start the download, the IO buffer is still full
+       with upload data. */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Pausing MHD download, not yet ready for download\n");
+    return 0; /* not yet ready for data download */
+  }
+  bytes_to_copy = GNUNET_MIN (max,
+                             s5r->io_len);
+  if ( (0 == bytes_to_copy) &&
+       (SOCKS5_SOCKET_DOWNLOAD_DONE != s5r->state) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Pausing MHD download, no data available\n");
+    if (NULL != s5r->curl)
+    {
+      curl_easy_pause (s5r->curl, CURLPAUSE_CONT);
+      curl_download_prepare ();
+    }
+    return 0; /* more data later */
+  }
+  if ( (0 == bytes_to_copy) &&
+       (SOCKS5_SOCKET_DOWNLOAD_DONE == s5r->state) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Completed MHD download\n");
+    return MHD_CONTENT_READER_END_OF_STREAM;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Writing %lu/%lu bytes\n", bytes_to_copy, s5r->io_len);
+  GNUNET_memcpy (buf, s5r->io_buf, bytes_to_copy);
+  memmove (s5r->io_buf,
+          &s5r->io_buf[bytes_to_copy],
+          s5r->io_len - bytes_to_copy);
+  s5r->io_len -= bytes_to_copy;
+  if (NULL != s5r->curl)
+    curl_easy_pause (s5r->curl, CURLPAUSE_CONT);
+  return bytes_to_copy;
+}
+
+
+/**
+ * We're getting an HTTP response header from cURL.  Convert it to the
+ * MHD response headers.  Mostly copies the headers, but makes special
+ * adjustments based on control requests.
+ *
+ * @param buffer curl buffer with a single line of header data; not 
0-terminated!
+ * @param size curl blocksize
+ * @param nmemb curl blocknumber
+ * @param cls our `struct Socks5Request *`
+ * @return size of processed bytes
+ */
+static size_t
+curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
+{
+  struct Socks5Request *s5r = cls;
+  struct HttpResponseHeader *header;
+  size_t bytes = size * nmemb;
+  char *ndup;
+  const char *hdr_type;
+  const char *cookie_domain;
+  char *hdr_val;
+  char *new_cookie_hdr;
+  char *new_location;
+  size_t offset;
+  size_t delta_cdomain;
+  int domain_matched;
+  char *tok;
+
+  /* first, check SSL certificate */
+  if ((GNUNET_YES != s5r->ssl_checked) &&
+      (HTTPS_PORT == s5r->port))
+  {
+      if (GNUNET_OK != check_ssl_certificate (s5r))
+        return 0;
+  }
+
+  ndup = GNUNET_strndup (buffer, bytes);
+  hdr_type = strtok (ndup, ":");
+  if (NULL == hdr_type)
+  {
+    GNUNET_free (ndup);
+    return bytes;
+  }
+  hdr_val = strtok (NULL, "");
+  if (NULL == hdr_val)
+  {
+    GNUNET_free (ndup);
+    return bytes;
+  }
+  if (' ' == *hdr_val)
+    hdr_val++;
+
+  /* custom logic for certain header types */
+#if 0
+  new_cookie_hdr = NULL;
+  if ( (NULL != s5r->leho) &&
+       (0 == strcasecmp (hdr_type,
+                         MHD_HTTP_HEADER_SET_COOKIE)) )
+
+  {
+    new_cookie_hdr = GNUNET_malloc (strlen (hdr_val) +
+                                    strlen (s5r->domain) + 1);
+    offset = 0;
+    domain_matched = GNUNET_NO; /* make sure we match domain at most once */
+    for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";"))
+    {
+      if ( (0 == strncasecmp (tok, " domain", strlen (" domain"))) &&
+           (GNUNET_NO == domain_matched) )
+      {
+        domain_matched = GNUNET_YES;
+        cookie_domain = tok + strlen (" domain") + 1;
+        if (strlen (cookie_domain) < strlen (s5r->leho))
+        {
+          delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain);
+          if (0 == strcasecmp (cookie_domain, s5r->leho + delta_cdomain))
+          {
+            offset += sprintf (new_cookie_hdr + offset,
+                               " domain=%s;",
+                               s5r->domain);
+            continue;
+          }
+        }
+        else if (0 == strcmp (cookie_domain, s5r->leho))
+        {
+          offset += sprintf (new_cookie_hdr + offset,
+                             " domain=%s;",
+                             s5r->domain);
+          continue;
+        }
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    _("Cookie domain `%s' supplied by server is invalid\n"),
+                    tok);
+      }
+      GNUNET_memcpy (new_cookie_hdr + offset, tok, strlen (tok));
+      offset += strlen (tok);
+      new_cookie_hdr[offset++] = ';';
+    }
+    hdr_val = new_cookie_hdr;
+  }
+
+  new_location = NULL;
+  if (0 == strcasecmp (MHD_HTTP_HEADER_LOCATION, hdr_type))
+  {
+    char *leho_host;
+
+    GNUNET_asprintf (&leho_host,
+                     (HTTPS_PORT != s5r->port)
+                     ? "http://%s";
+                     : "https://%s";,
+                     s5r->leho);
+    if (0 == strncmp (leho_host,
+                      hdr_val,
+                      strlen (leho_host)))
+    {
+      GNUNET_asprintf (&new_location,
+                       "%s%s%s",
+                       (HTTPS_PORT != s5r->port)
+                       ? "http://";
+                       : "https://";,
+                       s5r->domain,
+                       hdr_val + strlen (leho_host));
+      hdr_val = new_location;
+    }
+    GNUNET_free (leho_host);
+  }
+#endif
+  /* MHD does not allow certain characters in values, remove those */
+  if (NULL != (tok = strchr (hdr_val, '\n')))
+    *tok = '\0';
+  if (NULL != (tok = strchr (hdr_val, '\r')))
+    *tok = '\0';
+  if (NULL != (tok = strchr (hdr_val, '\t')))
+    *tok = '\0';
+  if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Adding header %s: %s to MHD response\n",
+                hdr_type,
+                hdr_val);
+    header = GNUNET_new (struct HttpResponseHeader);
+    header->type = GNUNET_strndup (hdr_type, strlen (hdr_type));
+    header->value = GNUNET_strndup (hdr_val, strlen (hdr_val));
+    GNUNET_CONTAINER_DLL_insert (s5r->header_head,
+                                 s5r->header_tail,
+                                 header);
+  }
+  GNUNET_free (ndup);
+  GNUNET_free_non_null (new_cookie_hdr);
+  GNUNET_free_non_null (new_location);
+  return bytes;
+}
+
+
+static int
+create_mhd_response_from_s5r (struct Socks5Request *s5r)
+{
+  long resp_code;
+  double content_length;
+  struct HttpResponseHeader *header;
+
+  if (NULL != s5r->response)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Response already set!\n");
+    return GNUNET_SYSERR;
+  }
+
+  GNUNET_break (CURLE_OK ==
+                curl_easy_getinfo (s5r->curl,
+                                   CURLINFO_RESPONSE_CODE,
+                                   &resp_code));
+  GNUNET_break (CURLE_OK ==
+                curl_easy_getinfo (s5r->curl,
+                                   CURLINFO_CONTENT_LENGTH_DOWNLOAD,
+                                   &content_length));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Creating MHD response with code %d and size %d\n",
+              (int) resp_code, (int) content_length);
+  s5r->response_code = resp_code;
+  s5r->response = MHD_create_response_from_callback ((-1 == content_length) ? 
MHD_SIZE_UNKNOWN : content_length,
+                                                     IO_BUFFERSIZE,
+                                                     &mhd_content_cb,
+                                                     s5r,
+                                                     NULL);
+  for (header = s5r->header_head; NULL != header; header = header->next)
+  {
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (s5r->response,
+                                           header->type,
+                                           header->value));
+
+  }
+  if (NULL != s5r->leho)
+  {
+    char *cors_hdr;
+
+    GNUNET_asprintf (&cors_hdr,
+                     (HTTPS_PORT == s5r->port)
+                     ? "https://%s";
+                     : "http://%s";,
+                     s5r->leho);
+
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (s5r->response,
+                                           
MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
+                                           cors_hdr));
+    GNUNET_free (cors_hdr);
+  }
+  /* force connection to be closed after each request, as we
+     do not support HTTP pipelining (yet, FIXME!) */
+  /*GNUNET_break (MHD_YES ==
+    MHD_add_response_header (s5r->response,
+    MHD_HTTP_HEADER_CONNECTION,
+    "close"));*/
+  return GNUNET_OK;
+}
+
+/**
+ * Handle response payload data from cURL.  Copies it into our `io_buf` to make
+ * it available to MHD.
+ *
+ * @param ptr pointer to the data
+ * @param size number of blocks of data
+ * @param nmemb blocksize
+ * @param ctx our `struct Socks5Request *`
+ * @return number of bytes handled
+ */
+static size_t
+curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx)
+{
+  struct Socks5Request *s5r = ctx;
+  size_t total = size * nmemb;
+
+  if (NULL == s5r->response)
+    GNUNET_assert (GNUNET_OK == create_mhd_response_from_s5r (s5r));
+
+  if ( (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
+       (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) )
+  {
+    /* we're still not done with the upload, do not yet
+       start the download, the IO buffer is still full
+       with upload data. */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Pausing CURL download, waiting for UPLOAD to finish\n");
+    return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
+  }
+  if (sizeof (s5r->io_buf) - s5r->io_len < total)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Pausing CURL download, not enough space %lu %lu %lu\n", 
sizeof (s5r->io_buf),
+                s5r->io_len, total);
+    return CURL_WRITEFUNC_PAUSE; /* not enough space */
+  }
+  GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
+                 ptr,
+                 total);
+  s5r->io_len += total;
+  if (s5r->io_len == total)
+    run_mhd_now (s5r->hd);
+  return total;
+}
+
+
+/**
+ * cURL callback for uploaded (PUT/POST) data.  Copies it into our `io_buf`
+ * to make it available to MHD.
+ *
+ * @param buf where to write the data
+ * @param size number of bytes per member
+ * @param nmemb number of members available in @a buf
+ * @param cls our `struct Socks5Request` that generated the data
+ * @return number of bytes copied to @a buf
+ */
+static size_t
+curl_upload_cb (void *buf, size_t size, size_t nmemb, void *cls)
+{
+  struct Socks5Request *s5r = cls;
+  size_t len = size * nmemb;
+  size_t to_copy;
+
+  if ( (0 == s5r->io_len) &&
+       (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Pausing CURL UPLOAD, need more data\n");
+    return CURL_READFUNC_PAUSE;
+  }
+  if ( (0 == s5r->io_len) &&
+       (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) )
+  {
+    s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Completed CURL UPLOAD\n");
+    return 0; /* upload finished, can now download */
+  }
+  if ( (SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
+       (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state) )
+  {
+    GNUNET_break (0);
+    return CURL_READFUNC_ABORT;
+  }
+  to_copy = GNUNET_MIN (s5r->io_len,
+                        len);
+  GNUNET_memcpy (buf, s5r->io_buf, to_copy);
+  memmove (s5r->io_buf,
+           &s5r->io_buf[to_copy],
+           s5r->io_len - to_copy);
+  s5r->io_len -= to_copy;
+  if (s5r->io_len + to_copy == sizeof (s5r->io_buf))
+    run_mhd_now (s5r->hd); /* got more space for upload now */
+  return to_copy;
+}
+
+
+/* ************************** main loop of cURL interaction ****************** 
*/
+
+
+/**
+ * Task that is run when we are ready to receive more data
+ * from curl
+ *
+ * @param cls closure
+ */
+static void
+curl_task_download (void *cls);
+
+
+/**
+ * Ask cURL for the select() sets and schedule cURL operations.
+ */
+static void
+curl_download_prepare ()
+{
+  CURLMcode mret;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  int max;
+  struct GNUNET_NETWORK_FDSet *grs;
+  struct GNUNET_NETWORK_FDSet *gws;
+  long to;
+  struct GNUNET_TIME_Relative rtime;
+
+  if (NULL != curl_download_task)
+  {
+    GNUNET_SCHEDULER_cancel (curl_download_task);
+    curl_download_task = NULL;
+  }
+  max = -1;
+  FD_ZERO (&rs);
+  FD_ZERO (&ws);
+  FD_ZERO (&es);
+  if (CURLM_OK != (mret = curl_multi_fdset (curl_multi, &rs, &ws, &es, &max)))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "%s failed at %s:%d: `%s'\n",
+                "curl_multi_fdset", __FILE__, __LINE__,
+                curl_multi_strerror (mret));
+    return;
+  }
+  to = -1;
+  GNUNET_break (CURLM_OK == curl_multi_timeout (curl_multi, &to));
+  if (-1 == to)
+    rtime = GNUNET_TIME_UNIT_FOREVER_REL;
+  else
+    rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
+  if (-1 != max)
+  {
+    grs = GNUNET_NETWORK_fdset_create ();
+    gws = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
+    GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
+    curl_download_task = GNUNET_SCHEDULER_add_select 
(GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                                      rtime,
+                                                      grs, gws,
+                                                      &curl_task_download, 
curl_multi);
+    GNUNET_NETWORK_fdset_destroy (gws);
+    GNUNET_NETWORK_fdset_destroy (grs);
+  }
+  else
+  {
+    curl_download_task = GNUNET_SCHEDULER_add_delayed (rtime,
+                                                       &curl_task_download,
+                                                       curl_multi);
+  }
+}
+
+
+/**
+ * Task that is run when we are ready to receive more data from curl.
+ *
+ * @param cls closure, NULL
+ */
+static void
+curl_task_download (void *cls)
+{
+  int running;
+  int msgnum;
+  struct CURLMsg *msg;
+  CURLMcode mret;
+  struct Socks5Request *s5r;
+
+  curl_download_task = NULL;
+  do
+  {
+    running = 0;
+    mret = curl_multi_perform (curl_multi, &running);
+    while (NULL != (msg = curl_multi_info_read (curl_multi, &msgnum)))
+    {
+      GNUNET_break (CURLE_OK ==
+                    curl_easy_getinfo (msg->easy_handle,
+                                       CURLINFO_PRIVATE,
+                                       (char **) &s5r ));
+      if (NULL == s5r)
+      {
+        GNUNET_break (0);
+        continue;
+      }
+      switch (msg->msg)
+      {
+        case CURLMSG_NONE:
+          /* documentation says this is not used */
+          GNUNET_break (0);
+          break;
+        case CURLMSG_DONE:
+          switch (msg->data.result)
+          {
+            case CURLE_OK:
+            case CURLE_GOT_NOTHING:
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                          "CURL download completed.\n");
+              if (NULL == s5r->response)
+                GNUNET_assert (GNUNET_OK == create_mhd_response_from_s5r 
(s5r));
+              s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
+              run_mhd_now (s5r->hd);
+              break;
+            default:
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                          "Download curl failed: %s\n",
+                          curl_easy_strerror (msg->data.result));
+              /* FIXME: indicate error somehow? close MHD connection badly as 
well? */
+              s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
+              run_mhd_now (s5r->hd);
+              break;
+          }
+          if (NULL == s5r->response)
+            s5r->response = curl_failure_response;
+          break;
+        case CURLMSG_LAST:
+          /* documentation says this is not used */
+          GNUNET_break (0);
+          break;
+        default:
+          /* unexpected status code */
+          GNUNET_break (0);
+          break;
+      }
+    };
+  } while (mret == CURLM_CALL_MULTI_PERFORM);
+  if (CURLM_OK != mret)
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "%s failed at %s:%d: `%s'\n",
+                "curl_multi_perform", __FILE__, __LINE__,
+                curl_multi_strerror (mret));
+  if (0 == running)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Suspending cURL multi loop, no more events pending\n");
+    return; /* nothing more in progress */
+  }
+  curl_download_prepare ();
+}
+
+
+/* ********************************* MHD response generation 
******************* */
+
+
+/**
+ * Read HTTP request header field from the request.  Copies the fields
+ * over to the 'headers' that will be given to curl.  However, 'Host'
+ * is substituted with the LEHO if present.  We also change the
+ * 'Connection' header value to "close" as the proxy does not support
+ * pipelining.
+ *
+ * @param cls our `struct Socks5Request`
+ * @param kind value kind
+ * @param key field key
+ * @param value field value
+ * @return MHD_YES to continue to iterate
+ */
+static int
+con_val_iter (void *cls,
+              enum MHD_ValueKind kind,
+              const char *key,
+              const char *value)
+{
+  struct Socks5Request *s5r = cls;
+  char *hdr;
+
+  if ( (0 == strcasecmp (MHD_HTTP_HEADER_HOST, key)) &&
+       (NULL != s5r->leho) )
+    value = s5r->leho;
+  if (0 == strcasecmp (MHD_HTTP_HEADER_CONTENT_LENGTH, key))
+    return MHD_YES;
+  if (0 == strcasecmp (MHD_HTTP_HEADER_ACCEPT_ENCODING, key))
+    return MHD_YES;
+  GNUNET_asprintf (&hdr,
+                   "%s: %s",
+                   key,
+                   value);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Adding HEADER `%s' to HTTP request\n",
+              hdr);
+  s5r->headers = curl_slist_append (s5r->headers,
+                                    hdr);
+  GNUNET_free (hdr);
+  return MHD_YES;
+}
+
+
+/**
+ * Main MHD callback for handling requests.
+ *
+ * @param cls unused
+ * @param con MHD connection handle
+ * @param url the url in the request
+ * @param meth the HTTP method used ("GET", "PUT", etc.)
+ * @param ver the HTTP version string (i.e. "HTTP/1.1")
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ *        for a POST that fits into memory and that is encoded
+ *        with a supported encoding, the POST data will NOT be
+ *        given in upload_data and is instead available as
+ *        part of MHD_get_connection_values; very large POST
+ *        data *will* be made available incrementally in
+ *        upload_data)
+ * @param upload_data_size set initially to the size of the
+ *        @a upload_data provided; the method must update this
+ *        value to the number of bytes NOT processed;
+ * @param con_cls pointer to location where we store the 'struct Request'
+ * @return MHD_YES if the connection was handled successfully,
+ *         MHD_NO if the socket must be closed due to a serious
+ *         error while handling the request
+ */
+static int
+create_response (void *cls,
+                 struct MHD_Connection *con,
+                 const char *url,
+                 const char *meth,
+                 const char *ver,
+                 const char *upload_data,
+                 size_t *upload_data_size,
+                 void **con_cls)
+{
+  struct Socks5Request *s5r = *con_cls;
+  char *curlurl;
+  char *curl_hosts;
+  char ipstring[INET6_ADDRSTRLEN];
+  char ipaddr[INET6_ADDRSTRLEN + 2];
+  const struct sockaddr *sa;
+  const struct sockaddr_in *s4;
+  const struct sockaddr_in6 *s6;
+  uint16_t port;
+  size_t left;
+
+  if (NULL == s5r)
+  {
+    GNUNET_break (0);
+    return MHD_NO;
+  }
+  //Fresh connection.
+  if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
+  {
+    /* first time here, initialize curl handle */
+    sa = (const struct sockaddr *) &s5r->destination_address;
+    switch (sa->sa_family)
+    {
+      case AF_INET:
+        s4 = (const struct sockaddr_in *) &s5r->destination_address;
+        if (NULL == inet_ntop (AF_INET,
+                               &s4->sin_addr,
+                               ipstring,
+                               sizeof (ipstring)))
+        {
+          GNUNET_break (0);
+          return MHD_NO;
+        }
+        GNUNET_snprintf (ipaddr,
+                         sizeof (ipaddr),
+                         "%s",
+                         ipstring);
+        port = ntohs (s4->sin_port);
+        break;
+      case AF_INET6:
+        s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
+        if (NULL == inet_ntop (AF_INET6,
+                               &s6->sin6_addr,
+                               ipstring,
+                               sizeof (ipstring)))
+        {
+          GNUNET_break (0);
+          return MHD_NO;
+        }
+        GNUNET_snprintf (ipaddr,
+                         sizeof (ipaddr),
+                         "%s",
+                         ipstring);
+        port = ntohs (s6->sin6_port);
+        break;
+      default:
+        GNUNET_break (0);
+        return MHD_NO;
+    }
+    if (NULL == s5r->curl)
+      s5r->curl = curl_easy_init ();
+    if (NULL == s5r->curl)
+      return MHD_queue_response (con,
+                                 MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                 curl_failure_response);
+    curl_easy_setopt (s5r->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr);
+    curl_easy_setopt (s5r->curl, CURLOPT_HEADERDATA, s5r);
+    curl_easy_setopt (s5r->curl, CURLOPT_FOLLOWLOCATION, 0);
+    curl_easy_setopt (s5r->curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+    curl_easy_setopt (s5r->curl, CURLOPT_CONNECTTIMEOUT, 600L);
+    curl_easy_setopt (s5r->curl, CURLOPT_TIMEOUT, 600L);
+    curl_easy_setopt (s5r->curl, CURLOPT_NOSIGNAL, 1L);
+    curl_easy_setopt (s5r->curl, CURLOPT_HTTP_CONTENT_DECODING, 0);
+    curl_easy_setopt (s5r->curl, CURLOPT_HTTP_TRANSFER_DECODING, 0);
+    curl_easy_setopt (s5r->curl, CURLOPT_NOSIGNAL, 1L);
+    curl_easy_setopt (s5r->curl, CURLOPT_PRIVATE, s5r);
+    curl_easy_setopt (s5r->curl, CURLOPT_VERBOSE, 0);
+    /**
+     * Pre-populate cache to resolve Hostname.
+     * This is necessary as the DNS name in the CURLOPT_URL is used
+     * for SNI http://de.wikipedia.org/wiki/Server_Name_Indication
+     */
+    if (NULL != s5r->leho)
+    {
+      GNUNET_asprintf (&curl_hosts,
+                       "%s:%d:%s",
+                       s5r->leho,
+                       port,
+                       ipaddr);
+      s5r->hosts = curl_slist_append(NULL, curl_hosts);
+      curl_easy_setopt(s5r->curl, CURLOPT_RESOLVE, s5r->hosts);
+      GNUNET_free (curl_hosts);
+    }
+    GNUNET_asprintf (&curlurl,
+                     (HTTPS_PORT != s5r->port)
+                     ? "http://%s:%d%s";
+                     : "https://%s:%d%s";,
+                     (NULL != s5r->leho)
+                     ? s5r->leho
+                     : ipaddr,
+                     port,
+                     s5r->url);
+    curl_easy_setopt (s5r->curl,
+                      CURLOPT_URL,
+                      curlurl);
+    GNUNET_free (curlurl);
+    if (0 == strcasecmp (meth, MHD_HTTP_METHOD_PUT))
+    {
+      s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
+      curl_easy_setopt (s5r->curl, CURLOPT_UPLOAD, 1);
+      curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb);
+      curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r);
+      curl_easy_setopt (s5r->curl, CURLOPT_READFUNCTION, &curl_upload_cb);
+      curl_easy_setopt (s5r->curl, CURLOPT_READDATA, s5r);
+    }
+    else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
+    {
+      s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
+      curl_easy_setopt (s5r->curl, CURLOPT_POST, 1L);
+            curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, 
&curl_download_cb);
+      curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r);
+      curl_easy_setopt (s5r->curl, CURLOPT_READFUNCTION, &curl_upload_cb);
+      curl_easy_setopt (s5r->curl, CURLOPT_READDATA, s5r);
+    }
+    else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_HEAD))
+    {
+      s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
+      curl_easy_setopt (s5r->curl, CURLOPT_NOBODY, 1);
+    }
+    else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_OPTIONS))
+    {
+      s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
+      curl_easy_setopt (s5r->curl, CURLOPT_CUSTOMREQUEST, "OPTIONS");
+    }
+    else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_GET))
+    {
+      s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
+      curl_easy_setopt (s5r->curl, CURLOPT_HTTPGET, 1);
+      curl_easy_setopt (s5r->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb);
+      curl_easy_setopt (s5r->curl, CURLOPT_WRITEDATA, s5r);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  _("Unsupported HTTP method `%s'\n"),
+                  meth);
+      curl_easy_cleanup (s5r->curl);
+      s5r->curl = NULL;
+      return MHD_NO;
+    }
+
+    if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
+    {
+      curl_easy_setopt (s5r->curl, CURLOPT_HTTP_VERSION, 
CURL_HTTP_VERSION_1_0);
+    }
+    else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
+    {
+      curl_easy_setopt (s5r->curl, CURLOPT_HTTP_VERSION, 
CURL_HTTP_VERSION_1_1);
+    }
+    else
+    {
+      curl_easy_setopt (s5r->curl, CURLOPT_HTTP_VERSION, 
CURL_HTTP_VERSION_NONE);
+    }
+
+    if (HTTPS_PORT == s5r->port)
+    {
+      curl_easy_setopt (s5r->curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
+      if (NULL != s5r->dane_data)
+        curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYPEER, 0L);
+      else
+        curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYPEER, 1L);
+      /* Disable cURL checking the hostname, as we will check ourselves
+         as only we have the domain name or the LEHO or the DANE record */
+      curl_easy_setopt (s5r->curl, CURLOPT_SSL_VERIFYHOST, 0L);
+    }
+    else
+    {
+      curl_easy_setopt (s5r->curl, CURLOPT_USE_SSL, CURLUSESSL_NONE);
+    }
+
+    if (CURLM_OK != curl_multi_add_handle (curl_multi, s5r->curl))
+    {
+      GNUNET_break (0);
+      curl_easy_cleanup (s5r->curl);
+      s5r->curl = NULL;
+      return MHD_NO;
+    }
+    MHD_get_connection_values (con,
+                               MHD_HEADER_KIND,
+                               &con_val_iter, s5r);
+    curl_easy_setopt (s5r->curl, CURLOPT_HTTPHEADER, s5r->headers);
+    curl_download_prepare ();
+    return MHD_YES;
+  }
+
+  /* continuing to process request */
+  if (0 != *upload_data_size)
+  {
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Processing %u bytes UPLOAD\n",
+               (unsigned int) *upload_data_size);
+
+    /* FIXME: This must be set or a header with Transfer-Encoding: chunked. 
Else
+     * upload callback is not called!
+     */
+    curl_easy_setopt (s5r->curl, CURLOPT_POSTFIELDSIZE, *upload_data_size);
+
+    left = GNUNET_MIN (*upload_data_size,
+                       sizeof (s5r->io_buf) - s5r->io_len);
+    GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
+                   upload_data,
+                   left);
+    s5r->io_len += left;
+    *upload_data_size -= left;
+    GNUNET_assert (NULL != s5r->curl);
+    curl_easy_pause (s5r->curl, CURLPAUSE_CONT);
+    return MHD_YES;
+  }
+  if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Finished processing UPLOAD\n");
+    s5r->state = SOCKS5_SOCKET_UPLOAD_DONE;
+  }
+  if (NULL == s5r->response)
+    return MHD_YES;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Queueing response with MHD\n");
+  run_mhd_now (s5r->hd);
+  return MHD_queue_response (con,
+                             s5r->response_code,
+                             s5r->response);
+}
+
+
+/* ******************** MHD HTTP setup and event loop ******************** */
+
+
+/**
+ * Function called when MHD decides that we are done with a request.
+ *
+ * @param cls NULL
+ * @param connection connection handle
+ * @param con_cls value as set by the last call to
+ *        the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
+ * @param toe reason for request termination (ignored)
+ */
+static void
+mhd_completed_cb (void *cls,
+                  struct MHD_Connection *connection,
+                  void **con_cls,
+                  enum MHD_RequestTerminationCode toe)
+{
+  struct Socks5Request *s5r = *con_cls;
+  struct HttpResponseHeader *header;
+
+  if (NULL == s5r)
+    return;
+  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "MHD encountered error handling request: %d\n",
+                toe);
+  if (NULL != s5r->curl)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Resetting cURL handle\n");
+    curl_multi_remove_handle (curl_multi,
+                              s5r->curl);
+    curl_slist_free_all (s5r->headers);
+    s5r->headers = NULL;
+    curl_easy_reset (s5r->curl);
+    s5r->rbuf_len = 0;
+    s5r->wbuf_len = 0;
+    s5r->io_len = 0;
+  }
+  if ( (NULL != s5r->response) &&
+       (curl_failure_response != s5r->response) )
+    MHD_destroy_response (s5r->response);
+  for (header = s5r->header_head; header != NULL; header = s5r->header_head)
+  {
+    GNUNET_CONTAINER_DLL_remove (s5r->header_head,
+                                 s5r->header_tail,
+                                 header);
+    GNUNET_free (header->type);
+    GNUNET_free (header->value);
+    GNUNET_free (header);
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Finished request for %s\n",
+              s5r->url);
+  GNUNET_free (s5r->url);
+  GNUNET_free (s5r);
+  *con_cls = NULL;
+}
+
+
+/**
+ * Function called when MHD first processes an incoming connection.
+ * Gives us the respective URI information.
+ *
+ * We use this to associate the `struct MHD_Connection` with our
+ * internal `struct Socks5Request` data structure (by checking
+ * for matching sockets).
+ *
+ * @param cls the HTTP server handle (a `struct MhdHttpList`)
+ * @param url the URL that is being requested
+ * @param connection MHD connection object for the request
+ * @return the `struct Socks5Request` that this @a connection is for
+ */
+static void *
+mhd_log_callback (void *cls,
+                  const char *url,
+                  struct MHD_Connection *connection)
+{
+  struct Socks5Request *s5r;
+  const union MHD_ConnectionInfo *ci;
+
+  ci = MHD_get_connection_info (connection,
+                                MHD_CONNECTION_INFO_SOCKET_CONTEXT);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Processing %s\n",
+              url);
+  if (NULL == ci)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  s5r = GNUNET_new (struct Socks5Request);
+  s5r->url = GNUNET_strdup (url);
+  return s5r;
+}
+
+
+/**
+ * Kill the MHD daemon.
+ */
+static void
+kill_httpd (void)
+{
+  MHD_stop_daemon (daemon);
+  daemon = NULL;
+  if (NULL != httpd_task)
+  {
+    GNUNET_SCHEDULER_cancel (httpd_task);
+    httpd_task = NULL;
+  }
+}
+
+
+/**
+ * Task run whenever HTTP server operations are pending.
+ *
+ * @param cls the `struct MhdHttpList *` of the daemon that is being run
+ */
+static void
+do_httpd (void *cls);
+
+
+/**
+ * Schedule MHD.  This function should be called initially when an
+ * MHD is first getting its client socket, and will then automatically
+ * always be called later whenever there is work to be done.
+ */
+static void
+schedule_httpd (void)
+{
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  struct GNUNET_NETWORK_FDSet *wrs;
+  struct GNUNET_NETWORK_FDSet *wws;
+  int max;
+  int haveto;
+  MHD_UNSIGNED_LONG_LONG timeout;
+  struct GNUNET_TIME_Relative tv;
+
+  FD_ZERO (&rs);
+  FD_ZERO (&ws);
+  FD_ZERO (&es);
+  max = -1;
+  if (MHD_YES !=
+      MHD_get_fdset (daemon,
+                     &rs,
+                     &ws,
+                     &es,
+                     &max))
+  {
+    kill_httpd (NULL);
+    return;
+  }
+  haveto = MHD_get_timeout (daemon,
+                            &timeout);
+  if (MHD_YES == haveto)
+    tv.rel_value_us = (uint64_t) timeout * 1000LL;
+  else
+    tv = GNUNET_TIME_UNIT_FOREVER_REL;
+  if (-1 != max)
+  {
+    wrs = GNUNET_NETWORK_fdset_create ();
+    wws = GNUNET_NETWORK_fdset_create ();
+    GNUNET_NETWORK_fdset_copy_native (wrs,
+                                      &rs,
+                                      max + 1);
+    GNUNET_NETWORK_fdset_copy_native (wws,
+                                      &ws,
+                                      max + 1);
+  }
+  else
+  {
+    wrs = NULL;
+    wws = NULL;
+  }
+  if (NULL != httpd_task)
+  {
+    GNUNET_SCHEDULER_cancel (httpd_task);
+    httpd_task = NULL;
+  }
+  httpd_task =
+    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                 tv,
+                                 wrs,
+                                 wws,
+                                 &do_httpd,
+                                 NULL);
+  if (NULL != wrs)
+    GNUNET_NETWORK_fdset_destroy (wrs);
+  if (NULL != wws)
+    GNUNET_NETWORK_fdset_destroy (wws);
+}
+
+
+/**
+ * Task run whenever HTTP server operations are pending.
+ *
+ * @param cls NULL
+ */
+static void
+do_httpd (void *cls)
+{
+  httpd_task = NULL;
+  MHD_run (daemon);
+  schedule_httpd (NULL);
+}
+
+
+/**
+ * Run MHD now, we have extra data ready for the callback.
+ */
+static void
+run_mhd_now (void)
+{
+  if (NULL != httpd_task)
+    GNUNET_SCHEDULER_cancel (httpd_task);
+  httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
+                                         NULL);
+}
+
+
+
+/**
+ * Function called by MHD with errors, suppresses them all.
+ *
+ * @param cls closure
+ * @param fm format string (`printf()`-style)
+ * @param ap arguments to @a fm
+ */
+static void
+mhd_error_log_callback (void *cls,
+                        const char *fm,
+                        va_list ap)
+{
+  /* do nothing */
+}
+
+
+/* ******************* General / main code ********************* */
+
+
+/**
+ * Task run on shutdown
+ *
+ * @param cls closure
+ */
+static void
+do_shutdown (void *cls)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Shutting down...\n");
+  kill_httpd ();
+  if (NULL != curl_multi)
+  {
+    curl_multi_cleanup (curl_multi);
+    curl_multi = NULL;
+  }
+  if (NULL != curl_download_task)
+  {
+    GNUNET_SCHEDULER_cancel (curl_download_task);
+    curl_download_task = NULL;
+  }
+}
+
+
+/**
+ * Main function that will be run
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  cfg = c;
+  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "cURL global init failed!\n");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if (NULL == (curl_multi = curl_multi_init ()))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to create cURL multi handle!\n");
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Proxy listens on port %llu\n",
+              port);
+
+  /* start MHD daemon for HTTP */
+  daemon = MHD_start_daemon (MHD_USE_DEBUG,
+                             port,
+                             NULL, NULL,
+                             &create_response, NULL,
+                             MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
+                             MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, 
NULL,
+                             MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, 
NULL,
+                             MHD_OPTION_END);
+  if (NULL == daemon)
+  {
+    GNUNET_break (0);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+                                 NULL);
+  run_mhd_now ();
+}
+
+
+/**
+ * The main function for gnunet-gns-proxy.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_option_ulong ('p',
+                                "port",
+                                NULL,
+                                gettext_noop ("listen on specified port 
(default: 7777)"),
+                                &port),
+    GNUNET_GETOPT_OPTION_END
+  };
+  static const char* page =
+    "<html><head><title>taler-twister</title>"
+    "</head><body>cURL fail</body></html>";
+  int ret;
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_get_utf8_args (argc, argv,
+                                    &argc, &argv))
+    return 2;
+  GNUNET_log_setup ("taler-twister",
+                    "WARNING",
+                    NULL);
+  curl_failure_response
+    = MHD_create_response_from_buffer (strlen (page),
+                                       (void *) page,
+                                       MHD_RESPMEM_PERSISTENT);
+
+  ret =
+    (GNUNET_OK ==
+     GNUNET_PROGRAM_run (argc, argv,
+                         "taler-twister",
+                         _("Taler Man-in-the-Middle HTTP proxy"),
+                         options,
+                         &run, NULL)) ? 0 : 1;
+  MHD_destroy_response (curl_failure_response);
+  GNUNET_free_non_null ((char *) argv);
+  return ret;
+}
+
+/* end of taler-twister.c */

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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