4445245b327b123986e22e2fb9bc8bdfbca2c7e2
[oweals/gnunet.git] / src / gns / gnunet-gns-proxy.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 #include "platform.h"
22 #include <gnunet_util_lib.h>
23 #include <gnunet_gns_service.h>
24 #include <microhttpd.h>
25 #include <curl/curl.h>
26 #include <regex.h>
27 #include "gns_proxy_proto.h"
28 #include "gns.h"
29
30 /** SSL **/
31 #include <gnutls/gnutls.h>
32 #include <gnutls/x509.h>
33 #include <gnutls/abstract.h>
34 #include <gnutls/crypto.h>
35 #include <time.h>
36
37 #define GNUNET_GNS_PROXY_PORT 7777
38 #define MHD_MAX_CONNECTIONS 300
39
40 /* MHD/cURL defines */
41 #define BUF_WAIT_FOR_CURL 0
42 #define BUF_WAIT_FOR_MHD 1
43 #define HTML_HDR_CONTENT "Content-Type: text/html"
44
45 /* regexp */
46 //#define RE_DOTPLUS "<a href=\"http://(([A-Za-z]+[.])+)([+])"
47 #define RE_A_HREF  "<a href=\"https?://(([A-Za-z0-9]+[.])+)([+]|zkey)"
48 #define RE_N_MATCHES 4
49
50 /* The usual suspects */
51 #define HTTP_PORT 80
52 #define HTTPS_PORT 443
53
54
55 /**
56  * A structure for CA cert/key
57  */
58 struct ProxyCA
59 {
60   /* The certificate */
61   gnutls_x509_crt_t cert;
62
63   /* The private key */
64   gnutls_x509_privkey_t key;
65 };
66
67
68 /**
69  * Structure for GNS certificates
70  */
71 struct ProxyGNSCertificate
72 {
73   /* The certificate as PEM */
74   char cert[10 * 1024];
75
76   /* The private key as PEM */
77   char key[10 * 1024];
78 };
79
80
81 /**
82  * A structure for socks requests
83  */
84 struct Socks5Request
85 {
86   /* The client socket */
87   struct GNUNET_NETWORK_Handle *sock;
88
89   /* The server socket */
90   struct GNUNET_NETWORK_Handle *remote_sock;
91   
92   /* The socks state */
93   int state;
94   
95   /* Client socket read task */
96   GNUNET_SCHEDULER_TaskIdentifier rtask;
97
98   /* Server socket read task */
99   GNUNET_SCHEDULER_TaskIdentifier fwdrtask;
100
101   /* Client socket write task */
102   GNUNET_SCHEDULER_TaskIdentifier wtask;
103
104   /* Server socket write task */
105   GNUNET_SCHEDULER_TaskIdentifier fwdwtask;
106
107   /* Read buffer */
108   char rbuf[2048];
109
110   /* Write buffer */
111   char wbuf[2048];
112
113   /* Length of data in read buffer */
114   unsigned int rbuf_len;
115
116   /* Length of data in write buffer */
117   unsigned int wbuf_len;
118
119   /* This handle is scheduled for cleanup? */
120   int cleanup;
121
122   /* Shall we close the client socket on cleanup? */
123   int cleanup_sock;
124 };
125
126 /**
127  * DLL for Network Handles
128  */
129 struct NetworkHandleList
130 {
131   /*DLL*/
132   struct NetworkHandleList *next;
133
134   /*DLL*/
135   struct NetworkHandleList *prev;
136
137   /* The handle */
138   struct GNUNET_NETWORK_Handle *h;
139 };
140
141 /**
142  * A structure for all running Httpds
143  */
144 struct MhdHttpList
145 {
146   /* DLL for httpds */
147   struct MhdHttpList *prev;
148
149   /* DLL for httpds */
150   struct MhdHttpList *next;
151
152   /* is this an ssl daemon? */
153   int is_ssl;
154
155   /* the domain name to server (only important for SSL) */
156   char domain[256];
157
158   /* The daemon handle */
159   struct MHD_Daemon *daemon;
160
161   /* Optional proxy certificate used */
162   struct ProxyGNSCertificate *proxy_cert;
163
164   /* The task ID */
165   GNUNET_SCHEDULER_TaskIdentifier httpd_task;
166
167   /* Handles associated with this daemon */
168   struct NetworkHandleList *socket_handles_head;
169   
170   /* Handles associated with this daemon */
171   struct NetworkHandleList *socket_handles_tail;
172 };
173
174 /**
175  * A structure for MHD<->cURL streams
176  */
177 struct ProxyCurlTask
178 {
179   /* DLL for tasks */
180   struct ProxyCurlTask *prev;
181
182   /* DLL for tasks */
183   struct ProxyCurlTask *next;
184
185   /* Handle to cURL */
186   CURL *curl;
187
188   /* Optional header replacements for curl (LEHO) */
189   struct curl_slist *headers;
190
191   /* Optional resolver replacements for curl (LEHO) */
192   struct curl_slist *resolver;
193
194   /* The URL to fetch */
195   char url[2048];
196
197   /* The cURL write buffer / MHD read buffer */
198   char buffer[CURL_MAX_WRITE_SIZE];
199
200   /* The pointer to the data in the buffer */
201   char *buffer_ptr;
202
203   /* The buffer status (BUF_WAIT_FOR_CURL or BUF_WAIT_FOR_MHD) */
204   int buf_status;
205
206   /* Number of bytes in buffer */
207   unsigned int bytes_in_buffer;
208
209   /* Indicates wheather the download is in progress */
210   int download_in_progress;
211
212   /* Indicates wheather the download was successful */
213   int download_successful;
214
215   /* Indicates wheather the download failed */
216   int download_error;
217
218   /* Indicates wheather we need to parse HTML */
219   int parse_content;
220
221   /* Indicates wheather we are postprocessing the HTML right now */
222   int is_postprocessing;
223
224   /* Indicates wheather postprocessing has finished */
225   int pp_finished;
226
227   /* Task ID of the postprocessing task */
228   GNUNET_SCHEDULER_TaskIdentifier pp_task;
229
230   /* The postprocessing buffer TODO length? */
231   char pp_buf[256];
232
233   /* The authority of the corresponding host (site of origin) */
234   char authority[256];
235
236   /* The hostname (Host header field) */
237   char host[256];
238
239   /* The LEgacy HOstname (can be empty) */
240   char leho[256];
241
242   /* The associated daemon list entry */
243   struct MhdHttpList *mhd;
244
245   /* The associated response */
246   struct MHD_Response *response;
247
248   /* Cookies to set */
249   struct ProxySetCookieHeader *set_cookies_head;
250
251   /* Cookies to set */
252   struct ProxySetCookieHeader *set_cookies_tail;
253
254   /* connection status */
255   int con_status;
256
257   /* connection */
258   struct MHD_Connection *connection;
259   
260 };
261
262 /**
263  * Struct for set-cookies
264  */
265 struct ProxySetCookieHeader
266 {
267   /* DLL */
268   struct ProxySetCookieHeader *next;
269
270   /* DLL */
271   struct ProxySetCookieHeader *prev;
272
273   /* the cookie */
274   char *cookie;
275 };
276
277 /* The port the proxy is running on (default 7777) */
278 static unsigned long port = GNUNET_GNS_PROXY_PORT;
279
280 /* The CA file (pem) to use for the proxy CA */
281 static char* cafile_opt;
282
283 /* The listen socket of the proxy */
284 static struct GNUNET_NETWORK_Handle *lsock;
285
286 /* The listen task ID */
287 GNUNET_SCHEDULER_TaskIdentifier ltask;
288
289 /* The cURL download task */
290 GNUNET_SCHEDULER_TaskIdentifier curl_download_task;
291
292 /* The non SSL httpd daemon handle */
293 static struct MHD_Daemon *httpd;
294
295 /* Number of current mhd connections */
296 static unsigned int total_mhd_connections;
297
298 /* The cURL multi handle */
299 static CURLM *curl_multi;
300
301 /* Handle to the GNS service */
302 static struct GNUNET_GNS_Handle *gns_handle;
303
304 /* DLL for ProxyCurlTasks */
305 static struct ProxyCurlTask *ctasks_head;
306
307 /* DLL for ProxyCurlTasks */
308 static struct ProxyCurlTask *ctasks_tail;
309
310 /* DLL for http daemons */
311 static struct MhdHttpList *mhd_httpd_head;
312
313 /* DLL for http daemons */
314 static struct MhdHttpList *mhd_httpd_tail;
315
316 /* Handle to the regex for dotplus (.+) replacement in HTML */
317 static regex_t re_dotplus;
318
319 /* The users local GNS zone hash */
320 static struct GNUNET_CRYPTO_ShortHashCode local_gns_zone;
321
322 /* The users local private zone */
323 static struct GNUNET_CRYPTO_ShortHashCode local_private_zone;
324
325 /* The users local shorten zone */
326 static struct GNUNET_CRYPTO_ShortHashCode local_shorten_zone;
327
328 /* The CA for SSL certificate generation */
329 static struct ProxyCA proxy_ca;
330
331 /* UNIX domain socket for mhd */
332 struct GNUNET_NETWORK_Handle *mhd_unix_socket;
333
334 /* Shorten zone private key */
335 struct GNUNET_CRYPTO_RsaPrivateKey *shorten_zonekey;
336
337 /**
338  * Checks if name is in tld
339  *
340  * @param name the name to check
341  * @param tld the TLD to check for
342  * @return GNUNET_YES or GNUNET_NO
343  */
344 int
345 is_tld(const char* name, const char* tld)
346 {
347   int offset = 0;
348
349   if (strlen(name) <= strlen(tld))
350   {
351     return GNUNET_NO;
352   }
353
354   offset = strlen(name)-strlen(tld);
355   if (strcmp (name+offset, tld) != 0)
356   {
357     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
358                "%s is not in .%s TLD\n", name, tld);
359     return GNUNET_NO;
360   }
361
362   return GNUNET_YES;
363 }
364
365
366 /**
367  * Read HTTP request header field 'Host'
368  *
369  * @param cls buffer to write to
370  * @param kind value kind
371  * @param key field key
372  * @param value field value
373  * @return MHD_NO when Host found
374  */
375 static int
376 con_val_iter (void *cls,
377               enum MHD_ValueKind kind,
378               const char *key,
379               const char *value)
380 {
381   char* buf = (char*)cls;
382
383   if (0 == strcmp ("Host", key))
384   {
385     strcpy (buf, value);
386     return MHD_NO;
387   }
388   return MHD_YES;
389 }
390
391
392 /**
393  * Check HTTP response header for mime
394  *
395  * @param buffer curl buffer
396  * @param size curl blocksize
397  * @param nmemb curl blocknumber
398  * @param cls handle
399  * @return size of read bytes
400  */
401 static size_t
402 curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
403 {
404   size_t bytes = size * nmemb;
405   struct ProxyCurlTask *ctask = cls;
406   int html_mime_len = strlen (HTML_HDR_CONTENT);
407   int cookie_hdr_len = strlen (MHD_HTTP_HEADER_SET_COOKIE);
408   char hdr_mime[html_mime_len+1];
409   char hdr_cookie[bytes+1];
410   //char hdr_cookie_gns[bytes+strlen (ctask->leho)+1];
411   //char* ndup;
412   
413   if (html_mime_len <= bytes)
414   {
415     memcpy (hdr_mime, buffer, html_mime_len);
416     hdr_mime[html_mime_len] = '\0';
417
418     if (0 == strcmp (hdr_mime, HTML_HDR_CONTENT))
419     {
420       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421                   "Got HTML HTTP response header\n");
422       ctask->parse_content = GNUNET_YES;
423     }
424   }
425
426   if (cookie_hdr_len > bytes)
427     return bytes;
428
429   memcpy (hdr_cookie, buffer, bytes);
430   hdr_cookie[bytes] = '\0';
431   /*remove crlf*/
432   if (hdr_cookie[bytes-1] == '\n')
433     hdr_cookie[bytes-1] = '\0';
434
435   if (hdr_cookie[bytes-2] == '\r')
436     hdr_cookie[bytes-2] = '\0';
437   
438   if (0 == memcmp (hdr_cookie,
439                    MHD_HTTP_HEADER_SET_COOKIE,
440                    cookie_hdr_len))
441   {
442     //ndup = GNUNET_strdup (hdr_cookie);
443     //tok = strtok (ndup, ";");
444
445     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
446                 "Got Set-Cookie HTTP header %s\n", hdr_cookie);
447     //pch = GNUNET_malloc (sizeof (struct ProxySetCookieHeader));
448     //len = strlen (hdr_cookie) - cookie_hdr_len - 1;
449     //pch->cookie = GNUNET_malloc (len + 1);
450     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
451                 "Copying Set-Cookie data %s:\n", hdr_cookie+cookie_hdr_len+1);
452     //memset (pch->cookie, 0, len + 1);
453     //memcpy (pch->cookie, hdr_cookie+cookie_hdr_len+1, len);
454     //GNUNET_CONTAINER_DLL_insert (ctask->set_cookies_head,
455     //                             ctask->set_cookies_tail,
456     //                             pch);
457     //pch = ctask->set_cookies_head;
458     //while (pch != NULL)
459     //{
460       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
461                   "MHD: adding cookie: %s\n",
462                   hdr_cookie+cookie_hdr_len+1);
463     
464       if (GNUNET_NO == MHD_add_response_header (ctask->response,
465                                                 MHD_HTTP_HEADER_SET_COOKIE,
466                                                 hdr_cookie+cookie_hdr_len+1))
467       {
468         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
469                     "MHD: Error adding set-cookie header field %s\n",
470                     hdr_cookie+cookie_hdr_len+1);
471       }
472       MHD_add_response_header (ctask->response,
473                                MHD_HTTP_HEADER_SET_COOKIE,
474                                "test=test; domain=homepage.gnunet; secure");
475       //GNUNET_free (pch->cookie);
476       //GNUNET_CONTAINER_DLL_remove (ctask->set_cookies_head,
477       //                             ctask->set_cookies_tail,
478       //                             pch);
479       //GNUNET_free (pch);
480       //pch = ctask->set_cookies_head;
481     //}
482   }
483
484   return bytes;
485 }
486
487 /**
488  * schedule mhd
489  *
490  * @param hd a http daemon list entry
491  */
492 static void
493 run_httpd (struct MhdHttpList *hd);
494
495
496 /**
497  * schedule all mhds
498  *
499  */
500 static void
501 run_httpds (void);
502
503
504 /**
505  * Task that simply runs MHD main loop
506  *
507  * @param cls NULL
508  * @param tc task context
509  */
510 static void
511 run_mhd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
512 {
513
514   struct MhdHttpList *hd = cls;
515
516   //for (hd=mhd_httpd_head; hd != NULL; hd = hd->next)
517     MHD_run (hd->daemon);
518 }
519
520
521 /**
522  * Process cURL download bits
523  *
524  * @param ptr buffer with data
525  * @param size size of a record
526  * @param nmemb number of records downloaded
527  * @param ctx context
528  * @return number of processed bytes
529  */
530 static size_t
531 callback_download (void *ptr, size_t size, size_t nmemb, void *ctx)
532 {
533   const char *cbuf = ptr;
534   size_t total;
535   struct ProxyCurlTask *ctask = ctx;
536
537   //MHD_run (httpd);
538   if (ctask->con_status == MHD_NO)
539   {
540     MHD_queue_response (ctask->connection,
541                         MHD_HTTP_OK,
542                         ctask->response);
543     ctask->con_status = MHD_YES;
544   }
545   total = size*nmemb;
546
547   if (total == 0)
548   {
549     return total;
550   }
551
552   if (total > sizeof (ctask->buffer))
553   {
554     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555                 "CURL gave us too much data to handle (%d)!\n",
556                 total);
557     return 0;
558   }
559   
560   if (ctask->buf_status == BUF_WAIT_FOR_MHD)
561   {
562     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563                 "CURL: Waiting for MHD (%s)\n", ctask->url);
564     return CURL_WRITEFUNC_PAUSE;
565   }
566
567
568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569               "CURL: Copying to MHD (%s, %d)\n", ctask->url, total);
570   memcpy (ctask->buffer, cbuf, total);
571   ctask->bytes_in_buffer = total;
572   ctask->buffer_ptr = ctask->buffer;
573
574   ctask->buf_status = BUF_WAIT_FOR_MHD;
575
576   //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577   //            "cURL chunk:\n%s\n", (char*)ctask->buffer);
578   //run_mhd (NULL, NULL);
579   GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
580   return total;
581 }
582
583 /**
584  * Ask cURL for the select sets and schedule download
585  */
586 static void
587 curl_download_prepare ();
588
589 /**
590  * Callback to free content
591  *
592  * @param cls content to free
593  * @param tc task context
594  */
595 static void
596 mhd_content_free (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
597 {
598   struct ProxyCurlTask *ctask = cls;
599
600   if (NULL != ctask->headers)
601     curl_slist_free_all (ctask->headers);
602
603   if (NULL != ctask->headers)
604     curl_slist_free_all (ctask->resolver);
605
606   if (NULL != ctask->response)
607     MHD_destroy_response (ctask->response);
608
609   GNUNET_free (ctask);
610
611 }
612
613
614 /**
615  * Shorten result callback
616  *
617  * @param cls the proxycurltask
618  * @param short_name the shortened name (NULL on error)
619  */
620 static void
621 process_shorten (void* cls, const char* short_name)
622 {
623   struct ProxyCurlTask *ctask = cls;
624
625   char tmp[strlen(ctask->pp_buf)]; //TODO length
626
627   if (NULL == short_name)
628   {
629     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
630                 "MHD PP: Unable to shorten %s\n",
631                 ctask->pp_buf);
632     return;
633   }
634
635   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636               "MHD PP: Shorten %s -> %s\n",
637               ctask->pp_buf,
638               short_name);
639
640   sprintf (tmp, "<a href=\"http://%s", short_name);
641   strcpy (ctask->pp_buf, tmp);
642
643   ctask->pp_finished = GNUNET_YES;
644
645   GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
646 }
647
648
649 /**
650  * Callback for MHD response
651  *
652  * @param cls closure
653  * @param pos in buffer
654  * @param buf buffer
655  * @param max space in buffer
656  * @return number of bytes written
657  */
658 static ssize_t
659 mhd_content_cb (void *cls,
660                 uint64_t pos,
661                 char* buf,
662                 size_t max)
663 {
664   struct ProxyCurlTask *ctask = cls;
665   ssize_t copied = 0;
666   size_t bytes_to_copy;
667   int nomatch;
668   char *hostptr;
669   regmatch_t m[RE_N_MATCHES];
670
671   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672               "MHD: content cb %s\n", ctask->url);
673
674   if (ctask->download_successful &&
675       (ctask->buf_status == BUF_WAIT_FOR_CURL))
676   {
677     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678                 "MHD: sending response for %s\n", ctask->url);
679     ctask->download_in_progress = GNUNET_NO;
680     GNUNET_SCHEDULER_add_now (&mhd_content_free, ctask);
681     GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
682     total_mhd_connections--;
683     return MHD_CONTENT_READER_END_OF_STREAM;
684   }
685   
686   if (ctask->download_error &&
687       (ctask->buf_status == BUF_WAIT_FOR_CURL))
688   {
689     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
690                 "MHD: sending error response\n");
691     ctask->download_in_progress = GNUNET_NO;
692     GNUNET_SCHEDULER_add_now (&mhd_content_free, ctask);
693     GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
694     total_mhd_connections--;
695     return MHD_CONTENT_READER_END_WITH_ERROR;
696   }
697
698   if ( ctask->buf_status == BUF_WAIT_FOR_CURL )
699     return 0;
700
701   bytes_to_copy = ctask->bytes_in_buffer;
702   
703   if (ctask->parse_content == GNUNET_YES)
704   {
705
706     GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG,
707                  "MHD: We need to parse the HTML %s\n", ctask->buffer_ptr);
708
709     nomatch = regexec ( &re_dotplus, ctask->buffer_ptr, RE_N_MATCHES, m, 0);
710
711     if (nomatch)
712     {
713       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
714                   "MHD RE: No match\n");
715     }
716     else
717     {
718       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719                   "MHD RE: Match\n");
720
721       GNUNET_assert (m[1].rm_so != -1);
722
723       hostptr = ctask->buffer_ptr+m[1].rm_so;
724
725       if (m[0].rm_so > 0)
726       {
727         bytes_to_copy = m[0].rm_so;
728         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729                     "Copying %d bytes.\n", m[0].rm_so);
730
731
732       }
733       else
734       {
735         if (ctask->is_postprocessing == GNUNET_YES)
736         {
737           
738           /*Done?*/
739           if ( ctask->pp_finished == GNUNET_NO )
740           {
741             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
742                         "MHD PP: Waiting for PP of %s\n", ctask->pp_buf);
743             return 0;
744           }
745           
746           ctask->is_postprocessing = GNUNET_NO;
747
748           ctask->bytes_in_buffer -= m[0].rm_eo;//(m[1].rm_eo-m[1].rm_so);
749           ctask->buffer_ptr += m[0].rm_eo;//(m[1].rm_eo-m[1].rm_so);
750           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
751                       "Skipping next %d bytes in buffer\n", m[0].rm_eo);
752
753           GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
754
755           if ( strlen (ctask->pp_buf) <= max )
756           {
757             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
758                         "Copying postprocessed %s.\n", ctask->pp_buf);
759             memcpy ( buf, ctask->pp_buf, strlen (ctask->pp_buf) );
760             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761                         "Done %s.\n", buf);
762             ctask->is_postprocessing = GNUNET_NO;
763             return strlen (ctask->pp_buf);
764           }
765           
766           return 0;
767         }
768
769         memset (ctask->pp_buf, 0, sizeof(ctask->pp_buf));
770         
771         /* If .+ extend with authority */
772         if (*(ctask->buffer_ptr+m[1].rm_eo) == '+')
773         {
774           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775                       "Links is .+\n");
776            memcpy (ctask->pp_buf, hostptr, (m[1].rm_eo-m[1].rm_so));
777            strcpy ( ctask->pp_buf+strlen(ctask->pp_buf),
778                     ctask->authority);
779         }
780         /* If .zkey simply copy the name */
781         else
782         {
783           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784                       "Link is zkey\n");
785           memcpy (ctask->pp_buf, hostptr, (m[1].rm_eo-m[1].rm_so + strlen (GNUNET_GNS_TLD_ZKEY)));
786         }
787
788         ctask->is_postprocessing = GNUNET_YES;
789         ctask->pp_finished = GNUNET_NO;
790         
791         GNUNET_GNS_shorten_zone (gns_handle,
792                                  ctask->pp_buf,
793                                  &local_private_zone,
794                                  &local_shorten_zone,
795                                  &local_gns_zone,
796                                  &process_shorten,
797                                  ctask);
798
799         return 0;
800       }
801     }
802   }
803
804   if ( bytes_to_copy > max )
805   {
806     GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG,
807                  "MHD: buffer in response too small! (%s)\n",
808                  ctask->url);
809     memcpy ( buf, ctask->buffer_ptr, max);
810     ctask->bytes_in_buffer -= max;
811     ctask->buffer_ptr += max;
812     copied = max;
813   }
814   else
815   {
816     GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG,
817                  "MHD: copying %d bytes to mhd response at offset %d\n",
818                  bytes_to_copy, pos);
819
820     memcpy ( buf, ctask->buffer_ptr, bytes_to_copy );
821     copied = bytes_to_copy;
822     if (bytes_to_copy < ctask->bytes_in_buffer)
823     {
824       ctask->bytes_in_buffer -= bytes_to_copy;
825       ctask->buffer_ptr += bytes_to_copy;
826     }
827     else
828     {
829       ctask->bytes_in_buffer = 0;
830       ctask->buf_status = BUF_WAIT_FOR_CURL;
831       ctask->buffer_ptr = ctask->buffer;
832       if (NULL != ctask->curl)
833         curl_easy_pause (ctask->curl, CURLPAUSE_CONT);
834       GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
835     }
836   }
837
838   GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd);
839
840   return copied;
841 }
842
843
844
845 /**
846  * Task that is run when we are ready to receive more data
847  * from curl
848  *
849  * @param cls closure
850  * @param tc task context
851  */
852 static void
853 curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
854
855 /**
856  * Ask cURL for the select sets and schedule download
857  */
858 static void
859 curl_download_prepare ()
860 {
861   CURLMcode mret;
862   fd_set rs;
863   fd_set ws;
864   fd_set es;
865   int max;
866   struct GNUNET_NETWORK_FDSet *grs;
867   struct GNUNET_NETWORK_FDSet *gws;
868   long to;
869   struct GNUNET_TIME_Relative rtime;
870
871   max = -1;
872   FD_ZERO (&rs);
873   FD_ZERO (&ws);
874   FD_ZERO (&es);
875   mret = curl_multi_fdset (curl_multi, &rs, &ws, &es, &max);
876
877   if (mret != CURLM_OK)
878   {
879     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
880                 "%s failed at %s:%d: `%s'\n",
881                 "curl_multi_fdset", __FILE__, __LINE__,
882                 curl_multi_strerror (mret));
883     //TODO cleanup here?
884     return;
885   }
886
887   mret = curl_multi_timeout (curl_multi, &to);
888   rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
889
890   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891               "cURL multi fds: max=%d timeout=%llu\n", max, to);
892
893   grs = GNUNET_NETWORK_fdset_create ();
894   gws = GNUNET_NETWORK_fdset_create ();
895   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
896   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
897   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898               "Scheduling task cURL\n");
899
900   if (curl_download_task != GNUNET_SCHEDULER_NO_TASK)
901     GNUNET_SCHEDULER_cancel (curl_download_task);
902   
903   curl_download_task =
904     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
905                                  rtime,
906                                  grs, gws,
907                                  &curl_task_download, curl_multi);
908   GNUNET_NETWORK_fdset_destroy (gws);
909   GNUNET_NETWORK_fdset_destroy (grs);
910
911 }
912
913
914 /**
915  * Task that is run when we are ready to receive more data
916  * from curl
917  *
918  * @param cls closure
919  * @param tc task context
920  */
921 static void
922 curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
923 {
924   int running;
925   int msgnum;
926   struct CURLMsg *msg;
927   CURLMcode mret;
928   struct ProxyCurlTask *ctask;
929   int num_ctasks;
930
931   struct ProxyCurlTask *clean_head = NULL;
932   struct ProxyCurlTask *clean_tail = NULL;
933
934   curl_download_task = GNUNET_SCHEDULER_NO_TASK;
935
936   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
937   {
938     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939                 "Shutdown requested while trying to download\n");
940     //TODO cleanup
941     return;
942   }
943   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
944               "Ready to dl\n");
945
946   do
947   {
948     running = 0;
949     num_ctasks = 0;
950     
951     mret = curl_multi_perform (curl_multi, &running);
952
953     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954                 "Running curl tasks: %d\n", running);
955
956     ctask = ctasks_head;
957     for (; ctask != NULL; ctask = ctask->next)
958     {
959       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
960                   "CTask: %s\n", ctask->url);
961       num_ctasks++;
962     }
963
964     if (num_ctasks != running)
965     {
966       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967                   "%d ctasks, %d curl running\n", num_ctasks, running);
968     }
969     
970     do
971     {
972       ctask = ctasks_head;
973       msg = curl_multi_info_read (curl_multi, &msgnum);
974       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975                   "Messages left: %d\n", msgnum);
976       
977       if (msg == NULL)
978         break;
979       switch (msg->msg)
980       {
981        case CURLMSG_DONE:
982          if ((msg->data.result != CURLE_OK) &&
983              (msg->data.result != CURLE_GOT_NOTHING))
984          {
985            GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
986                        "Download curl failed");
987             
988            for (; ctask != NULL; ctask = ctask->next)
989            {
990              if (NULL == ctask->curl)
991                continue;
992
993              if (memcmp (msg->easy_handle, ctask->curl, sizeof (CURL)) != 0)
994                continue;
995              
996              GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
997                          "Download curl failed for task %s: %s.\n",
998                          ctask->url,
999                          curl_easy_strerror (msg->data.result));
1000              ctask->download_successful = GNUNET_NO;
1001              ctask->download_error = GNUNET_YES;
1002              //curl_multi_remove_handle (curl_multi, ctask->curl);
1003              //curl_easy_cleanup (ctask->curl);
1004              //ctask->curl = NULL;
1005              GNUNET_CONTAINER_DLL_remove (ctasks_head, ctasks_tail,
1006                                           ctask);
1007              GNUNET_CONTAINER_DLL_insert (clean_head, clean_tail, ctask);
1008              break;
1009            }
1010            GNUNET_assert (ctask != NULL);
1011          }
1012          else
1013          {
1014            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015                        "cURL download completed.\n");
1016
1017            for (; ctask != NULL; ctask = ctask->next)
1018            {
1019              if (NULL == ctask->curl)
1020                continue;
1021
1022              if (memcmp (msg->easy_handle, ctask->curl, sizeof (CURL)) != 0)
1023                continue;
1024              
1025              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026                          "cURL task %s found.\n", ctask->url);
1027              ctask->download_successful = GNUNET_YES;
1028              //curl_multi_remove_handle (curl_multi, ctask->curl);
1029              //curl_easy_cleanup (ctask->curl);
1030              //ctask->curl = NULL;
1031              GNUNET_CONTAINER_DLL_remove (ctasks_head, ctasks_tail,
1032                                           ctask);
1033              GNUNET_CONTAINER_DLL_insert (clean_head, clean_tail, ctask);
1034
1035              break;
1036            }
1037            GNUNET_assert (ctask != NULL);
1038          }
1039          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1040                      "curl end %s\n", curl_easy_strerror(msg->data.result));
1041          break;
1042        default:
1043          GNUNET_assert (0);
1044          break;
1045       }
1046     } while (msgnum > 0);
1047
1048     for (ctask=clean_head; ctask != NULL; ctask = ctask->next)
1049     {
1050       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051                   "Removing cURL task %s.\n", ctask->url);
1052       curl_multi_remove_handle (curl_multi, ctask->curl);
1053       curl_easy_cleanup (ctask->curl);
1054       ctask->curl = NULL;
1055     }
1056     
1057     num_ctasks=0;
1058     for (ctask=ctasks_head; ctask != NULL; ctask = ctask->next)
1059     {
1060       num_ctasks++;
1061     }
1062     
1063     if (num_ctasks != running)
1064     {
1065       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066                   "%d ctasks, %d curl running\n", num_ctasks, running);
1067     }
1068
1069     GNUNET_assert ( num_ctasks == running );
1070
1071     run_httpds ();
1072
1073   } while (mret == CURLM_CALL_MULTI_PERFORM);
1074   
1075   
1076   if (mret != CURLM_OK)
1077   {
1078     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s failed at %s:%d: `%s'\n",
1079                 "curl_multi_perform", __FILE__, __LINE__,
1080                 curl_multi_strerror (mret));
1081   }
1082   curl_download_prepare();
1083 }
1084
1085 /**
1086  * Process LEHO lookup
1087  *
1088  * @param cls the ctask
1089  * @param rd_count number of records returned
1090  * @param rd record data
1091  */
1092 static void
1093 process_leho_lookup (void *cls,
1094                      uint32_t rd_count,
1095                      const struct GNUNET_NAMESTORE_RecordData *rd)
1096 {
1097   struct ProxyCurlTask *ctask = cls;
1098   char hosthdr[262]; //256 + "Host: "
1099   int i;
1100   CURLcode ret;
1101   CURLMcode mret;
1102   struct hostent *phost;
1103   char *ssl_ip;
1104   char resolvename[512];
1105   char curlurl[512];
1106
1107   ctask->headers = NULL;
1108
1109   strcpy (ctask->leho, "");
1110
1111   if (rd_count == 0)
1112     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113                 "No LEHO present!\n");
1114
1115   for (i=0; i<rd_count; i++)
1116   {
1117     if (rd[i].record_type != GNUNET_GNS_RECORD_LEHO)
1118       continue;
1119
1120     memcpy (ctask->leho, rd[i].data, rd[i].data_size);
1121
1122     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123                 "Found LEHO %s for %s\n", ctask->leho, ctask->url);
1124   }
1125
1126   if (0 != strcmp (ctask->leho, ""))
1127   {
1128     sprintf (hosthdr, "%s%s", "Host: ", ctask->leho);
1129     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1130                 "New HTTP header value: %s\n", hosthdr);
1131     ctask->headers = curl_slist_append (ctask->headers, hosthdr);
1132     GNUNET_assert (NULL != ctask->headers);
1133     ret = curl_easy_setopt (ctask->curl, CURLOPT_HTTPHEADER, ctask->headers);
1134     if (CURLE_OK != ret)
1135     {
1136       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s failed at %s:%d: `%s'\n",
1137                            "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret));
1138     }
1139
1140   }
1141
1142   if (ctask->mhd->is_ssl)
1143   {
1144     phost = (struct hostent*)gethostbyname (ctask->host);
1145
1146     if (phost!=NULL)
1147     {
1148       ssl_ip = inet_ntoa(*((struct in_addr*)(phost->h_addr)));
1149       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1150                   "SSL target server: %s\n", ssl_ip);
1151       sprintf (resolvename, "%s:%d:%s", ctask->leho, HTTPS_PORT, ssl_ip);
1152       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153                   "Curl resolve: %s\n", resolvename);
1154       ctask->resolver = curl_slist_append ( ctask->resolver, resolvename);
1155       curl_easy_setopt (ctask->curl, CURLOPT_RESOLVE, ctask->resolver);
1156       sprintf (curlurl, "https://%s%s", ctask->leho, ctask->url);
1157       curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl);
1158     }
1159     else
1160     {
1161       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1162                   "gethostbyname failed for %s!\n", ctask->host);
1163       ctask->download_successful = GNUNET_NO;
1164       ctask->download_error = GNUNET_YES;
1165       return;
1166     }
1167   }
1168
1169   if (CURLM_OK != (mret=curl_multi_add_handle (curl_multi, ctask->curl)))
1170   {
1171     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1172                 "%s failed at %s:%d: `%s'\n",
1173                 "curl_multi_add_handle", __FILE__, __LINE__,
1174                 curl_multi_strerror (mret));
1175     ctask->download_successful = GNUNET_NO;
1176     ctask->download_error = GNUNET_YES;
1177     return;
1178   }
1179   GNUNET_CONTAINER_DLL_insert (ctasks_head, ctasks_tail, ctask);
1180
1181   curl_download_prepare ();
1182
1183 }
1184
1185 /**
1186  * Initialize download and trigger curl
1187  *
1188  * @param cls the proxycurltask
1189  * @param auth_name the name of the authority (site of origin) of ctask->host
1190  *
1191  */
1192 static void
1193 process_get_authority (void *cls,
1194                        const char* auth_name)
1195 {
1196   struct ProxyCurlTask *ctask = cls;
1197
1198   if (NULL == auth_name)
1199   {
1200     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1201                 "Get authority failed!\n");
1202     strcpy (ctask->authority, "");
1203   }
1204   else
1205   {
1206     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1207                 "Get authority yielded %s\n", auth_name);
1208     strcpy (ctask->authority, auth_name);
1209   }
1210
1211   GNUNET_GNS_lookup_zone (gns_handle,
1212                           ctask->host,
1213                           &local_gns_zone,
1214                           GNUNET_GNS_RECORD_LEHO,
1215                           GNUNET_YES, //Only cached for performance
1216                           shorten_zonekey,
1217                           &process_leho_lookup,
1218                           ctask);
1219 }
1220
1221 /**
1222  * Main MHD callback for handling requests.
1223  *
1224  * @param cls unused
1225  * @param con MHD connection handle
1226  * @param url the url in the request
1227  * @param meth the HTTP method used ("GET", "PUT", etc.)
1228  * @param ver the HTTP version string (i.e. "HTTP/1.1")
1229  * @param upload_data the data being uploaded (excluding HEADERS,
1230  *        for a POST that fits into memory and that is encoded
1231  *        with a supported encoding, the POST data will NOT be
1232  *        given in upload_data and is instead available as
1233  *        part of MHD_get_connection_values; very large POST
1234  *        data *will* be made available incrementally in
1235  *        upload_data)
1236  * @param upload_data_size set initially to the size of the
1237  *        upload_data provided; the method must update this
1238  *        value to the number of bytes NOT processed;
1239  * @param con_cls pointer to location where we store the 'struct Request'
1240  * @return MHD_YES if the connection was handled successfully,
1241  *         MHD_NO if the socket must be closed due to a serious
1242  *         error while handling the request
1243  */
1244 static int
1245 create_response (void *cls,
1246                  struct MHD_Connection *con,
1247                  const char *url,
1248                  const char *meth,
1249                  const char *ver,
1250                  const char *upload_data,
1251                  size_t *upload_data_size,
1252                  void **con_cls)
1253 {
1254   static int dummy;
1255   struct MhdHttpList* hd = cls;
1256   const char* page = "<html><head><title>gnoxy</title>"\
1257                       "</head><body>cURL fail</body></html>";
1258   
1259   char host[265];
1260   char curlurl[512];
1261   int ret = MHD_YES;
1262
1263   struct ProxyCurlTask *ctask;
1264   
1265   if (0 != strcmp (meth, "GET"))
1266     return MHD_NO;
1267   if (&dummy != *con_cls)
1268   {
1269     *con_cls = &dummy;
1270     return MHD_YES;
1271   }
1272
1273   if (0 != *upload_data_size)
1274     return MHD_NO;
1275
1276   *con_cls = NULL;
1277
1278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1279               "url %s\n", url);
1280
1281   MHD_get_connection_values (con,
1282                              MHD_HEADER_KIND,
1283                              &con_val_iter, host);
1284
1285   
1286   /* Do cURL */
1287   ctask = GNUNET_malloc (sizeof (struct ProxyCurlTask));
1288   ctask->mhd = hd;
1289
1290   if (curl_multi == NULL)
1291     curl_multi = curl_multi_init ();
1292
1293   ctask->curl = curl_easy_init();
1294   
1295   if ((ctask->curl == NULL) || (curl_multi == NULL))
1296   {
1297     ctask->response = MHD_create_response_from_buffer (strlen (page),
1298                                               (void*)page,
1299                                               MHD_RESPMEM_PERSISTENT);
1300     ret = MHD_queue_response (con,
1301                               MHD_HTTP_OK,
1302                               ctask->response);
1303     MHD_destroy_response (ctask->response);
1304     GNUNET_free (ctask);
1305     return ret;
1306   }
1307   
1308   ctask->prev = NULL;
1309   ctask->next = NULL;
1310   ctask->headers = NULL;
1311   ctask->resolver = NULL;
1312   ctask->buffer_ptr = NULL;
1313   ctask->download_in_progress = GNUNET_YES;
1314   ctask->download_successful = GNUNET_NO;
1315   ctask->buf_status = BUF_WAIT_FOR_CURL;
1316   ctask->bytes_in_buffer = 0;
1317   ctask->parse_content = GNUNET_NO;
1318   ctask->connection = con;
1319   ctask->con_status = MHD_NO;
1320
1321   curl_easy_setopt (ctask->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr);
1322   curl_easy_setopt (ctask->curl, CURLOPT_HEADERDATA, ctask);
1323   curl_easy_setopt (ctask->curl, CURLOPT_WRITEFUNCTION, &callback_download);
1324   curl_easy_setopt (ctask->curl, CURLOPT_WRITEDATA, ctask);
1325   curl_easy_setopt (ctask->curl, CURLOPT_FOLLOWLOCATION, 1);
1326   curl_easy_setopt (ctask->curl, CURLOPT_MAXREDIRS, 4);
1327   /* no need to abort if the above failed */
1328   if (GNUNET_NO == ctask->mhd->is_ssl)
1329   {
1330     sprintf (curlurl, "http://%s%s", host, url);
1331     curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl);
1332     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333                 "Adding new curl task for %s\n", curlurl);
1334   }
1335   strcpy (ctask->host, host);
1336   strcpy (ctask->url, url);
1337   
1338   //curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl);
1339   curl_easy_setopt (ctask->curl, CURLOPT_FAILONERROR, 1);
1340   curl_easy_setopt (ctask->curl, CURLOPT_CONNECTTIMEOUT, 600L);
1341   curl_easy_setopt (ctask->curl, CURLOPT_TIMEOUT, 600L);
1342
1343   GNUNET_GNS_get_authority (gns_handle,
1344                             ctask->host,
1345                             &process_get_authority,
1346                             ctask);
1347   //download_prepare (ctask);
1348   //curl_download_prepare ();
1349
1350   ctask->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
1351                                                 20,
1352                                                 &mhd_content_cb,
1353                                                 ctask,
1354                                                 NULL);
1355   //ret = MHD_queue_response (con, MHD_HTTP_OK, ctask->response);
1356   
1357   //MHD_destroy_response (response);
1358
1359   //return ret;
1360   return MHD_YES;
1361 }
1362
1363 /**
1364  * Task run whenever HTTP server operations are pending.
1365  *
1366  * @param cls unused
1367  * @param tc sched context
1368  */
1369 static void
1370 do_httpd (void *cls,
1371           const struct GNUNET_SCHEDULER_TaskContext *tc);
1372
1373
1374 /**
1375  * run all httpd
1376  */
1377 static void
1378 run_httpds ()
1379 {
1380   struct MhdHttpList *hd;
1381
1382   for (hd=mhd_httpd_head; hd != NULL; hd = hd->next)
1383     run_httpd (hd);
1384
1385 }
1386
1387 /**
1388  * schedule mhd
1389  *
1390  * @param hd the daemon to run
1391  */
1392 static void
1393 run_httpd (struct MhdHttpList *hd)
1394 {
1395   fd_set rs;
1396   fd_set ws;
1397   fd_set es;
1398   struct GNUNET_NETWORK_FDSet *wrs;
1399   struct GNUNET_NETWORK_FDSet *wws;
1400   struct GNUNET_NETWORK_FDSet *wes;
1401   int max;
1402   int haveto;
1403   unsigned MHD_LONG_LONG timeout;
1404   struct GNUNET_TIME_Relative tv;
1405
1406   FD_ZERO (&rs);
1407   FD_ZERO (&ws);
1408   FD_ZERO (&es);
1409   wrs = GNUNET_NETWORK_fdset_create ();
1410   wes = GNUNET_NETWORK_fdset_create ();
1411   wws = GNUNET_NETWORK_fdset_create ();
1412   max = -1;
1413   GNUNET_assert (MHD_YES == MHD_get_fdset (hd->daemon, &rs, &ws, &es, &max));
1414   
1415   
1416   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1417               "MHD fds: max=%d\n", max);
1418   
1419   haveto = MHD_get_timeout (hd->daemon, &timeout);
1420
1421   if (haveto == MHD_YES)
1422     tv.rel_value = (uint64_t) timeout;
1423   else
1424     tv = GNUNET_TIME_UNIT_FOREVER_REL;
1425   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1426   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1427   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
1428   
1429   if (hd->httpd_task != GNUNET_SCHEDULER_NO_TASK)
1430     GNUNET_SCHEDULER_cancel (hd->httpd_task);
1431   hd->httpd_task =
1432     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
1433                                  tv, wrs, wws,
1434                                  &do_httpd, hd);
1435   GNUNET_NETWORK_fdset_destroy (wrs);
1436   GNUNET_NETWORK_fdset_destroy (wws);
1437   GNUNET_NETWORK_fdset_destroy (wes);
1438 }
1439
1440
1441 /**
1442  * Task run whenever HTTP server operations are pending.
1443  *
1444  * @param cls unused
1445  * @param tc sched context
1446  */
1447 static void
1448 do_httpd (void *cls,
1449           const struct GNUNET_SCHEDULER_TaskContext *tc)
1450 {
1451   struct MhdHttpList *hd = cls;
1452   
1453   hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
1454   
1455   MHD_run (hd->daemon);
1456   run_httpd (hd);
1457 }
1458
1459
1460 /**
1461  * Read data from socket
1462  *
1463  * @param cls the closure
1464  * @param tc scheduler context
1465  */
1466 static void
1467 do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1468
1469 /**
1470  * Read from remote end
1471  *
1472  * @param cls closure
1473  * @param tc scheduler context
1474  */
1475 static void
1476 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1477
1478 /**
1479  * Write data to remote socket
1480  *
1481  * @param cls the closure
1482  * @param tc scheduler context
1483  */
1484 static void
1485 do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1486 {
1487   struct Socks5Request *s5r = cls;
1488   unsigned int len;
1489
1490   s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
1491
1492   if ((NULL != tc->read_ready) &&
1493       (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->remote_sock)) &&
1494       ((len = GNUNET_NETWORK_socket_send (s5r->remote_sock, s5r->rbuf,
1495                                          s5r->rbuf_len)>0)))
1496   {
1497     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1498                 "Successfully sent %d bytes to remote socket\n",
1499                 len);
1500   }
1501   else
1502   {
1503     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote");
1504     //Really!?!?!?
1505     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1506       GNUNET_SCHEDULER_cancel (s5r->rtask);
1507     if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
1508       GNUNET_SCHEDULER_cancel (s5r->wtask);
1509     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1510       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1511     GNUNET_NETWORK_socket_close (s5r->remote_sock);
1512     GNUNET_NETWORK_socket_close (s5r->sock);
1513     GNUNET_free(s5r);
1514     return;
1515   }
1516
1517   s5r->rtask =
1518     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1519                                    s5r->sock,
1520                                    &do_read, s5r);
1521 }
1522
1523
1524 /**
1525  * Clean up s5r handles
1526  *
1527  * @param s5r the handle to destroy
1528  */
1529 static void
1530 cleanup_s5r (struct Socks5Request *s5r)
1531 {
1532   if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1533     GNUNET_SCHEDULER_cancel (s5r->rtask);
1534   if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
1535     GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
1536   if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1537     GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1538   
1539   if (NULL != s5r->remote_sock)
1540     GNUNET_NETWORK_socket_close (s5r->remote_sock);
1541   if ((NULL != s5r->sock) && (s5r->cleanup_sock == GNUNET_YES))
1542     GNUNET_NETWORK_socket_close (s5r->sock);
1543   
1544   GNUNET_free(s5r);
1545 }
1546
1547 /**
1548  * Write data to socket
1549  *
1550  * @param cls the closure
1551  * @param tc scheduler context
1552  */
1553 static void
1554 do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1555 {
1556   struct Socks5Request *s5r = cls;
1557   unsigned int len;
1558
1559   s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
1560
1561   if ((NULL != tc->read_ready) &&
1562       (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) &&
1563       ((len = GNUNET_NETWORK_socket_send (s5r->sock, s5r->wbuf,
1564                                          s5r->wbuf_len)>0)))
1565   {
1566     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1567                 "Successfully sent %d bytes to socket\n",
1568                 len);
1569   }
1570   else
1571   {
1572     
1573     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
1574     s5r->cleanup = GNUNET_YES;
1575     s5r->cleanup_sock = GNUNET_YES;
1576     cleanup_s5r (s5r);
1577     
1578     return;
1579   }
1580
1581   if (GNUNET_YES == s5r->cleanup)
1582   {
1583     cleanup_s5r (s5r);
1584     return;
1585   }
1586
1587   if ((s5r->state == SOCKS5_DATA_TRANSFER) &&
1588       (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK))
1589     s5r->fwdrtask =
1590       GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1591                                      s5r->remote_sock,
1592                                      &do_read_remote, s5r);
1593 }
1594
1595 /**
1596  * Read from remote end
1597  *
1598  * @param cls closure
1599  * @param tc scheduler context
1600  */
1601 static void
1602 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1603 {
1604   struct Socks5Request *s5r = cls;
1605   
1606   s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
1607
1608
1609   if ((NULL != tc->write_ready) &&
1610       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->remote_sock)) &&
1611       (s5r->wbuf_len = GNUNET_NETWORK_socket_recv (s5r->remote_sock, s5r->wbuf,
1612                                          sizeof (s5r->wbuf))))
1613   {
1614     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1615                 "Successfully read %d bytes from remote socket\n",
1616                 s5r->wbuf_len);
1617   }
1618   else
1619   {
1620     if (s5r->wbuf_len == 0)
1621       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1622                   "0 bytes received from remote... graceful shutdown!\n");
1623     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
1624       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
1625     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1626       GNUNET_SCHEDULER_cancel (s5r->rtask);
1627     
1628     GNUNET_NETWORK_socket_close (s5r->remote_sock);
1629     s5r->remote_sock = NULL;
1630     GNUNET_NETWORK_socket_close (s5r->sock);
1631     GNUNET_free(s5r);
1632
1633     return;
1634   }
1635   
1636   s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1637                                                s5r->sock,
1638                                                &do_write, s5r);
1639   
1640 }
1641
1642
1643 /**
1644  * Adds a socket to MHD
1645  *
1646  * @param h the handle to the socket to add
1647  * @param daemon the daemon to add the fd to
1648  * @return whatever MHD_add_connection returns
1649  */
1650 static int
1651 add_handle_to_mhd (struct GNUNET_NETWORK_Handle *h, struct MHD_Daemon *daemon)
1652 {
1653   int fd;
1654   struct sockaddr *addr;
1655   socklen_t len;
1656
1657   fd = dup (GNUNET_NETWORK_get_fd (h));
1658   addr = GNUNET_NETWORK_get_addr (h);
1659   len = GNUNET_NETWORK_get_addrlen (h);
1660
1661   return MHD_add_connection (daemon, fd, addr, len);
1662 }
1663
1664 /**
1665  * Calculate size of file
1666  *
1667  * @param filename name of file
1668  * @return filesize or 0 on error
1669  */
1670 static long
1671 get_file_size (const char* filename)
1672 {
1673   FILE *fp;
1674
1675   fp = fopen (filename, "rb");
1676   if (fp)
1677   {
1678     long size;
1679
1680     if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp))))
1681       size = 0;
1682
1683     fclose (fp);
1684
1685     return size;
1686   }
1687   
1688   return 0;
1689 }
1690
1691 /**
1692  * Read file in filename
1693  *
1694  * @param filename file to read
1695  * @param size pointer where filesize is stored
1696  * @return data
1697  */
1698 static char*
1699 load_file (const char* filename, unsigned int* size)
1700 {
1701   FILE *fp;
1702   char *buffer;
1703
1704   *size = get_file_size (filename);
1705   if (*size == 0)
1706     return NULL;
1707
1708   fp = fopen (filename, "rb");
1709   if (!fp)
1710     return NULL;
1711
1712   buffer = GNUNET_malloc (*size);
1713   if (!buffer)
1714   {
1715     fclose (fp);
1716     return NULL;
1717   }
1718
1719   if (*size != fread (buffer, 1, *size, fp))
1720   {
1721     GNUNET_free (buffer);
1722     buffer = NULL;
1723   }
1724
1725   fclose (fp);
1726   return buffer;
1727 }
1728
1729 /**
1730  * Load PEM key from file
1731  *
1732  * @param key where to store the data
1733  * @param keyfile path to the PEM file
1734  */
1735 static void
1736 load_key_from_file (gnutls_x509_privkey_t key, char* keyfile)
1737 {
1738   gnutls_datum_t key_data;
1739   key_data.data = NULL;
1740   int ret;
1741
1742   key_data.data = (unsigned char*)load_file (keyfile, &key_data.size);
1743
1744   ret = gnutls_x509_privkey_import (key, &key_data,
1745                                     GNUTLS_X509_FMT_PEM);
1746   
1747   if (GNUTLS_E_SUCCESS != ret)
1748   {
1749     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1750                 "Unable to import private key %s(ret=%d)\n", key_data.data, ret);
1751     GNUNET_break (0);
1752   }
1753
1754   GNUNET_free (key_data.data);
1755 }
1756
1757 /**
1758  * Load cert from file
1759  *
1760  * @param crt struct to store data in
1761  * @param certfile path to pem file
1762  */
1763 static void
1764 load_cert_from_file (gnutls_x509_crt_t crt, char* certfile)
1765 {
1766   gnutls_datum_t cert_data;
1767   cert_data.data = NULL;
1768   int ret;
1769
1770   cert_data.data = (unsigned char*)load_file (certfile, &cert_data.size);
1771
1772   ret = gnutls_x509_crt_import (crt, &cert_data,
1773                                  GNUTLS_X509_FMT_PEM);
1774   if (GNUTLS_E_SUCCESS != ret)
1775   {
1776     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1777                 "Unable to import certificate %s(ret=%d)\n", certfile, ret);
1778     GNUNET_break (0);
1779   }
1780
1781   GNUNET_free (cert_data.data);
1782
1783 }
1784
1785
1786 /**
1787  * Generate new certificate for specific name
1788  *
1789  * @param name the subject name to generate a cert for
1790  * @return a struct holding the PEM data
1791  */
1792 static struct ProxyGNSCertificate *
1793 generate_gns_certificate (const char *name)
1794 {
1795
1796   int ret;
1797   unsigned int serial;
1798   size_t key_buf_size;
1799   size_t cert_buf_size;
1800   gnutls_x509_crt_t request;
1801   time_t etime;
1802   struct tm *tm_data;
1803
1804   ret = gnutls_x509_crt_init (&request);
1805
1806   if (GNUTLS_E_SUCCESS != ret)
1807   {
1808     GNUNET_break (0);
1809   }
1810
1811   ret = gnutls_x509_crt_set_key (request, proxy_ca.key);
1812
1813   if (GNUTLS_E_SUCCESS != ret)
1814   {
1815     GNUNET_break (0);
1816   }
1817
1818   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generating cert\n");
1819
1820   struct ProxyGNSCertificate *pgc =
1821     GNUNET_malloc (sizeof (struct ProxyGNSCertificate));
1822
1823   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding DNs\n");
1824   
1825   gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_COUNTRY_NAME,
1826                                  0, "DE", 2);
1827
1828   gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_ORGANIZATION_NAME,
1829                                  0, "GNUnet", 6);
1830
1831   gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_COMMON_NAME,
1832                                  0, name, strlen (name));
1833
1834   ret = gnutls_x509_crt_set_version (request, 3);
1835
1836   ret = gnutls_rnd (GNUTLS_RND_NONCE, &serial, sizeof (serial));
1837
1838   etime = time (NULL);
1839   tm_data = localtime (&etime);
1840   
1841
1842   ret = gnutls_x509_crt_set_serial (request,
1843                                     &serial,
1844                                     sizeof (serial));
1845
1846   ret = gnutls_x509_crt_set_activation_time (request,
1847                                              etime);
1848   tm_data->tm_year++;
1849   etime = mktime (tm_data);
1850
1851   if (-1 == etime)
1852   {
1853     GNUNET_break (0);
1854   }
1855
1856   ret = gnutls_x509_crt_set_expiration_time (request,
1857                                              etime);
1858   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Signing...\n");
1859
1860   ret = gnutls_x509_crt_sign (request, proxy_ca.cert, proxy_ca.key);
1861
1862   key_buf_size = sizeof (pgc->key);
1863   cert_buf_size = sizeof (pgc->cert);
1864
1865   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exporting certificate...\n");
1866   
1867   gnutls_x509_crt_export (request, GNUTLS_X509_FMT_PEM,
1868                           pgc->cert, &cert_buf_size);
1869
1870   gnutls_x509_privkey_export (proxy_ca.key, GNUTLS_X509_FMT_PEM,
1871                           pgc->key, &key_buf_size);
1872
1873
1874   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
1875   gnutls_x509_crt_deinit (request);
1876
1877   return pgc;
1878
1879 }
1880
1881
1882 /*
1883  * Accept policy for mhdaemons
1884  *
1885  * @param cls NULL
1886  * @param addr the sockaddr
1887  * @param addrlen the sockaddr length
1888  * @return MHD_NO if sockaddr is wrong or #conns too high
1889  */
1890 static int
1891 accept_cb (void* cls, const struct sockaddr *addr, socklen_t addrlen)
1892 {
1893   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1894               "In MHD accept policy cb\n");
1895
1896   if (addr != NULL)
1897   {
1898     if (addr->sa_family == AF_UNIX)
1899       return MHD_NO;
1900   }
1901
1902   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1903               "Connection accepted\n");
1904
1905   return MHD_YES;
1906 }
1907
1908
1909 /**
1910  * Adds a socket to an SSL MHD instance
1911  * It is important the the domain name is
1912  * correct. In most cases we need to start a new daemon
1913  *
1914  * @param h the handle to add to a daemon
1915  * @param domain the domain the ssl daemon has to serve
1916  * @return MHD_YES on success
1917  */
1918 static int
1919 add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, char* domain)
1920 {
1921   struct MhdHttpList *hd = NULL;
1922   struct ProxyGNSCertificate *pgc;
1923   struct NetworkHandleList *nh;
1924
1925   for (hd = mhd_httpd_head; hd != NULL; hd = hd->next)
1926   {
1927     if (0 == strcmp (hd->domain, domain))
1928       break;
1929   }
1930
1931   if (NULL == hd)
1932   {
1933     
1934     pgc = generate_gns_certificate (domain);
1935     
1936     hd = GNUNET_malloc (sizeof (struct MhdHttpList));
1937     hd->is_ssl = GNUNET_YES;
1938     strcpy (hd->domain, domain);
1939     hd->proxy_cert = pgc;
1940
1941     /* Start new MHD */
1942     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1943                 "No previous SSL instance found... starting new one for %s\n",
1944                 domain);
1945
1946     hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL, 4444,
1947             &accept_cb, NULL,
1948             &create_response, hd,
1949             MHD_OPTION_LISTEN_SOCKET, GNUNET_NETWORK_get_fd (mhd_unix_socket),
1950             MHD_OPTION_CONNECTION_LIMIT, MHD_MAX_CONNECTIONS,
1951             MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
1952             MHD_OPTION_NOTIFY_COMPLETED,
1953             NULL, NULL,
1954             MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
1955             MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
1956             MHD_OPTION_END);
1957
1958     GNUNET_assert (hd->daemon != NULL);
1959     hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
1960     
1961     GNUNET_CONTAINER_DLL_insert (mhd_httpd_head, mhd_httpd_tail, hd);
1962   }
1963
1964   nh = GNUNET_malloc (sizeof (struct NetworkHandleList));
1965   nh->h = h;
1966
1967   GNUNET_CONTAINER_DLL_insert (hd->socket_handles_head,
1968                                hd->socket_handles_tail,
1969                                nh);
1970   
1971   return add_handle_to_mhd (h, hd->daemon);
1972 }
1973
1974
1975
1976 /**
1977  * Read data from incoming connection
1978  *
1979  * @param cls the closure
1980  * @param tc the scheduler context
1981  */
1982 static void
1983 do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1984 {
1985   struct Socks5Request *s5r = cls;
1986   struct socks5_client_hello *c_hello;
1987   struct socks5_server_hello *s_hello;
1988   struct socks5_client_request *c_req;
1989   struct socks5_server_response *s_resp;
1990
1991   int ret;
1992   char domain[256];
1993   uint8_t dom_len;
1994   uint16_t req_port;
1995   struct hostent *phost;
1996   uint32_t remote_ip;
1997   struct sockaddr_in remote_addr;
1998   struct in_addr *r_sin_addr;
1999
2000   struct NetworkHandleList *nh;
2001
2002   s5r->rtask = GNUNET_SCHEDULER_NO_TASK;
2003
2004   if ((NULL != tc->write_ready) &&
2005       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) &&
2006       (s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf,
2007                                          sizeof (s5r->rbuf))))
2008   {
2009     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2010                 "Successfully read %d bytes from socket\n",
2011                 s5r->rbuf_len);
2012   }
2013   else
2014   {
2015     if (s5r->rbuf_len != 0)
2016       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read");
2017     else
2018       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disco!\n");
2019
2020     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
2021       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
2022     if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
2023       GNUNET_SCHEDULER_cancel (s5r->wtask);
2024     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
2025       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
2026     GNUNET_NETWORK_socket_close (s5r->remote_sock);
2027     GNUNET_NETWORK_socket_close (s5r->sock);
2028     GNUNET_free(s5r);
2029     return;
2030   }
2031
2032   if (s5r->state == SOCKS5_INIT)
2033   {
2034     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2035                 "SOCKS5 init\n");
2036     c_hello = (struct socks5_client_hello*)&s5r->rbuf;
2037
2038     GNUNET_assert (c_hello->version == SOCKS_VERSION_5);
2039
2040     s_hello = (struct socks5_server_hello*)&s5r->wbuf;
2041     s5r->wbuf_len = sizeof( struct socks5_server_hello );
2042
2043     s_hello->version = c_hello->version;
2044     s_hello->auth_method = SOCKS_AUTH_NONE;
2045
2046     /* Write response to client */
2047     s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2048                                                 s5r->sock,
2049                                                 &do_write, s5r);
2050
2051     s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2052                                                 s5r->sock,
2053                                                 &do_read, s5r);
2054
2055     s5r->state = SOCKS5_REQUEST;
2056     return;
2057   }
2058
2059   if (s5r->state == SOCKS5_REQUEST)
2060   {
2061     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2062                 "Processing SOCKS5 request\n");
2063     c_req = (struct socks5_client_request*)&s5r->rbuf;
2064     s_resp = (struct socks5_server_response*)&s5r->wbuf;
2065     //Only 10byte for ipv4 response!
2066     s5r->wbuf_len = 10;//sizeof (struct socks5_server_response);
2067
2068     GNUNET_assert (c_req->addr_type == 3);
2069
2070     dom_len = *((uint8_t*)(&(c_req->addr_type) + 1));
2071     memset(domain, 0, sizeof(domain));
2072     strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len);
2073     req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len));
2074
2075     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076                 "Requested connection is %s:%d\n",
2077                 domain,
2078                 ntohs(req_port));
2079
2080     if (is_tld (domain, GNUNET_GNS_TLD) ||
2081         is_tld (domain, GNUNET_GNS_TLD_ZKEY))
2082     {
2083       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2084                   "Requested connection is gnunet tld\n",
2085                   domain);
2086       
2087       ret = MHD_NO;
2088       if (ntohs(req_port) == HTTPS_PORT)
2089       {
2090         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2091                     "Requested connection is HTTPS\n");
2092         ret = add_handle_to_ssl_mhd ( s5r->sock, domain );
2093       }
2094       else if (NULL != httpd)
2095       {
2096         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2097                     "Requested connection is HTTP\n");
2098         nh = GNUNET_malloc (sizeof (struct NetworkHandleList));
2099         nh->h = s5r->sock;
2100
2101         GNUNET_CONTAINER_DLL_insert (mhd_httpd_head->socket_handles_head,
2102                                mhd_httpd_head->socket_handles_tail,
2103                                nh);
2104
2105         ret = add_handle_to_mhd ( s5r->sock, httpd );
2106       }
2107
2108       if (ret != MHD_YES)
2109       {
2110         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2111                     _("Failed to start HTTP server\n"));
2112         s_resp->version = 0x05;
2113         s_resp->reply = 0x01;
2114         s5r->cleanup = GNUNET_YES;
2115         s5r->cleanup_sock = GNUNET_YES;
2116         s5r->wtask = 
2117           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2118                                         s5r->sock,
2119                                         &do_write, s5r);
2120         return;
2121       }
2122       
2123       /* Signal success */
2124       s_resp->version = 0x05;
2125       s_resp->reply = 0x00;
2126       s_resp->reserved = 0x00;
2127       s_resp->addr_type = 0x01;
2128       
2129       s5r->cleanup = GNUNET_YES;
2130       s5r->cleanup_sock = GNUNET_NO;
2131       s5r->wtask =
2132         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2133                                         s5r->sock,
2134                                         &do_write, s5r);
2135       run_httpds ();
2136       return;
2137     }
2138     else
2139     {
2140       phost = (struct hostent*)gethostbyname (domain);
2141       if (phost == NULL)
2142       {
2143         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2144                     "Resolve %s error!\n", domain );
2145         s_resp->version = 0x05;
2146         s_resp->reply = 0x01;
2147         s5r->cleanup = GNUNET_YES;
2148         s5r->cleanup_sock = GNUNET_YES;
2149         s5r->wtask = 
2150           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2151                                           s5r->sock,
2152                                           &do_write, s5r);
2153         return;
2154       }
2155
2156       s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET,
2157                                                        SOCK_STREAM,
2158                                                        0);
2159       r_sin_addr = (struct in_addr*)(phost->h_addr);
2160       remote_ip = r_sin_addr->s_addr;
2161       memset(&remote_addr, 0, sizeof(remote_addr));
2162       remote_addr.sin_family = AF_INET;
2163 #if HAVE_SOCKADDR_IN_SIN_LEN
2164       remote_addr.sin_len = sizeof (remote_addr);
2165 #endif
2166       remote_addr.sin_addr.s_addr = remote_ip;
2167       remote_addr.sin_port = req_port;
2168       
2169       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2170                   "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr),
2171                   ntohs(req_port));
2172
2173       if ((GNUNET_OK !=
2174           GNUNET_NETWORK_socket_connect ( s5r->remote_sock,
2175                                           (const struct sockaddr*)&remote_addr,
2176                                           sizeof (remote_addr)))
2177           && (errno != EINPROGRESS))
2178       {
2179         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
2180         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2181                     "socket request error...\n");
2182         s_resp->version = 0x05;
2183         s_resp->reply = 0x01;
2184         s5r->wtask =
2185           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2186                                           s5r->sock,
2187                                           &do_write, s5r);
2188         //TODO see above
2189         return;
2190       }
2191
2192       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2193                   "new remote connection\n");
2194
2195       s_resp->version = 0x05;
2196       s_resp->reply = 0x00;
2197       s_resp->reserved = 0x00;
2198       s_resp->addr_type = 0x01;
2199
2200       s5r->state = SOCKS5_DATA_TRANSFER;
2201
2202       s5r->wtask =
2203         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2204                                         s5r->sock,
2205                                         &do_write, s5r);
2206       s5r->rtask =
2207         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2208                                        s5r->sock,
2209                                        &do_read, s5r);
2210
2211     }
2212     return;
2213   }
2214
2215   if (s5r->state == SOCKS5_DATA_TRANSFER)
2216   {
2217     if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0))
2218     {
2219       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2220                   "Closing connection to client\n");
2221       if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
2222         GNUNET_SCHEDULER_cancel (s5r->rtask);
2223       if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
2224         GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
2225       if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
2226         GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
2227       if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
2228         GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
2229       
2230       if (s5r->remote_sock != NULL)
2231         GNUNET_NETWORK_socket_close (s5r->remote_sock);
2232       GNUNET_NETWORK_socket_close (s5r->sock);
2233       GNUNET_free(s5r);
2234       return;
2235     }
2236
2237     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2238                 "forwarding %d bytes from client\n", s5r->rbuf_len);
2239
2240     s5r->fwdwtask =
2241       GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2242                                       s5r->remote_sock,
2243                                       &do_write_remote, s5r);
2244
2245     if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK)
2246     {
2247       s5r->fwdrtask =
2248         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2249                                        s5r->remote_sock,
2250                                        &do_read_remote, s5r);
2251     }
2252
2253
2254   }
2255
2256   //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r);
2257
2258 }
2259
2260
2261 /**
2262  * Accept new incoming connections
2263  *
2264  * @param cls the closure
2265  * @param tc the scheduler context
2266  */
2267 static void
2268 do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2269 {
2270   struct GNUNET_NETWORK_Handle *s;
2271   struct Socks5Request *s5r;
2272
2273   ltask = GNUNET_SCHEDULER_NO_TASK;
2274   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2275     return;
2276
2277   ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2278                                          lsock,
2279                                          &do_accept, NULL);
2280
2281   s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
2282
2283   if (NULL == s)
2284   {
2285     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept");
2286     return;
2287   }
2288
2289   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2290               "Got an inbound connection, waiting for data\n");
2291
2292   s5r = GNUNET_malloc (sizeof (struct Socks5Request));
2293   s5r->sock = s;
2294   s5r->state = SOCKS5_INIT;
2295   s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
2296   s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
2297   s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
2298   s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2299                                               s5r->sock,
2300                                               &do_read, s5r);
2301   //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r);
2302 }
2303
2304
2305 /**
2306  * Task run on shutdown
2307  *
2308  * @param cls closure
2309  * @param tc task context
2310  */
2311 static void
2312 do_shutdown (void *cls,
2313              const struct GNUNET_SCHEDULER_TaskContext *tc)
2314 {
2315
2316   struct MhdHttpList *hd;
2317   struct MhdHttpList *tmp_hd;
2318   struct NetworkHandleList *nh;
2319   struct NetworkHandleList *tmp_nh;
2320   struct ProxyCurlTask *ctask;
2321   struct ProxyCurlTask *ctask_tmp;
2322   
2323   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2324               "Shutting down...\n");
2325
2326   gnutls_global_deinit ();
2327
2328   if (GNUNET_SCHEDULER_NO_TASK != curl_download_task)
2329   {
2330     GNUNET_SCHEDULER_cancel (curl_download_task);
2331     curl_download_task = GNUNET_SCHEDULER_NO_TASK;
2332   }
2333
2334   for (hd = mhd_httpd_head; hd != NULL; hd = tmp_hd)
2335   {
2336     tmp_hd = hd->next;
2337
2338     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2339                 "Stopping daemon\n");
2340
2341     if (GNUNET_SCHEDULER_NO_TASK != hd->httpd_task)
2342     {
2343       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2344                   "Stopping select task %d\n",
2345                   hd->httpd_task);
2346       GNUNET_SCHEDULER_cancel (hd->httpd_task);
2347       hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
2348     }
2349
2350     if (NULL != hd->daemon)
2351     {
2352       MHD_stop_daemon (hd->daemon);
2353       hd->daemon = NULL;
2354     }
2355
2356     for (nh = hd->socket_handles_head; nh != NULL; nh = tmp_nh)
2357     {
2358       tmp_nh = nh->next;
2359
2360       GNUNET_NETWORK_socket_close (nh->h);
2361
2362       GNUNET_free (nh);
2363     }
2364
2365     if (NULL != hd->proxy_cert)
2366     {
2367       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2368                   "Free certificate\n");
2369       GNUNET_free (hd->proxy_cert);
2370     }
2371
2372     GNUNET_free (hd);
2373   }
2374
2375   for (ctask=ctasks_head; ctask != NULL; ctask=ctask_tmp)
2376   {
2377     ctask_tmp = ctask->next;
2378
2379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2380                 "Cleaning up cURL task\n");
2381
2382     if (ctask->curl != NULL)
2383       curl_easy_cleanup (ctask->curl);
2384     ctask->curl = NULL;
2385     if (NULL != ctask->headers)
2386       curl_slist_free_all (ctask->headers);
2387     if (NULL != ctask->resolver)
2388       curl_slist_free_all (ctask->resolver);
2389
2390     if (NULL != ctask->response)
2391       MHD_destroy_response (ctask->response);
2392
2393
2394     GNUNET_free (ctask);
2395   }
2396
2397   GNUNET_GNS_disconnect (gns_handle);
2398 }
2399
2400
2401 /**
2402  * Compiles a regex for us
2403  *
2404  * @param re ptr to re struct
2405  * @param rt the expression to compile
2406  * @return 0 on success
2407  */
2408 static int
2409 compile_regex (regex_t *re, const char* rt)
2410 {
2411   int status;
2412   char err[1024];
2413
2414   status = regcomp (re, rt, REG_EXTENDED|REG_NEWLINE);
2415   if (status)
2416   {
2417     regerror (status, re, err, 1024);
2418     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2419                 "Regex error compiling '%s': %s\n", rt, err);
2420     return 1;
2421   }
2422   return 0;
2423 }
2424
2425
2426 /**
2427  * Loads the users local zone key
2428  *
2429  * @return GNUNET_YES on success
2430  */
2431 static int
2432 load_local_zone_key (const struct GNUNET_CONFIGURATION_Handle *cfg)
2433 {
2434   char *keyfile;
2435   struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL;
2436   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
2437   struct GNUNET_CRYPTO_ShortHashCode *zone = NULL;
2438   struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename;
2439
2440   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
2441                                                             "ZONEKEY", &keyfile))
2442   {
2443     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2444                 "Unable to load zone key config value!\n");
2445     return GNUNET_NO;
2446   }
2447
2448   if (GNUNET_NO == GNUNET_DISK_file_test (keyfile))
2449   {
2450     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2451                 "Unable to load zone key %s!\n", keyfile);
2452     GNUNET_free(keyfile);
2453     return GNUNET_NO;
2454   }
2455
2456   key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2457   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
2458   GNUNET_CRYPTO_short_hash(&pkey,
2459                            sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2460                            &local_gns_zone);
2461   zone = &local_gns_zone;
2462   GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename);
2463   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2464               "Using zone: %s!\n", &zonename);
2465   GNUNET_CRYPTO_rsa_key_free(key);
2466   GNUNET_free(keyfile);
2467   
2468   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
2469                                                    "PRIVATE_ZONEKEY", &keyfile))
2470   {
2471     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2472                 "Unable to load private zone key config value!\n");
2473     return GNUNET_NO;
2474   }
2475
2476   if (GNUNET_NO == GNUNET_DISK_file_test (keyfile))
2477   {
2478     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2479                 "Unable to load private zone key %s!\n", keyfile);
2480     GNUNET_free(keyfile);
2481     return GNUNET_NO;
2482   }
2483
2484   key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2485   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
2486   GNUNET_CRYPTO_short_hash(&pkey,
2487                            sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2488                            &local_private_zone);
2489   GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename);
2490   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2491               "Using private zone: %s!\n", &zonename);
2492   GNUNET_CRYPTO_rsa_key_free(key);
2493   GNUNET_free(keyfile);
2494
2495   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
2496                                                    "SHORTEN_ZONEKEY", &keyfile))
2497   {
2498     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2499                 "Unable to load shorten zone key config value!\n");
2500     return GNUNET_NO;
2501   }
2502
2503   if (GNUNET_NO == GNUNET_DISK_file_test (keyfile))
2504   {
2505     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2506                 "Unable to load shorten zone key %s!\n", keyfile);
2507     GNUNET_free(keyfile);
2508     return GNUNET_NO;
2509   }
2510
2511   key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2512   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
2513   GNUNET_CRYPTO_short_hash(&pkey,
2514                            sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2515                            &local_shorten_zone);
2516   GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename);
2517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2518               "Using shorten zone: %s!\n", &zonename);
2519   GNUNET_CRYPTO_rsa_key_free(key);
2520   GNUNET_free(keyfile);
2521
2522   return GNUNET_YES;
2523 }
2524
2525 /**
2526  * Main function that will be run
2527  *
2528  * @param cls closure
2529  * @param args remaining command-line arguments
2530  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
2531  * @param cfg configuration
2532  */
2533 static void
2534 run (void *cls, char *const *args, const char *cfgfile,
2535      const struct GNUNET_CONFIGURATION_Handle *cfg)
2536 {
2537   struct sockaddr_in sa;
2538   struct MhdHttpList *hd;
2539   struct sockaddr_un mhd_unix_sock_addr;
2540   size_t len;
2541   char* proxy_sockfile;
2542   char* cafile_cfg = NULL;
2543   char* cafile;
2544
2545   curl_multi = NULL;
2546
2547   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2548               "Loading CA\n");
2549   
2550   cafile = cafile_opt;
2551
2552   if (NULL == cafile)
2553   {
2554     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns-proxy",
2555                                                           "PROXY_CACERT",
2556                                                           &cafile_cfg))
2557     {
2558       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2559                   "Unable to load proxy CA config value!\n");
2560       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2561                   "No proxy CA provided!\n");
2562       return;
2563     }
2564     cafile = cafile_cfg;
2565   }
2566   
2567   gnutls_global_init ();
2568
2569   gnutls_x509_crt_init (&proxy_ca.cert);
2570   gnutls_x509_privkey_init (&proxy_ca.key);
2571   
2572   load_cert_from_file (proxy_ca.cert, cafile);
2573   load_key_from_file (proxy_ca.key, cafile);
2574
2575   GNUNET_free_non_null (cafile_cfg);
2576   
2577   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2578               "Loading Template\n");
2579   
2580   compile_regex (&re_dotplus, (char*) RE_A_HREF);
2581
2582   gns_handle = GNUNET_GNS_connect (cfg);
2583
2584   if (GNUNET_NO == load_local_zone_key (cfg))
2585   {
2586     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2587                 "Unable to load zone!\n");
2588     return;
2589   }
2590
2591   if (NULL == gns_handle)
2592   {
2593     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2594                 "Unable to connect to GNS!\n");
2595     return;
2596   }
2597
2598   memset (&sa, 0, sizeof (sa));
2599   sa.sin_family = AF_INET;
2600   sa.sin_port = htons (port);
2601 #if HAVE_SOCKADDR_IN_SIN_LEN
2602   sa.sin_len = sizeof (sa);
2603 #endif
2604
2605   lsock = GNUNET_NETWORK_socket_create (AF_INET,
2606                                         SOCK_STREAM,
2607                                         0);
2608
2609   if ((NULL == lsock) ||
2610       (GNUNET_OK !=
2611        GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &sa,
2612                                    sizeof (sa))))
2613   {
2614     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2615                 "Failed to create listen socket bound to `%s'",
2616                 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
2617     if (NULL != lsock)
2618       GNUNET_NETWORK_socket_close (lsock);
2619     return;
2620   }
2621
2622   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, 5))
2623   {
2624     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2625                 "Failed to listen on socket bound to `%s'",
2626                 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
2627     return;
2628   }
2629
2630   ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2631                                          lsock, &do_accept, NULL);
2632
2633   ctasks_head = NULL;
2634   ctasks_tail = NULL;
2635
2636   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
2637   {
2638     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2639                 "cURL global init failed!\n");
2640     return;
2641   }
2642
2643   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2644               "Proxy listens on port %u\n",
2645               port);
2646
2647   mhd_httpd_head = NULL;
2648   mhd_httpd_tail = NULL;
2649   total_mhd_connections = 0;
2650
2651   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns-proxy",
2652                                                             "PROXY_UNIXPATH",
2653                                                             &proxy_sockfile))
2654   {
2655     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2656                 "Specify PROXY_UNIXPATH in gns-proxy config section!\n");
2657     return;
2658   }
2659   
2660   mhd_unix_socket = GNUNET_NETWORK_socket_create (AF_UNIX,
2661                                                 SOCK_STREAM,
2662                                                 0);
2663
2664   if (NULL == mhd_unix_socket)
2665   {
2666     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2667                 "Unable to create unix domain socket!\n");
2668     return;
2669   }
2670
2671   mhd_unix_sock_addr.sun_family = AF_UNIX;
2672   strcpy (mhd_unix_sock_addr.sun_path, proxy_sockfile);
2673
2674 #if LINUX
2675   mhd_unix_sock_addr.sun_path[0] = '\0';
2676 #endif
2677 #if HAVE_SOCKADDR_IN_SIN_LEN
2678   mhd_unix_sock_addr.sun_len = (u_char) sizeof (struct sockaddr_un);
2679 #endif
2680
2681   len = strlen (proxy_sockfile) + sizeof(AF_UNIX);
2682
2683   GNUNET_free (proxy_sockfile);
2684
2685   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (mhd_unix_socket,
2686                                (struct sockaddr*)&mhd_unix_sock_addr,
2687                                len))
2688   {
2689     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2690                 "Unable to bind unix domain socket!\n");
2691     return;
2692   }
2693
2694   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (mhd_unix_socket,
2695                                                  1))
2696   {
2697     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2698                 "Unable to listen on unix domain socket!\n");
2699     return;
2700   }
2701
2702   hd = GNUNET_malloc (sizeof (struct MhdHttpList));
2703   hd->is_ssl = GNUNET_NO;
2704   strcpy (hd->domain, "");
2705   httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444, //Dummy port
2706             &accept_cb, NULL,
2707             &create_response, hd,
2708             MHD_OPTION_LISTEN_SOCKET, GNUNET_NETWORK_get_fd (mhd_unix_socket),
2709             MHD_OPTION_CONNECTION_LIMIT, MHD_MAX_CONNECTIONS,
2710             MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
2711             MHD_OPTION_NOTIFY_COMPLETED,
2712             NULL, NULL,
2713             MHD_OPTION_END);
2714
2715   GNUNET_assert (httpd != NULL);
2716   hd->daemon = httpd;
2717   hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
2718
2719   GNUNET_CONTAINER_DLL_insert (mhd_httpd_head, mhd_httpd_tail, hd);
2720
2721   run_httpds ();
2722
2723   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2724                                 &do_shutdown, NULL);
2725
2726 }
2727
2728
2729 /**
2730  * The main function for gnunet-gns-proxy.
2731  *
2732  * @param argc number of arguments from the command line
2733  * @param argv command line arguments
2734  * @return 0 ok, 1 on error
2735  */
2736 int
2737 main (int argc, char *const *argv)
2738 {
2739   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
2740     {'p', "port", NULL,
2741      gettext_noop ("listen on specified port"), 1,
2742      &GNUNET_GETOPT_set_string, &port},
2743     {'a', "authority", NULL,
2744       gettext_noop ("pem file to use as CA"), 1,
2745       &GNUNET_GETOPT_set_string, &cafile_opt},
2746     GNUNET_GETOPT_OPTION_END
2747   };
2748
2749   int ret;
2750
2751   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2752     return 2;
2753
2754
2755   GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL);
2756   ret =
2757       (GNUNET_OK ==
2758        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy",
2759                            _("GNUnet GNS proxy"),
2760                            options,
2761                            &run, NULL)) ? 0 : 1;
2762   GNUNET_free_non_null ((char*)argv);
2763
2764   return ret;
2765 }