-fix, mhd start
[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   httpd_task =
191     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
192                                  tv, wrs, wws,
193                                  &do_httpd, NULL);
194   GNUNET_NETWORK_fdset_destroy (wrs);
195   GNUNET_NETWORK_fdset_destroy (wws);
196   GNUNET_NETWORK_fdset_destroy (wes);
197 }
198
199 /**
200  * Task run whenever HTTP server operations are pending.
201  *
202  * @param cls unused
203  * @param tc sched context
204  */
205 static void
206 do_httpd (void *cls,
207           const struct GNUNET_SCHEDULER_TaskContext *tc)
208 {
209   httpd_task = GNUNET_SCHEDULER_NO_TASK;
210   MHD_run (httpd);
211   run_httpd ();
212 }
213
214 /**
215  * Read data from socket
216  *
217  * @param cls the closure
218  * @param tc scheduler context
219  */
220 static void
221 do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
222
223 /**
224  * Read from remote end
225  *
226  * @param cls closure
227  * @param tc scheduler context
228  */
229 static void
230 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
231
232 /**
233  * Write data to remote socket
234  *
235  * @param cls the closure
236  * @param tc scheduler context
237  */
238 static void
239 do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
240 {
241   struct Socks5Request *s5r = cls;
242   unsigned int len;
243
244   s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
245
246   if ((NULL != tc->read_ready) &&
247       (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->remote_sock)) &&
248       (len = GNUNET_NETWORK_socket_send (s5r->remote_sock, s5r->rbuf,
249                                          s5r->rbuf_len)))
250   {
251     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252                 "Successfully sent %d bytes to remote socket\n",
253                 len);
254   }
255   else
256   {
257     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote");
258     //Really!?!?!?
259     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
260       GNUNET_SCHEDULER_cancel (s5r->rtask);
261     if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
262       GNUNET_SCHEDULER_cancel (s5r->wtask);
263     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
264       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
265     GNUNET_NETWORK_socket_close (s5r->remote_sock);
266     GNUNET_NETWORK_socket_close (s5r->sock);
267     GNUNET_free(s5r);
268     return;
269   }
270
271   s5r->rtask =
272     GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
273                                    s5r->sock,
274                                    &do_read, s5r);
275 }
276
277
278 /**
279  * Write data to socket
280  *
281  * @param cls the closure
282  * @param tc scheduler context
283  */
284 static void
285 do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
286 {
287   struct Socks5Request *s5r = cls;
288   unsigned int len;
289
290   s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
291
292   if ((NULL != tc->read_ready) &&
293       (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) &&
294       (len = GNUNET_NETWORK_socket_send (s5r->sock, s5r->wbuf,
295                                          s5r->wbuf_len)))
296   {
297     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298                 "Successfully sent %d bytes to socket\n",
299                 len);
300   }
301   else
302   {
303     
304     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
305     //Really!?!?!?
306     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
307       GNUNET_SCHEDULER_cancel (s5r->rtask);
308     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
309       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
310     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
311       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
312     GNUNET_NETWORK_socket_close (s5r->remote_sock);
313     GNUNET_NETWORK_socket_close (s5r->sock);
314     GNUNET_free(s5r);
315     return;
316   }
317
318   if ((s5r->state == SOCKS5_DATA_TRANSFER) &&
319       (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK))
320     s5r->fwdrtask =
321       GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
322                                      s5r->remote_sock,
323                                      &do_read_remote, s5r);
324 }
325
326 /**
327  * Read from remote end
328  *
329  * @param cls closure
330  * @param tc scheduler context
331  */
332 static void
333 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
334 {
335   struct Socks5Request *s5r = cls;
336   
337   s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
338
339
340   if ((NULL != tc->write_ready) &&
341       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->remote_sock)) &&
342       (s5r->wbuf_len = GNUNET_NETWORK_socket_recv (s5r->remote_sock, s5r->wbuf,
343                                          sizeof (s5r->wbuf))))
344   {
345     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
346                 "Successfully read %d bytes from remote socket\n",
347                 s5r->wbuf_len);
348   }
349   else
350   {
351     if (s5r->wbuf_len == 0)
352       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353                   "0 bytes received from remote... graceful shutdown!\n");
354     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
355       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
356     if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
357       GNUNET_SCHEDULER_cancel (s5r->rtask);
358     
359     GNUNET_NETWORK_socket_close (s5r->remote_sock);
360     s5r->remote_sock = NULL;
361     GNUNET_NETWORK_socket_close (s5r->sock);
362     GNUNET_free(s5r);
363
364     return;
365   }
366   
367   s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
368                                                s5r->sock,
369                                                &do_write, s5r);
370   
371 }
372
373
374
375 /**
376  * Read data from incoming connection
377  *
378  * @param cls the closure
379  * @param tc the scheduler context
380  */
381 static void
382 do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
383 {
384   struct Socks5Request *s5r = cls;
385   struct socks5_client_hello *c_hello;
386   struct socks5_server_hello *s_hello;
387   struct socks5_client_request *c_req;
388   struct socks5_server_response *s_resp;
389
390   char domain[256];
391   uint8_t dom_len;
392   uint16_t req_port;
393   struct hostent *phost;
394   uint32_t remote_ip;
395   struct sockaddr_in remote_addr;
396   struct in_addr *r_sin_addr;
397
398   s5r->rtask = GNUNET_SCHEDULER_NO_TASK;
399
400   if ((NULL != tc->write_ready) &&
401       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) &&
402       (s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf,
403                                          sizeof (s5r->rbuf))))
404   {
405     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406                 "Successfully read %d bytes from socket\n",
407                 s5r->rbuf_len);
408   }
409   else
410   {
411     if (s5r->rbuf_len != 0)
412       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read");
413     else
414       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disco!\n");
415
416     if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
417       GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
418     if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
419       GNUNET_SCHEDULER_cancel (s5r->wtask);
420     if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
421       GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
422     GNUNET_NETWORK_socket_close (s5r->remote_sock);
423     GNUNET_NETWORK_socket_close (s5r->sock);
424     GNUNET_free(s5r);
425     return;
426   }
427
428   if (s5r->state == SOCKS5_INIT)
429   {
430     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431                 "SOCKS5 init\n");
432     c_hello = (struct socks5_client_hello*)&s5r->rbuf;
433
434     GNUNET_assert (c_hello->version == SOCKS_VERSION_5);
435
436     s_hello = (struct socks5_server_hello*)&s5r->wbuf;
437     s5r->wbuf_len = sizeof( struct socks5_server_hello );
438
439     s_hello->version = c_hello->version;
440     s_hello->auth_method = SOCKS_AUTH_NONE;
441
442     /* Write response to client */
443     s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
444                                                 s5r->sock,
445                                                 &do_write, s5r);
446
447     s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
448                                                 s5r->sock,
449                                                 &do_read, s5r);
450
451     s5r->state = SOCKS5_REQUEST;
452     return;
453   }
454
455   if (s5r->state == SOCKS5_REQUEST)
456   {
457     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458                 "Processing SOCKS5 request\n");
459     c_req = (struct socks5_client_request*)&s5r->rbuf;
460     s_resp = (struct socks5_server_response*)&s5r->wbuf;
461     //Only 10byte for ipv4 response!
462     s5r->wbuf_len = 10;//sizeof (struct socks5_server_response);
463
464     GNUNET_assert (c_req->addr_type == 3);
465
466     dom_len = *((uint8_t*)(&(c_req->addr_type) + 1));
467     memset(domain, 0, sizeof(domain));
468     strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len);
469     req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len));
470
471     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472                 "Requested connection is %s:%d\n",
473                 domain,
474                 ntohs(req_port));
475
476     if (is_tld (domain, GNUNET_GNS_TLD) ||
477         is_tld (domain, GNUNET_GNS_TLD_ZKEY))
478     {
479       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
480                   "Requested connection is gnunet tld\n",
481                   domain);
482
483       if (httpd == NULL)
484       {
485         
486
487         if (NULL == httpd)
488         {
489           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
490                       _("Failed to start HTTP server\n"));
491           s_resp->version = 0x05;
492           s_resp->reply = 0x01;
493           s5r->wtask = 
494             GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
495                                           s5r->sock,
496                                           &do_write, s5r);
497           //ERROR!
498           //TODO! close socket after the write! schedule task
499           //GNUNET_NETWORK_socket_close (s5r->sock);
500           //GNUNET_free(s5r);
501           return;
502         }
503       }
504     }
505     else
506     {
507       phost = (struct hostent*)gethostbyname (domain);
508       if (phost == NULL)
509       {
510         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511                     "Resolve %s error!\n", domain );
512         s_resp->version = 0x05;
513         s_resp->reply = 0x01;
514         s5r->wtask = 
515           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
516                                           s5r->sock,
517                                           &do_write, s5r);
518         //ERROR!
519         //TODO! close socket after the write! schedule task
520         //GNUNET_NETWORK_socket_close (s5r->sock);
521         //GNUNET_free(s5r);
522         return;
523       }
524
525       s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET,
526                                                        SOCK_STREAM,
527                                                        0);
528       r_sin_addr = (struct in_addr*)(phost->h_addr);
529       remote_ip = r_sin_addr->s_addr;
530       memset(&remote_addr, 0, sizeof(remote_addr));
531       remote_addr.sin_family = AF_INET;
532 #if HAVE_SOCKADDR_IN_SIN_LEN
533       remote_addr.sin_len = sizeof (remote_addr);
534 #endif
535       remote_addr.sin_addr.s_addr = remote_ip;
536       remote_addr.sin_port = req_port;
537       
538       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539                   "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr),
540                   ntohs(req_port));
541
542       if ((GNUNET_OK !=
543           GNUNET_NETWORK_socket_connect ( s5r->remote_sock,
544                                           (const struct sockaddr*)&remote_addr,
545                                           sizeof (remote_addr)))
546           && (errno != EINPROGRESS))
547       {
548         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
549         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550                     "socket request error...\n");
551         s_resp->version = 0x05;
552         s_resp->reply = 0x01;
553         s5r->wtask =
554           GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
555                                           s5r->sock,
556                                           &do_write, s5r);
557         //TODO see above
558         return;
559       }
560
561       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562                   "new remote connection\n");
563
564       s_resp->version = 0x05;
565       s_resp->reply = 0x00;
566       s_resp->reserved = 0x00;
567       s_resp->addr_type = 0x01;
568
569       s5r->state = SOCKS5_DATA_TRANSFER;
570
571       s5r->wtask =
572         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
573                                         s5r->sock,
574                                         &do_write, s5r);
575       s5r->rtask =
576         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
577                                        s5r->sock,
578                                        &do_read, s5r);
579
580     }
581     return;
582   }
583
584   if (s5r->state == SOCKS5_DATA_TRANSFER)
585   {
586     if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0))
587     {
588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589                   "Closing connection to client\n");
590       if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
591         GNUNET_SCHEDULER_cancel (s5r->rtask);
592       if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
593         GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
594       if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
595         GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
596       if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
597         GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
598       
599       if (s5r->remote_sock != NULL)
600         GNUNET_NETWORK_socket_close (s5r->remote_sock);
601       GNUNET_NETWORK_socket_close (s5r->sock);
602       GNUNET_free(s5r);
603       return;
604     }
605
606     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607                 "forwarding %d bytes from client\n", s5r->rbuf_len);
608
609     s5r->fwdwtask =
610       GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
611                                       s5r->remote_sock,
612                                       &do_write_remote, s5r);
613
614     if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK)
615     {
616       s5r->fwdrtask =
617         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
618                                        s5r->remote_sock,
619                                        &do_read_remote, s5r);
620     }
621
622
623   }
624
625   //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r);
626
627 }
628
629 /**
630  * Accept new incoming connections
631  *
632  * @param cls the closure
633  * @param tc the scheduler context
634  */
635 static void
636 do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
637 {
638   struct GNUNET_NETWORK_Handle *s;
639   struct Socks5Request *s5r;
640
641   ltask = GNUNET_SCHEDULER_NO_TASK;
642   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
643     return;
644
645   ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
646                                          lsock,
647                                          &do_accept, NULL);
648
649   s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
650
651   if (NULL == s)
652   {
653     GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept");
654     return;
655   }
656
657   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658               "Got an inbound connection, waiting for data\n");
659
660   s5r = GNUNET_malloc (sizeof (struct Socks5Request));
661   s5r->sock = s;
662   s5r->state = SOCKS5_INIT;
663   s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
664   s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
665   s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
666   s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
667                                               s5r->sock,
668                                               &do_read, s5r);
669   //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r);
670 }
671
672 /**
673  * Main function that will be run
674  *
675  * @param cls closure
676  * @param args remaining command-line arguments
677  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
678  * @param cfg configuration
679  */
680 static void
681 run (void *cls, char *const *args, const char *cfgfile,
682      const struct GNUNET_CONFIGURATION_Handle *cfg)
683 {
684   struct sockaddr_in sa;
685
686   memset (&sa, 0, sizeof (sa));
687   sa.sin_family = AF_INET;
688   sa.sin_port = htons (port);
689 #if HAVE_SOCKADDR_IN_SIN_LEN
690   sa.sin_len = sizeof (sa);
691 #endif
692
693   lsock = GNUNET_NETWORK_socket_create (AF_INET,
694                                         SOCK_STREAM,
695                                         0);
696
697   if ((NULL == lsock) ||
698       (GNUNET_OK !=
699        GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &sa,
700                                    sizeof (sa))))
701   {
702     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703                 "Failed to create listen socket bound to `%s'",
704                 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
705     if (NULL != lsock)
706       GNUNET_NETWORK_socket_close (lsock);
707     return;
708   }
709
710   if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, 5))
711   {
712     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
713                 "Failed to listen on socket bound to `%s'",
714                 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
715     return;
716   }
717
718   ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
719                                          lsock, &do_accept, NULL);
720
721   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
722               "Proxy listens on port %u\n",
723               port);
724   
725   httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444,
726                                NULL, NULL,
727                                &create_response, NULL,
728                                MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
729                                MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
730                                MHD_OPTION_NOTIFY_COMPLETED,
731                                NULL, NULL,
732                                MHD_OPTION_END);
733   run_httpd ();
734
735 }
736
737 /**
738  * The main function for gnunet-gns-proxy.
739  *
740  * @param argc number of arguments from the command line
741  * @param argv command line arguments
742  * @return 0 ok, 1 on error
743  */
744 int
745 main (int argc, char *const *argv)
746 {
747   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
748     {'p', "port", NULL,
749      gettext_noop ("listen on specified port"), 1,
750      &GNUNET_GETOPT_set_string, &port},
751     GNUNET_GETOPT_OPTION_END
752   };
753
754   int ret;
755
756   GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL);
757   ret =
758       (GNUNET_OK ==
759        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy",
760                            _("GNUnet GNS proxy"),
761                            options,
762                            &run, NULL)) ? 0 : 1;
763   return ret;
764 }