cbc12ed02653daa4813fac487a0941c296ad8380
[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 <microhttpd.h>
24 #include "gns_proxy_proto.h"
25 #include "gns.h"
26
27 #define GNUNET_GNS_PROXY_PORT 7777
28
29 //TODO maybe make this an api call
30 /**
31  * Checks if name is in tld
32  *
33  * @param name the name to check
34  * @param tld the TLD to check for
35  * @return GNUNET_YES or GNUNET_NO
36  */
37 int
38 is_tld(const char* name, const char* tld)
39 {
40   int offset = 0;
41
42   if (strlen(name) <= strlen(tld))
43   {
44     return GNUNET_NO;
45   }
46
47   offset = strlen(name)-strlen(tld);
48   if (strcmp (name+offset, tld) != 0)
49   {
50     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
51                "%s is not in .%s TLD\n", name, tld);
52     return GNUNET_NO;
53   }
54
55   return GNUNET_YES;
56 }
57
58 struct Socks5Request
59 {
60   struct GNUNET_NETWORK_Handle *sock;
61   struct GNUNET_NETWORK_Handle *remote_sock;
62
63   int state;
64
65   GNUNET_SCHEDULER_TaskIdentifier rtask;
66   GNUNET_SCHEDULER_TaskIdentifier fwdrtask;
67   GNUNET_SCHEDULER_TaskIdentifier wtask;
68   GNUNET_SCHEDULER_TaskIdentifier fwdwtask;
69
70   char rbuf[2048];
71   char wbuf[2048];
72   unsigned int rbuf_len;
73   unsigned int wbuf_len;
74 };
75
76 unsigned long port = GNUNET_GNS_PROXY_PORT;
77 static struct GNUNET_NETWORK_Handle *lsock;
78 GNUNET_SCHEDULER_TaskIdentifier ltask;
79 static struct MHD_Daemon *httpd;
80 static GNUNET_SCHEDULER_TaskIdentifier httpd_task;
81
82 /**
83  * Main MHD callback for handling requests.
84  *
85  * @param cls unused
86  * @param connection MHD connection handle
87  * @param method the HTTP method used ("GET", "PUT", etc.)
88  * @param version the HTTP version string (i.e. "HTTP/1.1")
89  * @param upload_data the data being uploaded (excluding HEADERS,
90  *        for a POST that fits into memory and that is encoded
91  *        with a supported encoding, the POST data will NOT be
92  *        given in upload_data and is instead available as
93  *        part of MHD_get_connection_values; very large POST
94  *        data *will* be made available incrementally in
95  *        upload_data)
96  * @param upload_data_size set initially to the size of the
97  *        upload_data provided; the method must update this
98  *        value to the number of bytes NOT processed;
99  * @param ptr pointer to location where we store the 'struct Request'
100  * @return MHD_YES if the connection was handled successfully,
101  *         MHD_NO if the socket must be closed due to a serious
102  *         error while handling the request
103  */
104 static int
105 create_response (void *cls,
106                  struct MHD_Connection *con,
107                  const char *url,
108                  const char *meth,
109                  const char *ver,
110                  const char *upload_data,
111                  size_t *upload_data_size,
112                  void **con_cls)
113 {
114   static int dummy;
115   const char* page = "<html><head><title>gnoxy</title>"\
116                       "</head><body>gnoxy demo</body></html>";
117   struct MHD_Response *response;
118   int ret;
119   
120   if (0 != strcmp (meth, "GET"))
121     return MHD_NO;
122   if (&dummy != *con_cls)
123   {
124     *con_cls = &dummy;
125     return MHD_YES;
126   }
127
128   if (0 != *upload_data_size)
129     return MHD_NO;
130
131   *con_cls = NULL;
132
133   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
134               "url %s\n", url);
135
136   response = MHD_create_response_from_buffer (strlen (page),
137                                               (void*)page,
138                                               MHD_RESPMEM_PERSISTENT);
139   ret = MHD_queue_response (con,
140                             MHD_HTTP_OK,
141                             response);
142   MHD_destroy_response (response);
143   return ret;
144 }
145
146 /**
147  * Task run whenever HTTP server operations are pending.
148  *
149  * @param cls unused
150  * @param tc sched context
151  */
152 static void
153 do_httpd (void *cls,
154           const struct GNUNET_SCHEDULER_TaskContext *tc);
155
156 /**
157  * Schedule MHD
158  */
159 static void
160 run_httpd ()
161 {
162   fd_set rs;
163   fd_set ws;
164   fd_set es;
165   struct GNUNET_NETWORK_FDSet *wrs;
166   struct GNUNET_NETWORK_FDSet *wws;
167   struct GNUNET_NETWORK_FDSet *wes;
168   int max;
169   int haveto;
170   unsigned MHD_LONG_LONG timeout;
171   struct GNUNET_TIME_Relative tv;
172
173   FD_ZERO (&rs);
174   FD_ZERO (&ws);
175   FD_ZERO (&es);
176   wrs = GNUNET_NETWORK_fdset_create ();
177   wes = GNUNET_NETWORK_fdset_create ();
178   wws = GNUNET_NETWORK_fdset_create ();
179   max = -1;
180   GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
181   haveto = MHD_get_timeout (httpd, &timeout);
182
183   if (haveto == MHD_YES)
184     tv.rel_value = (uint64_t) timeout;
185   else
186     tv = GNUNET_TIME_UNIT_FOREVER_REL;
187   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
188   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
189   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
190   
191   if (httpd_task != GNUNET_SCHEDULER_NO_TASK)
192     GNUNET_SCHEDULER_cancel (httpd_task);
193   httpd_task =
194     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
195                                  tv, wrs, wws,
196                                  &do_httpd, NULL);
197   GNUNET_NETWORK_fdset_destroy (wrs);
198   GNUNET_NETWORK_fdset_destroy (wws);
199   GNUNET_NETWORK_fdset_destroy (wes);
200 }
201
202 /**
203  * Task run whenever HTTP server operations are pending.
204  *
205  * @param cls unused
206  * @param tc sched context
207  */
208 static void
209 do_httpd (void *cls,
210           const struct GNUNET_SCHEDULER_TaskContext *tc)
211 {
212   httpd_task = GNUNET_SCHEDULER_NO_TASK;
213   MHD_run (httpd);
214   run_httpd ();
215 }
216
217 /**
218  * Read data from socket
219  *
220  * @param cls the closure
221  * @param tc scheduler context
222  */
223 static void
224 do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
225
226 /**
227  * Read from remote end
228  *
229  * @param cls closure
230  * @param tc scheduler context
231  */
232 static void
233 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
234
235 /**
236  * Write data to remote socket
237  *
238  * @param cls the closure
239  * @param tc scheduler context
240  */
241 static void
242 do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
243 {
244   struct Socks5Request *s5r = cls;
245   unsigned int len;
246
247   s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
248
249   if ((NULL != tc->read_ready) &&
250       (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->remote_sock)) &&
251       (len = GNUNET_NETWORK_socket_send (s5r->remote_sock, s5r->rbuf,
252                                          s5r->rbuf_len)))
253   {
254     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255                 "Successfully sent %d bytes to remote socket\n",
256                 len);
257   }
258   else
259   {
260     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote");
261     //Really!?!?!?
262     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
263       GNUNET_SCHEDULER_cancel (s5r->rtask);
264     if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
265       GNUNET_SCHEDULER_cancel (s5r->wtask);
266     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
267       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
268     GNUNET_NETWORK_socket_close (s5r->remote_sock);
269     GNUNET_NETWORK_socket_close (s5r->sock);
270     GNUNET_free(s5r);
271     return;
272   }
273
274   s5r->rtask =
275     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
276                                    s5r->sock,
277                                    &do_read, s5r);
278 }
279
280
281 /**
282  * Write data to socket
283  *
284  * @param cls the closure
285  * @param tc scheduler context
286  */
287 static void
288 do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
289 {
290   struct Socks5Request *s5r = cls;
291   unsigned int len;
292
293   s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
294
295   if ((NULL != tc->read_ready) &&
296       (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) &&
297       (len = GNUNET_NETWORK_socket_send (s5r->sock, s5r->wbuf,
298                                          s5r->wbuf_len)))
299   {
300     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
301                 "Successfully sent %d bytes to socket\n",
302                 len);
303   }
304   else
305   {
306     
307     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
308     //Really!?!?!?
309     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
310       GNUNET_SCHEDULER_cancel (s5r->rtask);
311     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
312       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
313     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
314       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
315     GNUNET_NETWORK_socket_close (s5r->remote_sock);
316     GNUNET_NETWORK_socket_close (s5r->sock);
317     GNUNET_free(s5r);
318     return;
319   }
320
321   if ((s5r->state == SOCKS5_DATA_TRANSFER) &&
322       (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK))
323     s5r->fwdrtask =
324       GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
325                                      s5r->remote_sock,
326                                      &do_read_remote, s5r);
327 }
328
329 /**
330  * Read from remote end
331  *
332  * @param cls closure
333  * @param tc scheduler context
334  */
335 static void
336 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
337 {
338   struct Socks5Request *s5r = cls;
339   
340   s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
341
342
343   if ((NULL != tc->write_ready) &&
344       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->remote_sock)) &&
345       (s5r->wbuf_len = GNUNET_NETWORK_socket_recv (s5r->remote_sock, s5r->wbuf,
346                                          sizeof (s5r->wbuf))))
347   {
348     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
349                 "Successfully read %d bytes from remote socket\n",
350                 s5r->wbuf_len);
351   }
352   else
353   {
354     if (s5r->wbuf_len == 0)
355       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
356                   "0 bytes received from remote... graceful shutdown!\n");
357     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
358       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
359     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
360       GNUNET_SCHEDULER_cancel (s5r->rtask);
361     
362     GNUNET_NETWORK_socket_close (s5r->remote_sock);
363     s5r->remote_sock = NULL;
364     GNUNET_NETWORK_socket_close (s5r->sock);
365     GNUNET_free(s5r);
366
367     return;
368   }
369   
370   s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
371                                                s5r->sock,
372                                                &do_write, s5r);
373   
374 }
375
376
377 static int
378 add_handle_to_mhd (struct GNUNET_NETWORK_Handle *h)
379 {
380   int fd;
381   struct sockaddr *addr;
382   socklen_t len;
383
384   fd = GNUNET_NETWORK_get_fd (h);
385   addr = GNUNET_NETWORK_get_addr (h);
386   len = GNUNET_NETWORK_get_addrlen (h);
387
388   return MHD_add_connection (httpd, fd, addr, len);
389 }
390
391 /**
392  * Read data from incoming connection
393  *
394  * @param cls the closure
395  * @param tc the scheduler context
396  */
397 static void
398 do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
399 {
400   struct Socks5Request *s5r = cls;
401   struct socks5_client_hello *c_hello;
402   struct socks5_server_hello *s_hello;
403   struct socks5_client_request *c_req;
404   struct socks5_server_response *s_resp;
405
406   char domain[256];
407   uint8_t dom_len;
408   uint16_t req_port;
409   struct hostent *phost;
410   uint32_t remote_ip;
411   struct sockaddr_in remote_addr;
412   struct in_addr *r_sin_addr;
413
414   s5r->rtask = GNUNET_SCHEDULER_NO_TASK;
415
416   if ((NULL != tc->write_ready) &&
417       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) &&
418       (s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf,
419                                          sizeof (s5r->rbuf))))
420   {
421     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
422                 "Successfully read %d bytes from socket\n",
423                 s5r->rbuf_len);
424   }
425   else
426   {
427     if (s5r->rbuf_len != 0)
428       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read");
429     else
430       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disco!\n");
431
432     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
433       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
434     if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
435       GNUNET_SCHEDULER_cancel (s5r->wtask);
436     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
437       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
438     GNUNET_NETWORK_socket_close (s5r->remote_sock);
439     GNUNET_NETWORK_socket_close (s5r->sock);
440     GNUNET_free(s5r);
441     return;
442   }
443
444   if (s5r->state == SOCKS5_INIT)
445   {
446     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447                 "SOCKS5 init\n");
448     c_hello = (struct socks5_client_hello*)&s5r->rbuf;
449
450     GNUNET_assert (c_hello->version == SOCKS_VERSION_5);
451
452     s_hello = (struct socks5_server_hello*)&s5r->wbuf;
453     s5r->wbuf_len = sizeof( struct socks5_server_hello );
454
455     s_hello->version = c_hello->version;
456     s_hello->auth_method = SOCKS_AUTH_NONE;
457
458     /* Write response to client */
459     s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
460                                                 s5r->sock,
461                                                 &do_write, s5r);
462
463     s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
464                                                 s5r->sock,
465                                                 &do_read, s5r);
466
467     s5r->state = SOCKS5_REQUEST;
468     return;
469   }
470
471   if (s5r->state == SOCKS5_REQUEST)
472   {
473     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474                 "Processing SOCKS5 request\n");
475     c_req = (struct socks5_client_request*)&s5r->rbuf;
476     s_resp = (struct socks5_server_response*)&s5r->wbuf;
477     //Only 10byte for ipv4 response!
478     s5r->wbuf_len = 10;//sizeof (struct socks5_server_response);
479
480     GNUNET_assert (c_req->addr_type == 3);
481
482     dom_len = *((uint8_t*)(&(c_req->addr_type) + 1));
483     memset(domain, 0, sizeof(domain));
484     strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len);
485     req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len));
486
487     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488                 "Requested connection is %s:%d\n",
489                 domain,
490                 ntohs(req_port));
491
492     if (is_tld (domain, GNUNET_GNS_TLD) ||
493         is_tld (domain, GNUNET_GNS_TLD_ZKEY))
494     {
495       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496                   "Requested connection is gnunet tld\n",
497                   domain);
498
499       if (NULL == httpd)
500       {
501         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
502                     _("Failed to start HTTP server\n"));
503         s_resp->version = 0x05;
504         s_resp->reply = 0x01;
505         s5r->wtask = 
506           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
507                                         s5r->sock,
508                                         &do_write, s5r);
509         //ERROR!
510         //TODO! close socket after the write! schedule task
511         //GNUNET_NETWORK_socket_close (s5r->sock);
512         //GNUNET_free(s5r);
513         return;
514       }
515
516       if (MHD_YES == add_handle_to_mhd ( s5r->sock ))
517         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518                     "Sucessfully added client to MHD!\n");
519       s_resp->version = 0x05;
520       s_resp->reply = 0x00;
521       s_resp->reserved = 0x00;
522       s_resp->addr_type = 0x01;
523
524       s5r->wtask =
525         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
526                                         s5r->sock,
527                                         &do_write, s5r);
528       run_httpd ();
529       //GNUNET_free ( s5r );
530       //FIXME complete socks resp!
531       return;
532     }
533     else
534     {
535       phost = (struct hostent*)gethostbyname (domain);
536       if (phost == NULL)
537       {
538         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539                     "Resolve %s error!\n", domain );
540         s_resp->version = 0x05;
541         s_resp->reply = 0x01;
542         s5r->wtask = 
543           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
544                                           s5r->sock,
545                                           &do_write, s5r);
546         //ERROR!
547         //TODO! close socket after the write! schedule task
548         //GNUNET_NETWORK_socket_close (s5r->sock);
549         //GNUNET_free(s5r);
550         return;
551       }
552
553       s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET,
554                                                        SOCK_STREAM,
555                                                        0);
556       r_sin_addr = (struct in_addr*)(phost->h_addr);
557       remote_ip = r_sin_addr->s_addr;
558       memset(&remote_addr, 0, sizeof(remote_addr));
559       remote_addr.sin_family = AF_INET;
560 #if HAVE_SOCKADDR_IN_SIN_LEN
561       remote_addr.sin_len = sizeof (remote_addr);
562 #endif
563       remote_addr.sin_addr.s_addr = remote_ip;
564       remote_addr.sin_port = req_port;
565       
566       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567                   "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr),
568                   ntohs(req_port));
569
570       if ((GNUNET_OK !=
571           GNUNET_NETWORK_socket_connect ( s5r->remote_sock,
572                                           (const struct sockaddr*)&remote_addr,
573                                           sizeof (remote_addr)))
574           && (errno != EINPROGRESS))
575       {
576         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
577         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
578                     "socket request error...\n");
579         s_resp->version = 0x05;
580         s_resp->reply = 0x01;
581         s5r->wtask =
582           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
583                                           s5r->sock,
584                                           &do_write, s5r);
585         //TODO see above
586         return;
587       }
588
589       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590                   "new remote connection\n");
591
592       s_resp->version = 0x05;
593       s_resp->reply = 0x00;
594       s_resp->reserved = 0x00;
595       s_resp->addr_type = 0x01;
596
597       s5r->state = SOCKS5_DATA_TRANSFER;
598
599       s5r->wtask =
600         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
601                                         s5r->sock,
602                                         &do_write, s5r);
603       s5r->rtask =
604         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
605                                        s5r->sock,
606                                        &do_read, s5r);
607
608     }
609     return;
610   }
611
612   if (s5r->state == SOCKS5_DATA_TRANSFER)
613   {
614     if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0))
615     {
616       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
617                   "Closing connection to client\n");
618       if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
619         GNUNET_SCHEDULER_cancel (s5r->rtask);
620       if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
621         GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
622       if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
623         GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
624       if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
625         GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
626       
627       if (s5r->remote_sock != NULL)
628         GNUNET_NETWORK_socket_close (s5r->remote_sock);
629       GNUNET_NETWORK_socket_close (s5r->sock);
630       GNUNET_free(s5r);
631       return;
632     }
633
634     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635                 "forwarding %d bytes from client\n", s5r->rbuf_len);
636
637     s5r->fwdwtask =
638       GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
639                                       s5r->remote_sock,
640                                       &do_write_remote, s5r);
641
642     if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK)
643     {
644       s5r->fwdrtask =
645         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
646                                        s5r->remote_sock,
647                                        &do_read_remote, s5r);
648     }
649
650
651   }
652
653   //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r);
654
655 }
656
657 /**
658  * Accept new incoming connections
659  *
660  * @param cls the closure
661  * @param tc the scheduler context
662  */
663 static void
664 do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
665 {
666   struct GNUNET_NETWORK_Handle *s;
667   struct Socks5Request *s5r;
668
669   ltask = GNUNET_SCHEDULER_NO_TASK;
670   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
671     return;
672
673   ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
674                                          lsock,
675                                          &do_accept, NULL);
676
677   s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
678
679   if (NULL == s)
680   {
681     GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept");
682     return;
683   }
684
685   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686               "Got an inbound connection, waiting for data\n");
687
688   s5r = GNUNET_malloc (sizeof (struct Socks5Request));
689   s5r->sock = s;
690   s5r->state = SOCKS5_INIT;
691   s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
692   s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
693   s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
694   s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
695                                               s5r->sock,
696                                               &do_read, s5r);
697   //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r);
698 }
699
700 /**
701  * Main function that will be run
702  *
703  * @param cls closure
704  * @param args remaining command-line arguments
705  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
706  * @param cfg configuration
707  */
708 static void
709 run (void *cls, char *const *args, const char *cfgfile,
710      const struct GNUNET_CONFIGURATION_Handle *cfg)
711 {
712   struct sockaddr_in sa;
713
714   memset (&sa, 0, sizeof (sa));
715   sa.sin_family = AF_INET;
716   sa.sin_port = htons (port);
717 #if HAVE_SOCKADDR_IN_SIN_LEN
718   sa.sin_len = sizeof (sa);
719 #endif
720
721   lsock = GNUNET_NETWORK_socket_create (AF_INET,
722                                         SOCK_STREAM,
723                                         0);
724
725   if ((NULL == lsock) ||
726       (GNUNET_OK !=
727        GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &sa,
728                                    sizeof (sa))))
729   {
730     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
731                 "Failed to create listen socket bound to `%s'",
732                 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
733     if (NULL != lsock)
734       GNUNET_NETWORK_socket_close (lsock);
735     return;
736   }
737
738   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, 5))
739   {
740     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
741                 "Failed to listen on socket bound to `%s'",
742                 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
743     return;
744   }
745
746   ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
747                                          lsock, &do_accept, NULL);
748
749   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750               "Proxy listens on port %u\n",
751               port);
752   
753   httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444,
754                                NULL, NULL,
755                                &create_response, NULL,
756                                MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
757                                MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
758                                MHD_OPTION_NOTIFY_COMPLETED,
759                                NULL, NULL,
760                                MHD_OPTION_END);
761   run_httpd ();
762
763 }
764
765 /**
766  * The main function for gnunet-gns-proxy.
767  *
768  * @param argc number of arguments from the command line
769  * @param argv command line arguments
770  * @return 0 ok, 1 on error
771  */
772 int
773 main (int argc, char *const *argv)
774 {
775   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
776     {'p', "port", NULL,
777      gettext_noop ("listen on specified port"), 1,
778      &GNUNET_GETOPT_set_string, &port},
779     GNUNET_GETOPT_OPTION_END
780   };
781
782   int ret;
783
784   GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL);
785   ret =
786       (GNUNET_OK ==
787        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy",
788                            _("GNUnet GNS proxy"),
789                            options,
790                            &run, NULL)) ? 0 : 1;
791   return ret;
792 }