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