2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 #include <gnunet_util_lib.h>
23 #include <gnunet_gns_service.h>
24 #include <microhttpd.h>
25 #include <curl/curl.h>
27 #include "gns_proxy_proto.h"
30 #define GNUNET_GNS_PROXY_PORT 7777
32 /* MHD/cURL defines */
33 #define BUF_WAIT_FOR_CURL 0
34 #define BUF_WAIT_FOR_MHD 1
35 #define HTML_HDR_CONTENT "Content-Type: text/html\r\n"
38 #define RE_DOTPLUS "<a href=\"http://(([A-Za-z]+[.])+)([+])"
39 #define RE_N_MATCHES 4
41 /* The usual suspects */
43 #define HTTPS_PORT 443
48 * A structure for socks requests
52 /* The client socket */
53 struct GNUNET_NETWORK_Handle *sock;
55 /* The server socket */
56 struct GNUNET_NETWORK_Handle *remote_sock;
61 /* Client socket read task */
62 GNUNET_SCHEDULER_TaskIdentifier rtask;
64 /* Server socket read task */
65 GNUNET_SCHEDULER_TaskIdentifier fwdrtask;
67 /* Client socket write task */
68 GNUNET_SCHEDULER_TaskIdentifier wtask;
70 /* Server socket write task */
71 GNUNET_SCHEDULER_TaskIdentifier fwdwtask;
79 /* Length of data in read buffer */
80 unsigned int rbuf_len;
82 /* Length of data in write buffer */
83 unsigned int wbuf_len;
88 * A structure for all running Httpds
93 struct MhdHttpList *prev;
96 struct MhdHttpList *next;
98 /* is this an ssl daemon? */
101 /* the domain name to server (only important for SSL) */
104 /* The daemon handle */
105 struct MHD_Daemon *daemon;
108 GNUNET_SCHEDULER_TaskIdentifier httpd_task;
112 * A structure for MHD<->cURL streams
117 struct ProxyCurlTask *prev;
120 struct ProxyCurlTask *next;
125 /* The URL to fetch */
128 /* The cURL write buffer / MHD read buffer */
129 char buffer[CURL_MAX_WRITE_SIZE];
131 /* The pointer to the data in the buffer */
134 /* The buffer status (BUF_WAIT_FOR_CURL or BUF_WAIT_FOR_MHD) */
137 /* Number of bytes in buffer */
138 unsigned int bytes_in_buffer;
140 /* Indicates wheather the download is in progress */
141 int download_in_progress;
143 /* Indicates wheather the download was successful */
144 int download_successful;
146 /* Indicates wheather the download failed */
149 /* Indicates wheather we need to parse HTML */
152 /* Indicates wheather we are postprocessing the HTML right now */
153 int is_postprocessing;
155 /* Indicates wheather postprocessing has finished */
158 /* Task ID of the postprocessing task */
159 GNUNET_SCHEDULER_TaskIdentifier pp_task;
161 /* The postprocessing buffer TODO length? */
164 /* The authority of the corresponding host (site of origin) */
167 /* The hostname (Host header field) */
170 /* The associated daemon list entry */
171 struct MhdHttpList *daemon;
175 /* The port the proxy is running on (default 7777) */
176 unsigned long port = GNUNET_GNS_PROXY_PORT;
178 /* The listen socket of the proxy */
179 static struct GNUNET_NETWORK_Handle *lsock;
181 /* The listen task ID */
182 GNUNET_SCHEDULER_TaskIdentifier ltask;
184 /* The cURL download task */
185 GNUNET_SCHEDULER_TaskIdentifier curl_download_task;
187 /* The non SSL httpd daemon handle */
188 static struct MHD_Daemon *httpd;
190 /* The http task ID */
191 static GNUNET_SCHEDULER_TaskIdentifier httpd_task;
193 /* The cURL multi handle */
194 static CURLM *curl_multi;
196 /* Handle to the GNS service */
197 static struct GNUNET_GNS_Handle *gns_handle;
199 /* DLL for ProxyCurlTasks */
200 static struct ProxyCurlTask *ctasks_head;
202 /* DLL for ProxyCurlTasks */
203 static struct ProxyCurlTask *ctasks_tail;
205 /* DLL for http daemons */
206 static struct MhdHttpList *mhd_httpd_head;
208 /* DLL for http daemons */
209 static struct MhdHttpList *mhd_httpd_tail;
211 /* Handle to the regex for dotplus (.+) replacement in HTML */
212 static regex_t re_dotplus;
215 * Checks if name is in tld
217 * @param name the name to check
218 * @param tld the TLD to check for
219 * @return GNUNET_YES or GNUNET_NO
222 is_tld(const char* name, const char* tld)
226 if (strlen(name) <= strlen(tld))
231 offset = strlen(name)-strlen(tld);
232 if (strcmp (name+offset, tld) != 0)
234 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
235 "%s is not in .%s TLD\n", name, tld);
244 * Read HTTP request header field 'Host'
246 * @param cls buffer to write to
247 * @param kind value kind
248 * @param key field key
249 * @param value field value
250 * @return MHD_NO when Host found
253 con_val_iter (void *cls,
254 enum MHD_ValueKind kind,
258 char* buf = (char*)cls;
260 if (0 == strcmp ("Host", key))
270 * Check HTTP response header for mime
272 * @param buffer curl buffer
273 * @param size curl blocksize
274 * @param nmemb curl blocknumber
276 * @return size of read bytes
279 curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls)
281 size_t bytes = size * nmemb;
282 struct ProxyCurlTask *ctask = cls;
285 memcpy (hdr, buffer, bytes);
288 if (0 == strcmp (hdr, HTML_HDR_CONTENT))
290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291 "Got HTML HTTP response header\n");
292 ctask->parse_content = GNUNET_YES;
301 * @param hd a http daemon list entry
304 run_httpd (struct MhdHttpList *hd);
316 * Task that simply runs MHD main loop
319 * @param tc task context
322 run_mhd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
325 struct MhdHttpList *hd;
327 for (hd=mhd_httpd_head; hd != NULL; hd = hd->next)
328 MHD_run (hd->daemon);
333 * Process cURL download bits
335 * @param ptr buffer with data
336 * @param size size of a record
337 * @param nmemb number of records downloaded
339 * @return number of processed bytes
342 callback_download (void *ptr, size_t size, size_t nmemb, void *ctx)
344 const char *cbuf = ptr;
346 struct ProxyCurlTask *ctask = ctx;
357 if (total > sizeof (ctask->buffer))
359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
360 "CURL gave us too much data to handle (%d)!\n",
365 if (ctask->buf_status == BUF_WAIT_FOR_MHD)
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368 "CURL: Waiting for MHD (%s)\n", ctask->url);
369 return CURL_WRITEFUNC_PAUSE;
373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
374 "CURL: Copying to MHD (%s, %d)\n", ctask->url, total);
375 memcpy (ctask->buffer, cbuf, total);
376 ctask->bytes_in_buffer = total;
377 ctask->buffer_ptr = ctask->buffer;
379 ctask->buf_status = BUF_WAIT_FOR_MHD;
381 //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382 // "cURL chunk:\n%s\n", (char*)ctask->buffer);
383 run_mhd (NULL, NULL);
390 * Callback to free content
392 * @param cls content to free
395 mhd_content_free (void *cls)
397 struct ProxyCurlTask *ctask = cls;
399 if (ctask->curl != NULL)
400 curl_easy_cleanup (ctask->curl);
411 * Shorten result callback
413 * @param cls the proxycurltask
414 * @param short_name the shortened name (NULL on error)
417 process_shorten (void* cls, const char* short_name)
419 struct ProxyCurlTask *ctask = cls;
421 char tmp[strlen(ctask->pp_buf)]; //TODO length
423 if (NULL == short_name)
425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426 "MHD PP: Unable to shorten %s\n",
431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432 "MHD PP: Shorten %s -> %s\n",
436 sprintf (tmp, "<a href=http://%s", short_name);
437 strcpy (ctask->pp_buf, tmp);
439 ctask->pp_finished = GNUNET_YES;
441 GNUNET_SCHEDULER_add_now (&run_mhd, NULL);
446 * Postprocessing task that uses GNS to shorten names
448 * @param cls the proxycurltask
449 * @param tc the task context
452 postprocess_name (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
454 struct ProxyCurlTask *ctask = cls;
455 char tmp[strlen(ctask->pp_buf)];
457 sprintf ( tmp, "%s%s", ctask->pp_buf, ctask->authority);
459 GNUNET_GNS_shorten (gns_handle,
467 * Callback for MHD response
470 * @param pos in buffer
472 * @param max space in buffer
475 mhd_content_cb (void *cls,
480 struct ProxyCurlTask *ctask = cls;
482 size_t bytes_to_copy;
485 regmatch_t m[RE_N_MATCHES];
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "MHD: content cb\n");
490 if (ctask->download_successful &&
491 (ctask->buf_status == BUF_WAIT_FOR_CURL))
493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
494 "MHD: sending response for %s\n", ctask->url);
495 ctask->download_in_progress = GNUNET_NO;
496 curl_multi_remove_handle (curl_multi, ctask->curl);
497 curl_easy_cleanup (ctask->curl);
498 GNUNET_SCHEDULER_add_now (&run_mhd, NULL);
499 return MHD_CONTENT_READER_END_OF_STREAM;
502 if (ctask->download_error &&
503 (ctask->buf_status == BUF_WAIT_FOR_CURL))
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
506 "MHD: sending error response\n");
507 ctask->download_in_progress = GNUNET_NO;
508 curl_multi_remove_handle (curl_multi, ctask->curl);
509 curl_easy_cleanup (ctask->curl);
510 GNUNET_SCHEDULER_add_now (&run_mhd, NULL);
511 return MHD_CONTENT_READER_END_WITH_ERROR;
514 if ( ctask->buf_status == BUF_WAIT_FOR_CURL )
517 bytes_to_copy = ctask->bytes_in_buffer;
519 if (ctask->parse_content == GNUNET_YES)
522 GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG,
523 "MHD: We need to parse the HTML %s\n", ctask->buffer_ptr);
525 nomatch = regexec ( &re_dotplus, ctask->buffer_ptr, RE_N_MATCHES, m, 0);
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532 GNUNET_assert (m[1].rm_so != -1);
534 hostptr = ctask->buffer_ptr+m[1].rm_so;
538 bytes_to_copy = m[0].rm_so;
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540 "Copying %d bytes.\n", m[0].rm_so);
546 if (ctask->is_postprocessing == GNUNET_YES)
550 if ( ctask->pp_finished == GNUNET_NO )
552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553 "MHD PP: Waiting for PP of %s\n", ctask->pp_buf);
557 ctask->is_postprocessing = GNUNET_NO;
559 ctask->bytes_in_buffer -= m[0].rm_eo;//(m[1].rm_eo-m[1].rm_so);
560 ctask->buffer_ptr += m[0].rm_eo;//(m[1].rm_eo-m[1].rm_so);
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562 "Skipping next %d bytes in buffer\n", m[0].rm_eo);
564 GNUNET_SCHEDULER_add_now (&run_mhd, NULL);
566 if ( strlen (ctask->pp_buf) <= max )
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569 "Copying postprocessed %s.\n", ctask->pp_buf);
570 memcpy ( buf, ctask->pp_buf, strlen (ctask->pp_buf) );
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
573 ctask->is_postprocessing = GNUNET_NO;
574 return strlen (ctask->pp_buf);
580 memset (ctask->pp_buf, 0, sizeof(ctask->pp_buf));
581 memcpy (ctask->pp_buf, hostptr, (m[1].rm_eo-m[1].rm_so));
583 ctask->is_postprocessing = GNUNET_YES;
584 ctask->pp_finished = GNUNET_NO;
586 //postprocess_name(ctask, NULL);
587 ctask->pp_task = GNUNET_SCHEDULER_add_now (&postprocess_name, ctask);
594 if ( bytes_to_copy > max )
596 GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG,
597 "MHD: buffer in response too small! (%s)\n",
599 memcpy ( buf, ctask->buffer_ptr, max);
600 ctask->bytes_in_buffer -= max;
601 ctask->buffer_ptr += max;
606 GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG,
607 "MHD: copying %d bytes to mhd response at offset %d\n",
610 memcpy ( buf, ctask->buffer_ptr, bytes_to_copy );
611 copied = bytes_to_copy;
612 if (bytes_to_copy < ctask->bytes_in_buffer)
614 ctask->bytes_in_buffer -= bytes_to_copy;
615 ctask->buffer_ptr += bytes_to_copy;
619 ctask->bytes_in_buffer = 0;
620 ctask->buf_status = BUF_WAIT_FOR_CURL;
621 ctask->buffer_ptr = ctask->buffer;
622 curl_easy_pause (ctask->curl, CURLPAUSE_CONT);
623 GNUNET_SCHEDULER_add_now (&run_mhd, NULL);
627 GNUNET_SCHEDULER_add_now (&run_mhd, NULL);
635 * Task that is run when we are ready to receive more data
639 * @param tc task context
642 curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
645 * Ask cURL for the select sets and schedule download
648 curl_download_prepare ()
655 struct GNUNET_NETWORK_FDSet *grs;
656 struct GNUNET_NETWORK_FDSet *gws;
658 struct GNUNET_TIME_Relative rtime;
664 mret = curl_multi_fdset (curl_multi, &rs, &ws, &es, &max);
666 if (mret != CURLM_OK)
668 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
669 "%s failed at %s:%d: `%s'\n",
670 "curl_multi_fdset", __FILE__, __LINE__,
671 curl_multi_strerror (mret));
676 mret = curl_multi_timeout (curl_multi, &to);
677 rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "cURL multi fds: max=%d timeout=%llu\n", max, to);
682 grs = GNUNET_NETWORK_fdset_create ();
683 gws = GNUNET_NETWORK_fdset_create ();
684 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
685 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687 "Scheduling task cURL\n");
689 if (curl_download_task != GNUNET_SCHEDULER_NO_TASK)
690 GNUNET_SCHEDULER_cancel (curl_download_task);
693 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
696 &curl_task_download, curl_multi);
697 GNUNET_NETWORK_fdset_destroy (gws);
698 GNUNET_NETWORK_fdset_destroy (grs);
704 * Task that is run when we are ready to receive more data
708 * @param tc task context
711 curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
717 struct ProxyCurlTask *ctask;
720 curl_download_task = GNUNET_SCHEDULER_NO_TASK;
722 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
725 "Shutdown requested while trying to download\n");
729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
737 mret = curl_multi_perform (curl_multi, &running);
739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740 "Running curl tasks: %d\n", running);
743 for (; ctask != NULL; ctask = ctask->next)
745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
746 "CTask: %s\n", ctask->url);
750 if (num_ctasks != running)
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753 "%d ctasks, %d curl running\n", num_ctasks, running);
759 msg = curl_multi_info_read (curl_multi, &msgnum);
760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761 "Messages left: %d\n", msgnum);
768 if ((msg->data.result != CURLE_OK) &&
769 (msg->data.result != CURLE_GOT_NOTHING))
771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
772 "Download curl failed");
774 for (; ctask != NULL; ctask = ctask->next)
776 if (memcmp (msg->easy_handle, ctask->curl, sizeof (CURL)) != 0)
779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
780 "Download curl failed for task %s: %s.\n",
782 curl_easy_strerror (msg->data.result));
783 ctask->download_successful = GNUNET_NO;
784 ctask->download_error = GNUNET_YES;
785 //curl_multi_remove_handle (curl_multi, ctask->curl);
786 //curl_easy_cleanup (ctask->curl);
787 GNUNET_CONTAINER_DLL_remove (ctasks_head, ctasks_tail,
791 GNUNET_assert (ctask != NULL);
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796 "cURL download completed.\n");
798 for (; ctask != NULL; ctask = ctask->next)
800 if (memcmp (msg->easy_handle, ctask->curl, sizeof (CURL)) != 0)
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "cURL task %s found.\n", ctask->url);
805 ctask->download_successful = GNUNET_YES;
806 //curl_multi_remove_handle (curl_multi, ctask->curl);
807 //curl_easy_cleanup (ctask->curl);
808 GNUNET_CONTAINER_DLL_remove (ctasks_head, ctasks_tail,
812 GNUNET_assert (ctask != NULL);
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
815 "curl end %s\n", curl_easy_strerror(msg->data.result));
821 } while (msgnum > 0);
824 for (ctask=ctasks_head; ctask != NULL; ctask = ctask->next)
829 if (num_ctasks != running)
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832 "%d ctasks, %d curl running\n", num_ctasks, running);
835 GNUNET_assert ( num_ctasks == running );
839 } while (mret == CURLM_CALL_MULTI_PERFORM);
842 if (mret != CURLM_OK)
844 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s failed at %s:%d: `%s'\n",
845 "curl_multi_perform", __FILE__, __LINE__,
846 curl_multi_strerror (mret));
848 curl_download_prepare();
852 * Initialize download and trigger curl
854 * @param cls the proxycurltask
855 * @param auth_name the name of the authority (site of origin) of ctask->host
859 process_get_authority (void* cls,
860 const char* auth_name)
862 struct ProxyCurlTask *ctask = cls;
864 if (NULL == auth_name)
866 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
867 "Get authority failed!\n");
868 strcpy (ctask->authority, "");
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "Get authority yielded %s\n", auth_name);
873 strcpy (ctask->authority, auth_name);
875 curl_download_prepare ();
879 * Main MHD callback for handling requests.
882 * @param con MHD connection handle
883 * @param meth the HTTP method used ("GET", "PUT", etc.)
884 * @param ver the HTTP version string (i.e. "HTTP/1.1")
885 * @param upload_data the data being uploaded (excluding HEADERS,
886 * for a POST that fits into memory and that is encoded
887 * with a supported encoding, the POST data will NOT be
888 * given in upload_data and is instead available as
889 * part of MHD_get_connection_values; very large POST
890 * data *will* be made available incrementally in
892 * @param upload_data_size set initially to the size of the
893 * upload_data provided; the method must update this
894 * value to the number of bytes NOT processed;
895 * @param con_cls pointer to location where we store the 'struct Request'
896 * @return MHD_YES if the connection was handled successfully,
897 * MHD_NO if the socket must be closed due to a serious
898 * error while handling the request
901 create_response (void *cls,
902 struct MHD_Connection *con,
906 const char *upload_data,
907 size_t *upload_data_size,
911 const char* page = "<html><head><title>gnoxy</title>"\
912 "</head><body>cURL fail</body></html>";
913 struct MHD_Response *response;
919 struct ProxyCurlTask *ctask;
921 if (0 != strcmp (meth, "GET"))
923 if (&dummy != *con_cls)
929 if (0 != *upload_data_size)
934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937 MHD_get_connection_values (con,
939 &con_val_iter, host);
943 ctask = GNUNET_malloc (sizeof (struct ProxyCurlTask));
944 ctask->curl = curl_easy_init();
946 if (curl_multi == NULL)
947 curl_multi = curl_multi_init ();
949 if ((ctask->curl == NULL) || (curl_multi == NULL))
951 response = MHD_create_response_from_buffer (strlen (page),
953 MHD_RESPMEM_PERSISTENT);
954 ret = MHD_queue_response (con,
957 MHD_destroy_response (response);
962 ctask->download_in_progress = GNUNET_YES;
963 ctask->download_successful = GNUNET_NO;
964 ctask->buf_status = BUF_WAIT_FOR_CURL;
965 ctask->bytes_in_buffer = 0;
966 ctask->parse_content = GNUNET_NO;
968 curl_easy_setopt (ctask->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr);
969 curl_easy_setopt (ctask->curl, CURLOPT_HEADERDATA, ctask);
970 curl_easy_setopt (ctask->curl, CURLOPT_WRITEFUNCTION, &callback_download);
971 curl_easy_setopt (ctask->curl, CURLOPT_WRITEDATA, ctask);
972 curl_easy_setopt (ctask->curl, CURLOPT_FOLLOWLOCATION, 1);
973 curl_easy_setopt (ctask->curl, CURLOPT_MAXREDIRS, 4);
974 /* no need to abort if the above failed */
975 sprintf (curlurl, "http://%s%s", host, url);
976 strcpy (ctask->host, host);
977 strcpy (ctask->url, curlurl);
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
979 "Adding new curl task for %s\n", curlurl);
981 curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl);
982 curl_easy_setopt (ctask->curl, CURLOPT_FAILONERROR, 1);
983 curl_easy_setopt (ctask->curl, CURLOPT_CONNECTTIMEOUT, 600L);
984 curl_easy_setopt (ctask->curl, CURLOPT_TIMEOUT, 600L);
986 mret = curl_multi_add_handle (curl_multi, ctask->curl);
988 if (mret != CURLM_OK)
990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991 "%s failed at %s:%d: `%s'\n",
992 "curl_multi_add_handle", __FILE__, __LINE__,
993 curl_multi_strerror (mret));
994 response = MHD_create_response_from_buffer (strlen (page),
996 MHD_RESPMEM_PERSISTENT);
997 ret = MHD_queue_response (con,
1000 MHD_destroy_response (response);
1002 curl_easy_cleanup (ctask->curl);
1003 GNUNET_free (ctask);
1007 GNUNET_CONTAINER_DLL_insert (ctasks_head, ctasks_tail, ctask);
1009 GNUNET_GNS_get_authority (gns_handle,
1011 &process_get_authority,
1013 //download_prepare (ctask);
1014 //curl_download_prepare ();
1016 response = MHD_create_response_from_callback (-1, -1,
1021 ret = MHD_queue_response (con, MHD_HTTP_OK, response);
1023 //MHD_destroy_response (response);
1029 * Task run whenever HTTP server operations are pending.
1032 * @param tc sched context
1035 do_httpd (void *cls,
1036 const struct GNUNET_SCHEDULER_TaskContext *tc);
1045 struct MhdHttpList *hd;
1047 for (hd=mhd_httpd_head; hd != NULL; hd = hd->next)
1056 run_httpd (struct MhdHttpList *hd)
1061 struct GNUNET_NETWORK_FDSet *wrs;
1062 struct GNUNET_NETWORK_FDSet *wws;
1063 struct GNUNET_NETWORK_FDSet *wes;
1066 unsigned MHD_LONG_LONG timeout;
1067 struct GNUNET_TIME_Relative tv;
1072 wrs = GNUNET_NETWORK_fdset_create ();
1073 wes = GNUNET_NETWORK_fdset_create ();
1074 wws = GNUNET_NETWORK_fdset_create ();
1076 GNUNET_assert (MHD_YES == MHD_get_fdset (hd->daemon, &rs, &ws, &es, &max));
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "MHD fds: max=%d\n", max);
1082 haveto = MHD_get_timeout (hd->daemon, &timeout);
1084 if (haveto == MHD_YES)
1085 tv.rel_value = (uint64_t) timeout;
1087 tv = GNUNET_TIME_UNIT_FOREVER_REL;
1088 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1089 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1090 GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
1092 if (httpd_task != GNUNET_SCHEDULER_NO_TASK)
1093 GNUNET_SCHEDULER_cancel (hd->httpd_task);
1095 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
1098 GNUNET_NETWORK_fdset_destroy (wrs);
1099 GNUNET_NETWORK_fdset_destroy (wws);
1100 GNUNET_NETWORK_fdset_destroy (wes);
1105 * Task run whenever HTTP server operations are pending.
1108 * @param tc sched context
1111 do_httpd (void *cls,
1112 const struct GNUNET_SCHEDULER_TaskContext *tc)
1114 struct MhdHttpList *hd = cls;
1116 hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
1118 MHD_run (hd->daemon);
1124 * Read data from socket
1126 * @param cls the closure
1127 * @param tc scheduler context
1130 do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1133 * Read from remote end
1135 * @param cls closure
1136 * @param tc scheduler context
1139 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1142 * Write data to remote socket
1144 * @param cls the closure
1145 * @param tc scheduler context
1148 do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1150 struct Socks5Request *s5r = cls;
1153 s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
1155 if ((NULL != tc->read_ready) &&
1156 (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->remote_sock)) &&
1157 ((len = GNUNET_NETWORK_socket_send (s5r->remote_sock, s5r->rbuf,
1160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1161 "Successfully sent %d bytes to remote socket\n",
1166 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote");
1168 if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1169 GNUNET_SCHEDULER_cancel (s5r->rtask);
1170 if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
1171 GNUNET_SCHEDULER_cancel (s5r->wtask);
1172 if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1173 GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1174 GNUNET_NETWORK_socket_close (s5r->remote_sock);
1175 GNUNET_NETWORK_socket_close (s5r->sock);
1181 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1188 * Write data to socket
1190 * @param cls the closure
1191 * @param tc scheduler context
1194 do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1196 struct Socks5Request *s5r = cls;
1199 s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
1201 if ((NULL != tc->read_ready) &&
1202 (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) &&
1203 ((len = GNUNET_NETWORK_socket_send (s5r->sock, s5r->wbuf,
1206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1207 "Successfully sent %d bytes to socket\n",
1213 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
1215 if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1216 GNUNET_SCHEDULER_cancel (s5r->rtask);
1217 if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
1218 GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
1219 if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1220 GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1221 GNUNET_NETWORK_socket_close (s5r->remote_sock);
1222 GNUNET_NETWORK_socket_close (s5r->sock);
1227 if ((s5r->state == SOCKS5_DATA_TRANSFER) &&
1228 (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK))
1230 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1232 &do_read_remote, s5r);
1236 * Read from remote end
1238 * @param cls closure
1239 * @param tc scheduler context
1242 do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1244 struct Socks5Request *s5r = cls;
1246 s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
1249 if ((NULL != tc->write_ready) &&
1250 (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->remote_sock)) &&
1251 (s5r->wbuf_len = GNUNET_NETWORK_socket_recv (s5r->remote_sock, s5r->wbuf,
1252 sizeof (s5r->wbuf))))
1254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1255 "Successfully read %d bytes from remote socket\n",
1260 if (s5r->wbuf_len == 0)
1261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1262 "0 bytes received from remote... graceful shutdown!\n");
1263 if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
1264 GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
1265 if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1266 GNUNET_SCHEDULER_cancel (s5r->rtask);
1268 GNUNET_NETWORK_socket_close (s5r->remote_sock);
1269 s5r->remote_sock = NULL;
1270 GNUNET_NETWORK_socket_close (s5r->sock);
1276 s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1284 * Adds a socket to MHD
1286 * @param h the handle to the socket to add
1287 * @return whatever MHD_add_connection returns
1290 add_handle_to_mhd (struct GNUNET_NETWORK_Handle *h, struct MHD_Daemon *daemon)
1293 struct sockaddr *addr;
1296 fd = GNUNET_NETWORK_get_fd (h);
1297 addr = GNUNET_NETWORK_get_addr (h);
1298 len = GNUNET_NETWORK_get_addrlen (h);
1300 return MHD_add_connection (daemon, fd, addr, len);
1304 /*TODO this needs MHD API modification */
1305 static int http_port = 4444;
1309 get_file_size (const char* filename)
1313 fp = fopen (filename, "rb");
1318 if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp))))
1330 * Read file in filename
1332 * @param filename file to read
1336 load_file (const char* filename)
1342 size = get_file_size (filename);
1346 fp = fopen (filename, "rb");
1350 buffer = GNUNET_malloc (size);
1357 if (size != fread (buffer, 1, size, fp))
1359 GNUNET_free (buffer);
1368 * Adds a socket to an SSL MHD instance
1369 * It is important the the domain name is
1370 * correct. In most cases we need to start a new daemon
1373 add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, char* domain)
1375 struct MhdHttpList *hd = NULL;
1377 static char *key_pem;
1378 static char *cert_pem;
1380 key_pem = load_file ("server.key");
1381 cert_pem = load_file ("server.pem");
1383 for (hd = mhd_httpd_head; hd != NULL; hd = hd->next)
1385 if (0 == strcmp (hd->domain, domain))
1392 /* TODO: create cert, start SSL MHD */
1393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1394 "No previous SSL instance found... starting new one\n");
1395 hd = GNUNET_malloc (sizeof (struct MhdHttpList));
1396 hd->is_ssl = GNUNET_YES;
1397 strcpy (hd->domain, domain);
1398 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL, http_port++,
1400 &create_response, NULL,
1401 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
1402 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
1403 MHD_OPTION_NOTIFY_COMPLETED,
1405 MHD_OPTION_HTTPS_MEM_KEY, key_pem,
1406 MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
1408 hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
1410 GNUNET_CONTAINER_DLL_insert (mhd_httpd_head, mhd_httpd_tail, hd);
1413 return add_handle_to_mhd (h, hd->daemon);
1419 * Read data from incoming connection
1421 * @param cls the closure
1422 * @param tc the scheduler context
1425 do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1427 struct Socks5Request *s5r = cls;
1428 struct socks5_client_hello *c_hello;
1429 struct socks5_server_hello *s_hello;
1430 struct socks5_client_request *c_req;
1431 struct socks5_server_response *s_resp;
1437 struct hostent *phost;
1439 struct sockaddr_in remote_addr;
1440 struct in_addr *r_sin_addr;
1442 s5r->rtask = GNUNET_SCHEDULER_NO_TASK;
1444 if ((NULL != tc->write_ready) &&
1445 (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) &&
1446 (s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf,
1447 sizeof (s5r->rbuf))))
1449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1450 "Successfully read %d bytes from socket\n",
1455 if (s5r->rbuf_len != 0)
1456 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read");
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disco!\n");
1460 if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1461 GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1462 if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK)
1463 GNUNET_SCHEDULER_cancel (s5r->wtask);
1464 if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
1465 GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
1466 GNUNET_NETWORK_socket_close (s5r->remote_sock);
1467 GNUNET_NETWORK_socket_close (s5r->sock);
1472 if (s5r->state == SOCKS5_INIT)
1474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1476 c_hello = (struct socks5_client_hello*)&s5r->rbuf;
1478 GNUNET_assert (c_hello->version == SOCKS_VERSION_5);
1480 s_hello = (struct socks5_server_hello*)&s5r->wbuf;
1481 s5r->wbuf_len = sizeof( struct socks5_server_hello );
1483 s_hello->version = c_hello->version;
1484 s_hello->auth_method = SOCKS_AUTH_NONE;
1486 /* Write response to client */
1487 s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1491 s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1495 s5r->state = SOCKS5_REQUEST;
1499 if (s5r->state == SOCKS5_REQUEST)
1501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1502 "Processing SOCKS5 request\n");
1503 c_req = (struct socks5_client_request*)&s5r->rbuf;
1504 s_resp = (struct socks5_server_response*)&s5r->wbuf;
1505 //Only 10byte for ipv4 response!
1506 s5r->wbuf_len = 10;//sizeof (struct socks5_server_response);
1508 GNUNET_assert (c_req->addr_type == 3);
1510 dom_len = *((uint8_t*)(&(c_req->addr_type) + 1));
1511 memset(domain, 0, sizeof(domain));
1512 strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len);
1513 req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len));
1515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1516 "Requested connection is %s:%d\n",
1520 if (is_tld (domain, GNUNET_GNS_TLD) ||
1521 is_tld (domain, GNUNET_GNS_TLD_ZKEY))
1523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1524 "Requested connection is gnunet tld\n",
1528 if (ntohs(req_port) == HTTPS_PORT)
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1531 "Requested connection is HTTPS\n");
1532 ret = add_handle_to_ssl_mhd ( s5r->sock, domain );
1534 else if (NULL != httpd)
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1537 "Requested connection is HTTP\n");
1538 ret = add_handle_to_mhd ( s5r->sock, httpd );
1543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1544 _("Failed to start HTTP server\n"));
1545 s_resp->version = 0x05;
1546 s_resp->reply = 0x01;
1548 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1552 //TODO! close socket after the write! schedule task
1553 //GNUNET_NETWORK_socket_close (s5r->sock);
1558 /* Signal success */
1559 s_resp->version = 0x05;
1560 s_resp->reply = 0x00;
1561 s_resp->reserved = 0x00;
1562 s_resp->addr_type = 0x01;
1565 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1569 //GNUNET_free ( s5r );
1570 //FIXME complete socks resp!
1575 phost = (struct hostent*)gethostbyname (domain);
1578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1579 "Resolve %s error!\n", domain );
1580 s_resp->version = 0x05;
1581 s_resp->reply = 0x01;
1583 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1587 //TODO! close socket after the write! schedule task
1588 //GNUNET_NETWORK_socket_close (s5r->sock);
1593 s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET,
1596 r_sin_addr = (struct in_addr*)(phost->h_addr);
1597 remote_ip = r_sin_addr->s_addr;
1598 memset(&remote_addr, 0, sizeof(remote_addr));
1599 remote_addr.sin_family = AF_INET;
1600 #if HAVE_SOCKADDR_IN_SIN_LEN
1601 remote_addr.sin_len = sizeof (remote_addr);
1603 remote_addr.sin_addr.s_addr = remote_ip;
1604 remote_addr.sin_port = req_port;
1606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1607 "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr),
1611 GNUNET_NETWORK_socket_connect ( s5r->remote_sock,
1612 (const struct sockaddr*)&remote_addr,
1613 sizeof (remote_addr)))
1614 && (errno != EINPROGRESS))
1616 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
1617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1618 "socket request error...\n");
1619 s_resp->version = 0x05;
1620 s_resp->reply = 0x01;
1622 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1630 "new remote connection\n");
1632 s_resp->version = 0x05;
1633 s_resp->reply = 0x00;
1634 s_resp->reserved = 0x00;
1635 s_resp->addr_type = 0x01;
1637 s5r->state = SOCKS5_DATA_TRANSFER;
1640 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1644 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1652 if (s5r->state == SOCKS5_DATA_TRANSFER)
1654 if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0))
1656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1657 "Closing connection to client\n");
1658 if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK)
1659 GNUNET_SCHEDULER_cancel (s5r->rtask);
1660 if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK)
1661 GNUNET_SCHEDULER_cancel (s5r->fwdwtask);
1662 if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1663 GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1664 if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK)
1665 GNUNET_SCHEDULER_cancel (s5r->fwdrtask);
1667 if (s5r->remote_sock != NULL)
1668 GNUNET_NETWORK_socket_close (s5r->remote_sock);
1669 GNUNET_NETWORK_socket_close (s5r->sock);
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "forwarding %d bytes from client\n", s5r->rbuf_len);
1678 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1680 &do_write_remote, s5r);
1682 if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK)
1685 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1687 &do_read_remote, s5r);
1693 //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r);
1699 * Accept new incoming connections
1701 * @param cls the closure
1702 * @param tc the scheduler context
1705 do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1707 struct GNUNET_NETWORK_Handle *s;
1708 struct Socks5Request *s5r;
1710 ltask = GNUNET_SCHEDULER_NO_TASK;
1711 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1714 ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1718 s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
1722 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept");
1726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1727 "Got an inbound connection, waiting for data\n");
1729 s5r = GNUNET_malloc (sizeof (struct Socks5Request));
1731 s5r->state = SOCKS5_INIT;
1732 s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
1733 s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK;
1734 s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK;
1735 s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1738 //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r);
1743 * Task run on shutdown
1745 * @param cls closure
1746 * @param tc task context
1749 do_shutdown (void *cls,
1750 const struct GNUNET_SCHEDULER_TaskContext *tc)
1753 struct MhdHttpList *hd;
1754 struct MhdHttpList *tmp_hd;
1756 if (GNUNET_SCHEDULER_NO_TASK != curl_download_task)
1758 GNUNET_SCHEDULER_cancel (curl_download_task);
1759 curl_download_task = GNUNET_SCHEDULER_NO_TASK;
1762 for (hd = mhd_httpd_head; hd != NULL; hd = tmp_hd)
1766 if (GNUNET_SCHEDULER_NO_TASK != hd->httpd_task)
1768 GNUNET_SCHEDULER_cancel (hd->httpd_task);
1769 hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
1772 if (NULL != hd->daemon)
1774 MHD_stop_daemon (hd->daemon);
1784 * Compiles a regex for us
1786 * @param re ptr to re struct
1787 * @param rt the expression to compile
1788 * @return 0 on success
1791 compile_regex (regex_t *re, const char* rt)
1796 status = regcomp (re, rt, REG_EXTENDED|REG_NEWLINE);
1799 regerror (status, re, err, 1024);
1800 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1801 "Regex error compiling '%s': %s\n", rt, err);
1809 * Main function that will be run
1811 * @param cls closure
1812 * @param args remaining command-line arguments
1813 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1814 * @param cfg configuration
1817 run (void *cls, char *const *args, const char *cfgfile,
1818 const struct GNUNET_CONFIGURATION_Handle *cfg)
1820 struct sockaddr_in sa;
1821 struct MhdHttpList *hd;
1823 compile_regex (&re_dotplus, (char*) RE_DOTPLUS);
1825 gns_handle = GNUNET_GNS_connect (cfg);
1827 if (NULL == gns_handle)
1829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1830 "Unable to connect to GNS!\n");
1834 memset (&sa, 0, sizeof (sa));
1835 sa.sin_family = AF_INET;
1836 sa.sin_port = htons (port);
1837 #if HAVE_SOCKADDR_IN_SIN_LEN
1838 sa.sin_len = sizeof (sa);
1841 lsock = GNUNET_NETWORK_socket_create (AF_INET,
1845 if ((NULL == lsock) ||
1847 GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &sa,
1850 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1851 "Failed to create listen socket bound to `%s'",
1852 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
1854 GNUNET_NETWORK_socket_close (lsock);
1858 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, 5))
1860 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1861 "Failed to listen on socket bound to `%s'",
1862 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)));
1866 ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1867 lsock, &do_accept, NULL);
1872 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
1874 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1875 "cURL global init failed!\n");
1879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1880 "Proxy listens on port %u\n",
1883 mhd_httpd_head = NULL;
1884 mhd_httpd_tail = NULL;
1886 hd = GNUNET_malloc (sizeof (struct MhdHttpList));
1887 hd->is_ssl = GNUNET_NO;
1888 strcpy (hd->domain, "");
1889 httpd = MHD_start_daemon (MHD_USE_DEBUG, http_port++,
1891 &create_response, NULL,
1892 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
1893 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
1894 MHD_OPTION_NOTIFY_COMPLETED,
1898 hd->httpd_task = GNUNET_SCHEDULER_NO_TASK;
1900 GNUNET_CONTAINER_DLL_insert (mhd_httpd_head, mhd_httpd_tail, hd);
1904 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1905 &do_shutdown, NULL);
1911 * The main function for gnunet-gns-proxy.
1913 * @param argc number of arguments from the command line
1914 * @param argv command line arguments
1915 * @return 0 ok, 1 on error
1918 main (int argc, char *const *argv)
1920 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1922 gettext_noop ("listen on specified port"), 1,
1923 &GNUNET_GETOPT_set_string, &port},
1924 GNUNET_GETOPT_OPTION_END
1929 GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL);
1932 GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy",
1933 _("GNUnet GNS proxy"),
1935 &run, NULL)) ? 0 : 1;