X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fgns%2Fgnunet-gns-proxy.c;h=cdc18e3f6b156ca8bfab88ffcf423f4ce292c10a;hb=bcbd694ad35e182e5a1486b545ea0706082ee94a;hp=4d605d82d1fc896f4382dc8a57e99c3934b9e67f;hpb=e6c8dc0ecca0cff34c606d158d9e31476c9bd28b;p=oweals%2Fgnunet.git diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c index 4d605d82d..cdc18e3f6 100644 --- a/src/gns/gnunet-gns-proxy.c +++ b/src/gns/gnunet-gns-proxy.c @@ -34,17 +34,25 @@ #include #include +#define HAVE_MHD_NO_LISTEN_SOCKET MHD_VERSION >= 0x00091401 + #define GNUNET_GNS_PROXY_PORT 7777 #define MHD_MAX_CONNECTIONS 300 +#define MAX_HTTP_URI_LENGTH 2048 +#define POSTBUFFERSIZE 4096 /* MHD/cURL defines */ #define BUF_WAIT_FOR_CURL 0 #define BUF_WAIT_FOR_MHD 1 +#define BUF_WAIT_FOR_PP 2 #define HTML_HDR_CONTENT "Content-Type: text/html" +/* buffer padding for proper RE matching */ +#define CURL_BUF_PADDING 1000 + /* regexp */ //#define RE_DOTPLUS " (i & 15)); + return hexmap[i & 15]; +} + +/** + * Escape given 0-terminated string + * + * @param to_esc string to escapse + * @return allocated new escaped string (MUST free!) + */ +static char* +escape_to_urlenc (const char *to_esc) +{ + char *pos = (char*)to_esc; + char *res = GNUNET_malloc (strlen (to_esc) * 3 + 1); + char *rpos = res; + + while ('\0' != *pos) + { + if (isalnum (*pos) || + ('-' == *pos) || ('_' == *pos) || + ('.' == *pos) || ('~' == *pos)) + *rpos++ = *pos; + else if (' ' == *pos) + *rpos++ = '+'; + else + { + *rpos++ = '%'; + *rpos++ = i_to_hexchar (*pos >> 4); + *rpos++ = i_to_hexchar (*pos >> 15); + } + pos++; + } + *rpos = '\0'; + return res; +} + +static int +con_post_data_iter (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, + uint64_t off, + size_t size) +{ + struct ProxyCurlTask* ctask = cls; + struct ProxyUploadData* pdata; + char* enc; + char* new_value; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got POST data: '%s : %s' at offset %llu size %lld\n", + key, data, off, size); + + GNUNET_assert (NULL != ctask->post_type); + + if (0 == strcasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, + ctask->post_type)) + { + ctask->is_httppost = GNUNET_YES; + /* new part */ + if (0 == off) + { + pdata = GNUNET_malloc (sizeof (struct ProxyUploadData)); + pdata->key = strdup (key); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copied %lld\n"); + + if (NULL != filename) + { + pdata->filename = strdup (filename); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Filename %s\n", filename); + } + + if (NULL != content_type) + { + pdata->content_type = strdup (content_type); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Content-Type %s\n", content_type); + } + + pdata->value = GNUNET_malloc (size); + pdata->total_bytes = size; + memcpy (pdata->value, data, size); + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copied %lld bytes of POST Data\n", size); + return MHD_YES; + } + + pdata = ctask->upload_data_tail; + new_value = GNUNET_malloc (size + pdata->total_bytes); + memcpy (new_value, pdata->value, pdata->total_bytes); + memcpy (new_value+off, data, size); + GNUNET_free (pdata->value); + pdata->value = new_value; + pdata->total_bytes += size; + + return MHD_YES; + + } + + if (0 != strcasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, + ctask->post_type)) + { + return MHD_NO; + } + + ctask->is_httppost = GNUNET_NO; + + if (NULL != ctask->curl) + curl_easy_pause (ctask->curl, CURLPAUSE_CONT); + + if (0 == off) + { + /* a key */ + pdata = GNUNET_malloc (sizeof (struct ProxyUploadData)); + enc = escape_to_urlenc (key); + pdata->value = GNUNET_malloc (strlen (enc) + 3); + if (NULL != ctask->upload_data_head) + { + pdata->value[0] = '&'; + memcpy (pdata->value+1, enc, strlen (enc)); + } + else + memcpy (pdata->value, enc, strlen (enc)); + pdata->value[strlen (pdata->value)] = '='; + pdata->bytes_left = strlen (pdata->value); + pdata->total_bytes = pdata->bytes_left; + GNUNET_free (enc); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Escaped POST key: '%s'\n", + pdata->value); + + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + } + + /* a value */ + pdata = GNUNET_malloc (sizeof (struct ProxyUploadData)); + enc = escape_to_urlenc (data); + pdata->value = GNUNET_malloc (strlen (enc) + 1); + memcpy (pdata->value, enc, strlen (enc)); + pdata->bytes_left = strlen (pdata->value); + pdata->total_bytes = pdata->bytes_left; + GNUNET_free (enc); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Escaped POST value: '%s'\n", + pdata->value); + + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + return MHD_YES; +} + /** * Read HTTP request header field 'Host' @@ -384,14 +667,30 @@ con_val_iter (void *cls, const char *key, const char *value) { - struct ProxyCurlTask *ctask = (struct ProxyCurlTask *) cls; + struct ProxyCurlTask *ctask = cls; char* buf = ctask->host; + char* port; char* cstr; const char* hdr_val; + unsigned int uport; if (0 == strcmp ("Host", key)) { - strcpy (buf, value); + port = strstr (value, ":"); + if (NULL != port) + { + strncpy (buf, value, port-value); + port++; + if ((1 != sscanf (port, "%u", &uport)) || + (uport > UINT16_MAX) || + (0 == uport)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse port!\n"); + else + ctask->port = (uint16_t) uport; + } + else + strcpy (buf, value); return MHD_YES; } @@ -400,11 +699,27 @@ con_val_iter (void *cls, else hdr_val = value; + if (0 == strcasecmp (MHD_HTTP_HEADER_CONTENT_TYPE, + key)) + { + if (0 == strncasecmp (value, + MHD_HTTP_POST_ENCODING_FORM_URLENCODED, + strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) + ctask->post_type = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; + else if (0 == strncasecmp (value, + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, + strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) + ctask->post_type = MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA; + else + ctask->post_type = NULL; + + } + cstr = GNUNET_malloc (strlen (key) + strlen (hdr_val) + 3); GNUNET_snprintf (cstr, strlen (key) + strlen (hdr_val) + 3, "%s: %s", key, hdr_val); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client Header: %s\n", cstr); ctask->headers = curl_slist_append (ctask->headers, cstr); @@ -414,6 +729,21 @@ con_val_iter (void *cls, } +/** + * Callback for MHD response + * + * @param cls closure + * @param pos in buffer + * @param buf buffer + * @param max space in buffer + * @return number of bytes written + */ +static ssize_t +mhd_content_cb (void *cls, + uint64_t pos, + char* buf, + size_t max); + /** * Check HTTP response header for mime * @@ -433,6 +763,9 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) char hdr_mime[html_mime_len+1]; char hdr_generic[bytes+1]; char new_cookie_hdr[bytes+strlen (ctask->leho)+1]; + char new_location[MAX_HTTP_URI_LENGTH+500]; + char real_host[264]; + char leho_host[264]; char* ndup; char* tok; char* cookie_domain; @@ -440,6 +773,43 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) char* hdr_val; int delta_cdomain; size_t offset = 0; + char cors_hdr[strlen (ctask->leho) + strlen ("https://")]; + + if (NULL == ctask->response) + { + /* FIXME: get total size from curl (if available) */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating response for %s\n", ctask->url); + ctask->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, + sizeof (ctask->buffer), + &mhd_content_cb, + ctask, + NULL); + + /* if we have a leho add a CORS header */ + if (0 != strcmp ("", ctask->leho)) + { + /* We could also allow ssl and http here */ + if (ctask->mhd->is_ssl) + sprintf (cors_hdr, "https://%s", ctask->leho); + else + sprintf (cors_hdr, "http://%s", ctask->leho); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding CORS header field %s\n", + cors_hdr); + + if (GNUNET_NO == MHD_add_response_header (ctask->response, + "Access-Control-Allow-Origin", + cors_hdr)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "MHD: Error adding CORS header field %s\n", + cors_hdr); + } + } + ctask->ready_to_queue = GNUNET_YES; + } if (html_mime_len <= bytes) { @@ -459,8 +829,8 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) memcpy (hdr_generic, buffer, bytes); hdr_generic[bytes] = '\0'; - /*remove crlf*/ - if (hdr_generic[bytes-1] == '\n') + /* remove crlf */ + if ('\n' == hdr_generic[bytes-1]) hdr_generic[bytes-1] = '\0'; if (hdr_generic[bytes-2] == '\r') @@ -516,7 +886,7 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) continue; } } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cookie domain invalid\n"); @@ -527,24 +897,11 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) offset++; } - //memcpy (new_cookie_hdr+offset, tok, strlen (tok)); - GNUNET_free (ndup); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got Set-Cookie HTTP header %s\n", new_cookie_hdr); - //pch = GNUNET_malloc (sizeof (struct ProxySetCookieHeader)); - //len = strlen (hdr_cookie) - cookie_hdr_len - 1; - //pch->cookie = GNUNET_malloc (len + 1); - //memset (pch->cookie, 0, len + 1); - //memcpy (pch->cookie, hdr_cookie+cookie_hdr_len+1, len); - //GNUNET_CONTAINER_DLL_insert (ctask->set_cookies_head, - // ctask->set_cookies_tail, - // pch); - //pch = ctask->set_cookies_head; - //while (pch != NULL) - //{ if (GNUNET_NO == MHD_add_response_header (ctask->response, MHD_HTTP_HEADER_SET_COOKIE, new_cookie_hdr)) @@ -554,40 +911,61 @@ curl_check_hdr (void *buffer, size_t size, size_t nmemb, void *cls) hdr_generic+cookie_hdr_len+1); } return bytes; - //GNUNET_free (pch->cookie); - //GNUNET_CONTAINER_DLL_remove (ctask->set_cookies_head, - // ctask->set_cookies_tail, - // pch); - //GNUNET_free (pch); - //pch = ctask->set_cookies_head; - //} } ndup = GNUNET_strdup (hdr_generic); hdr_type = strtok (ndup, ":"); - if (hdr_type != NULL) + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return bytes; + } + + hdr_val = strtok (NULL, ""); + + if (NULL == hdr_val) { - hdr_val = strtok (NULL, ""); - if (hdr_val != NULL) + GNUNET_free (ndup); + return bytes; + } + + hdr_val++; + + if (0 == strcasecmp (MHD_HTTP_HEADER_LOCATION, hdr_type)) + { + if (ctask->mhd->is_ssl) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Trying to set %s: %s\n", - hdr_type, - hdr_val+1); - if (GNUNET_NO == MHD_add_response_header (ctask->response, - hdr_type, - hdr_val+1)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "MHD: Error adding %s header field %s\n", - hdr_type, - hdr_val+1); - } + sprintf (leho_host, "https://%s", ctask->leho); + sprintf (real_host, "https://%s", ctask->host); + } + else + { + sprintf (leho_host, "http://%s", ctask->leho); + sprintf (real_host, "http://%s", ctask->host); + } + + if (0 == memcmp (leho_host, hdr_val, strlen (leho_host))) + { + sprintf (new_location, "%s%s", real_host, hdr_val+strlen (leho_host)); + hdr_val = new_location; } } - GNUNET_free (ndup); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to set %s: %s\n", + hdr_type, + hdr_val); + if (GNUNET_NO == MHD_add_response_header (ctask->response, + hdr_type, + hdr_val)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "MHD: Error adding %s header field %s\n", + hdr_type, + hdr_val); + } + GNUNET_free (ndup); return bytes; } @@ -607,85 +985,28 @@ run_httpd (struct MhdHttpList *hd); static void run_httpds (void); - /** - * Task that simply runs MHD main loop + * Task run whenever HTTP server operations are pending. * - * @param cls NULL - * @param tc task context + * @param cls unused + * @param tc sched context */ static void -run_mhd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - - struct MhdHttpList *hd = cls; - - //for (hd=mhd_httpd_head; hd != NULL; hd = hd->next) - MHD_run (hd->daemon); -} - +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); -/** - * Process cURL download bits - * - * @param ptr buffer with data - * @param size size of a record - * @param nmemb number of records downloaded - * @param ctx context - * @return number of processed bytes - */ -static size_t -callback_download (void *ptr, size_t size, size_t nmemb, void *ctx) +static void +run_mhd_now (struct MhdHttpList *hd) { - const char *cbuf = ptr; - size_t total; - struct ProxyCurlTask *ctask = ctx; - - //MHD_run (httpd); - ctask->ready_to_queue = GNUNET_YES; - /*if (ctask->con_status == MHD_NO) - { - MHD_queue_response (ctask->connection, - MHD_HTTP_OK, - ctask->response); - ctask->con_status = MHD_YES; - }*/ - total = size*nmemb; - - if (total == 0) - { - return total; - } - - if (total > sizeof (ctask->buffer)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "CURL gave us too much data to handle (%d)!\n", - total); - return 0; - } - - if (ctask->buf_status == BUF_WAIT_FOR_MHD) + if (GNUNET_SCHEDULER_NO_TASK != hd->httpd_task) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CURL: Waiting for MHD (%s)\n", ctask->url); - return CURL_WRITEFUNC_PAUSE; + "MHD: killing old task\n"); + GNUNET_SCHEDULER_cancel (hd->httpd_task); } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CURL: Copying to MHD (%s, %d)\n", ctask->url, total); - memcpy (ctask->buffer, cbuf, total); - ctask->bytes_in_buffer = total; - ctask->buffer_ptr = ctask->buffer; - - ctask->buf_status = BUF_WAIT_FOR_MHD; - - //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - // "cURL chunk:\n%s\n", (char*)ctask->buffer); - //run_mhd (NULL, NULL); - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); - return total; + "MHD: Scheduling MHD now\n"); + hd->httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, hd); } /** @@ -701,10 +1022,13 @@ curl_download_prepare (); * @param tc task context */ static void -mhd_content_free (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +mhd_content_free (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ProxyCurlTask *ctask = cls; + struct ProxyUploadData *pdata; + GNUNET_assert (NULL == ctask->pp_match_head); if (NULL != ctask->headers) curl_slist_free_all (ctask->headers); @@ -714,43 +1038,21 @@ mhd_content_free (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (NULL != ctask->response) MHD_destroy_response (ctask->response); - GNUNET_free (ctask); - -} - - -/** - * Shorten result callback - * - * @param cls the proxycurltask - * @param short_name the shortened name (NULL on error) - */ -static void -process_shorten (void* cls, const char* short_name) -{ - struct ProxyCurlTask *ctask = cls; - - char tmp[strlen(ctask->pp_buf)]; //TODO length + if (NULL != ctask->post_handler) + MHD_destroy_post_processor (ctask->post_handler); - if (NULL == short_name) + for (pdata = ctask->upload_data_head; NULL != pdata; pdata = ctask->upload_data_head) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD PP: Unable to shorten %s\n", - ctask->pp_buf); - return; + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free_non_null (pdata->filename); + GNUNET_free_non_null (pdata->content_type); + GNUNET_free_non_null (pdata->key); + GNUNET_free_non_null (pdata->value); + GNUNET_free (pdata); } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD PP: Shorten %s -> %s\n", - ctask->pp_buf, - short_name); - - sprintf (tmp, "pp_buf, tmp); - - ctask->pp_finished = GNUNET_YES; - - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); + GNUNET_free (ctask); } @@ -770,185 +1072,429 @@ mhd_content_cb (void *cls, size_t max) { struct ProxyCurlTask *ctask = cls; + struct ProxyREMatch *re_match; ssize_t copied = 0; - size_t bytes_to_copy; - int nomatch; - char *hostptr; - regmatch_t m[RE_N_MATCHES]; + long long int bytes_to_copy = ctask->buffer_write_ptr - ctask->buffer_read_ptr; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD: content cb %s\n", ctask->url); + "MHD: content cb for %s. To copy: %lld\n", + ctask->url, bytes_to_copy); + GNUNET_assert (bytes_to_copy >= 0); - if (ctask->download_successful && - (ctask->buf_status == BUF_WAIT_FOR_CURL)) + if ((GNUNET_YES == ctask->download_is_finished) && + (GNUNET_NO == ctask->download_error) && + (0 == bytes_to_copy)) /* && + (BUF_WAIT_FOR_CURL == ctask->buf_status))*/ { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "MHD: sending response for %s\n", ctask->url); ctask->download_in_progress = GNUNET_NO; + run_mhd_now (ctask->mhd); GNUNET_SCHEDULER_add_now (&mhd_content_free, ctask); - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); total_mhd_connections--; return MHD_CONTENT_READER_END_OF_STREAM; } - if (ctask->download_error && - (ctask->buf_status == BUF_WAIT_FOR_CURL)) + if ((GNUNET_YES == ctask->download_error) && + (GNUNET_YES == ctask->download_is_finished) && + (0 == bytes_to_copy)) /* && + (BUF_WAIT_FOR_CURL == ctask->buf_status))*/ { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "MHD: sending error response\n"); ctask->download_in_progress = GNUNET_NO; + run_mhd_now (ctask->mhd); GNUNET_SCHEDULER_add_now (&mhd_content_free, ctask); - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); total_mhd_connections--; return MHD_CONTENT_READER_END_WITH_ERROR; } if ( ctask->buf_status == BUF_WAIT_FOR_CURL ) return 0; - - bytes_to_copy = ctask->bytes_in_buffer; - if (ctask->parse_content == GNUNET_YES) + copied = 0; + for (re_match = ctask->pp_match_head; NULL != re_match; re_match = ctask->pp_match_head) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Processing PP %s\n", + re_match->hostname); + bytes_to_copy = re_match->start - ctask->buffer_read_ptr; + GNUNET_assert (bytes_to_copy >= 0); - GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG, - "MHD: We need to parse the HTML %s\n", ctask->buffer_ptr); + if (bytes_to_copy+copied > max) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: buffer in response too small for %d. Using available space (%d). (%s)\n", + bytes_to_copy, + max, + ctask->url); + memcpy (buf+copied, ctask->buffer_read_ptr, max-copied); + ctask->buffer_read_ptr += max-copied; + copied = max; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: copied %d bytes\n", copied); + return copied; + } - nomatch = regexec ( &re_dotplus, ctask->buffer_ptr, RE_N_MATCHES, m, 0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: copying %d bytes to mhd response at offset %d\n", + bytes_to_copy, ctask->buffer_read_ptr); + memcpy (buf+copied, ctask->buffer_read_ptr, bytes_to_copy); + copied += bytes_to_copy; - if (nomatch) + if (GNUNET_NO == re_match->done) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD RE: No match\n"); + "MHD: Waiting for PP of %s\n", re_match->hostname); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: copied %d bytes\n", copied); + ctask->buffer_read_ptr += bytes_to_copy; + return copied; } - else + + if (strlen (re_match->result) > (max - copied)) { + //FIXME partially copy domain here GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD RE: Match\n"); + "MHD: buffer in response too small for %s! (%s)\n", + re_match->result, + ctask->url); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: copied %d bytes\n", copied); + ctask->buffer_read_ptr += bytes_to_copy; + return copied; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding PP result %s to buffer\n", + re_match->result); + memcpy (buf+copied, re_match->result, strlen (re_match->result)); + copied += strlen (re_match->result); + ctask->buffer_read_ptr = re_match->end; + GNUNET_CONTAINER_DLL_remove (ctask->pp_match_head, + ctask->pp_match_tail, + re_match); + GNUNET_free (re_match); + } - GNUNET_assert (m[1].rm_so != -1); + bytes_to_copy = ctask->buffer_write_ptr - ctask->buffer_read_ptr; - hostptr = ctask->buffer_ptr+m[1].rm_so; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: copied: %d left: %d, space left in buf: %d\n", + copied, + bytes_to_copy, max-copied); + + GNUNET_assert (0 <= bytes_to_copy); - if (m[0].rm_so > 0) - { - bytes_to_copy = m[0].rm_so; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying %d bytes.\n", m[0].rm_so); + if (GNUNET_NO == ctask->download_is_finished) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Purging buffer\n"); + memmove (ctask->buffer, ctask->buffer_read_ptr, bytes_to_copy); + ctask->buffer_read_ptr = ctask->buffer; + ctask->buffer_write_ptr = ctask->buffer + bytes_to_copy; + ctask->buffer[bytes_to_copy] = '\0'; + } + + if (bytes_to_copy+copied > max) + bytes_to_copy = max-copied; + if (0 > bytes_to_copy) + bytes_to_copy = 0; + + memcpy (buf+copied, ctask->buffer_read_ptr, bytes_to_copy); + ctask->buffer_read_ptr += bytes_to_copy; + copied += bytes_to_copy; + ctask->buf_status = BUF_WAIT_FOR_CURL; + + if (NULL != ctask->curl) + curl_easy_pause (ctask->curl, CURLPAUSE_CONT); - } - else - { - if (ctask->is_postprocessing == GNUNET_YES) - { - - /*Done?*/ - if ( ctask->pp_finished == GNUNET_NO ) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "MHD PP: Waiting for PP of %s\n", ctask->pp_buf); - return 0; - } - - ctask->is_postprocessing = GNUNET_NO; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: copied %d bytes\n", copied); + run_mhd_now (ctask->mhd); + return copied; +} - ctask->bytes_in_buffer -= m[0].rm_eo;//(m[1].rm_eo-m[1].rm_so); - ctask->buffer_ptr += m[0].rm_eo;//(m[1].rm_eo-m[1].rm_so); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Skipping next %d bytes in buffer\n", m[0].rm_eo); - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); +/** + * Shorten result callback + * + * @param cls the proxycurltask + * @param short_name the shortened name (NULL on error) + */ +static void +process_shorten (void* cls, const char* short_name) +{ + struct ProxyREMatch *re_match = cls; + char result[sizeof (re_match->result)]; + + if (NULL == short_name) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: Unable to shorten %s\n", + re_match->hostname); + GNUNET_CONTAINER_DLL_remove (re_match->ctask->pp_match_head, + re_match->ctask->pp_match_tail, + re_match); + GNUNET_free (re_match); + return; + } + + if (0 == strcmp (short_name, re_match->ctask->leho)) + strcpy (result, re_match->ctask->host); + else + strcpy (result, short_name); - if ( strlen (ctask->pp_buf) <= max ) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying postprocessed %s.\n", ctask->pp_buf); - memcpy ( buf, ctask->pp_buf, strlen (ctask->pp_buf) ); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Done %s.\n", buf); - ctask->is_postprocessing = GNUNET_NO; - return strlen (ctask->pp_buf); - } - - return 0; - } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: Shorten %s -> %s\n", + re_match->hostname, + result); + + if (re_match->ctask->mhd->is_ssl) + sprintf (re_match->result, "href=\"https://%s", result); + else + sprintf (re_match->result, "href=\"http://%s", result); - memset (ctask->pp_buf, 0, sizeof(ctask->pp_buf)); - - /* If .+ extend with authority */ - if (*(ctask->buffer_ptr+m[1].rm_eo) == '+') - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Links is .+\n"); - memcpy (ctask->pp_buf, hostptr, (m[1].rm_eo-m[1].rm_so)); - strcpy ( ctask->pp_buf+strlen(ctask->pp_buf), - ctask->authority); - } - /* If .zkey simply copy the name */ - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Link is zkey\n"); - memcpy (ctask->pp_buf, hostptr, (m[1].rm_eo-m[1].rm_so + strlen (GNUNET_GNS_TLD_ZKEY))); - } + re_match->done = GNUNET_YES; + run_mhd_now (re_match->ctask->mhd); +} - ctask->is_postprocessing = GNUNET_YES; - ctask->pp_finished = GNUNET_NO; - - GNUNET_GNS_shorten_zone (gns_handle, - ctask->pp_buf, - &local_private_zone, - &local_shorten_zone, - &local_gns_zone, - &process_shorten, - ctask); - return 0; - } - } - } +/** + * Postprocess data in buffer. From read ptr to write ptr + * + * @param cls the curlproxytask + * @param tc task context + */ +static void +postprocess_buffer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ProxyCurlTask *ctask = cls; + struct ProxyREMatch *re_match; + char* re_ptr = ctask->buffer_read_ptr; + char re_hostname[255]; + regmatch_t m[RE_N_MATCHES]; + + ctask->pp_task = GNUNET_SCHEDULER_NO_TASK; - if ( bytes_to_copy > max ) + if (GNUNET_YES != ctask->parse_content) { - GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG, - "MHD: buffer in response too small! (%s)\n", - ctask->url); - memcpy ( buf, ctask->buffer_ptr, max); - ctask->bytes_in_buffer -= max; - ctask->buffer_ptr += max; - copied = max; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: Not parsing content\n"); + ctask->buf_status = BUF_WAIT_FOR_MHD; + run_mhd_now (ctask->mhd); + return; } - else + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: We need to parse the HTML\n"); + + /* 0 means match found */ + while (0 == regexec (&re_dotplus, re_ptr, RE_N_MATCHES, m, 0)) { - GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG, - "MHD: copying %d bytes to mhd response at offset %d\n", - bytes_to_copy, pos); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: regex match\n"); + + GNUNET_assert (m[1].rm_so != -1); + + memset (re_hostname, 0, sizeof (re_hostname)); + memcpy (re_hostname, re_ptr+m[1].rm_so, (m[3].rm_eo-m[1].rm_so)); + + re_match = GNUNET_malloc (sizeof (struct ProxyREMatch)); + re_match->start = re_ptr + m[0].rm_so; + re_match->end = re_ptr + m[3].rm_eo; + re_match->done = GNUNET_NO; + re_match->ctask = ctask; + strcpy (re_match->hostname, re_hostname); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: Got hostname %s\n", re_hostname); + re_ptr += m[3].rm_eo; - memcpy ( buf, ctask->buffer_ptr, bytes_to_copy ); - copied = bytes_to_copy; - if (bytes_to_copy < ctask->bytes_in_buffer) + if (GNUNET_YES == is_tld (re_match->hostname, GNUNET_GNS_TLD_PLUS)) { - ctask->bytes_in_buffer -= bytes_to_copy; - ctask->buffer_ptr += bytes_to_copy; + re_match->hostname[strlen(re_match->hostname)-1] = '\0'; + strcpy (re_match->hostname+strlen(re_match->hostname), + ctask->authority); } - else + + re_match->shorten_task = GNUNET_GNS_shorten_zone (gns_handle, + re_match->hostname, + local_private_zone, + local_shorten_zone, + local_gns_zone, + &process_shorten, + re_match); //FIXME cancel appropriately + + GNUNET_CONTAINER_DLL_insert_tail (ctask->pp_match_head, + ctask->pp_match_tail, + re_match); + } + + ctask->buf_status = BUF_WAIT_FOR_MHD; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PP: No more matches\n"); + run_mhd_now (ctask->mhd); +} + +/** + * Handle data from cURL + * + * @param ptr pointer to the data + * @param size number of blocks of data + * @param nmemb blocksize + * @param ctx the curlproxytask + * @return number of bytes handled + */ +static size_t +curl_download_cb (void *ptr, size_t size, size_t nmemb, void* ctx) +{ + const char *cbuf = ptr; + size_t total = size * nmemb; + struct ProxyCurlTask *ctask = ctx; + size_t buf_space = sizeof (ctask->buffer) - + (ctask->buffer_write_ptr-ctask->buffer); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Got %d. %d free in buffer\n", + total, buf_space); + + if (BUF_WAIT_FOR_CURL != ctask->buf_status) + return CURL_WRITEFUNC_PAUSE; + + if (total > (buf_space - CURL_BUF_PADDING)) + { + if (ctask->buf_status == BUF_WAIT_FOR_CURL) { - ctask->bytes_in_buffer = 0; - ctask->buf_status = BUF_WAIT_FOR_CURL; - ctask->buffer_ptr = ctask->buffer; - if (NULL != ctask->curl) - curl_easy_pause (ctask->curl, CURLPAUSE_CONT); - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Buffer full starting postprocessing\n"); + ctask->buf_status = BUF_WAIT_FOR_PP; + ctask->pp_task = GNUNET_SCHEDULER_add_now (&postprocess_buffer, + ctask); + return CURL_WRITEFUNC_PAUSE; } + + /* we should not get called in that case */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "CURL: called out of context and no space in buffer!\n"); + return CURL_WRITEFUNC_PAUSE; } - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Copying %d bytes to buffer (%s)\n", total, ctask->url); + memcpy (ctask->buffer_write_ptr, cbuf, total); + ctask->bytes_in_buffer += total; + ctask->buffer_write_ptr += total; + ctask->buffer_write_ptr[0] = '\0'; + + return total; +} + + +/** + * cURL callback for put data + */ +static size_t +put_read_callback (void *buf, size_t size, size_t nmemb, void *cls) +{ + struct ProxyCurlTask *ctask = cls; + struct ProxyUploadData *pdata = ctask->upload_data_head; + size_t len = size * nmemb; + size_t to_copy; + char* pos; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: put read callback\n"); + + if (NULL == pdata) + return CURL_READFUNC_PAUSE; + + //fin + if (NULL == pdata->value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Terminating PUT\n"); + + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free (pdata); + return 0; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: read callback value %s\n", pdata->value); + + to_copy = pdata->bytes_left; + if (to_copy > len) + to_copy = len; + + pos = pdata->value + (pdata->total_bytes - pdata->bytes_left); + memcpy (buf, pos, to_copy); + pdata->bytes_left -= to_copy; + if (pdata->bytes_left <= 0) + { + GNUNET_free (pdata->value); + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free (pdata); + } + return to_copy; +} + + +/** + * cURL callback for post data + */ +static size_t +post_read_callback (void *buf, size_t size, size_t nmemb, void *cls) +{ + struct ProxyCurlTask *ctask = cls; + struct ProxyUploadData *pdata = ctask->upload_data_head; + size_t len = size * nmemb; + size_t to_copy; + char* pos; - return copied; -} + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: read callback\n"); + if (NULL == pdata) + return CURL_READFUNC_PAUSE; + + //fin + if (NULL == pdata->value) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Terminating POST data\n"); + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free (pdata); + return 0; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: read callback value %s\n", pdata->value); + + to_copy = pdata->bytes_left; + if (to_copy > len) + to_copy = len; + + pos = pdata->value + (pdata->total_bytes - pdata->bytes_left); + memcpy (buf, pos, to_copy); + pdata->bytes_left -= to_copy; + if (pdata->bytes_left <= 0) + { + GNUNET_free (pdata->value); + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free (pdata); + } + return to_copy; +} /** * Task that is run when we are ready to receive more data @@ -1008,14 +1554,23 @@ curl_download_prepare () if (curl_download_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (curl_download_task); - curl_download_task = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - rtime, - grs, gws, - &curl_task_download, curl_multi); + if (-1 != max) + { + curl_download_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + rtime, + grs, gws, + &curl_task_download, curl_multi); + } + else if (NULL != ctasks_head) + { + /* as specified in curl docs */ + curl_download_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, + &curl_task_download, + curl_multi); + } GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); - } @@ -1044,10 +1599,10 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown requested while trying to download\n"); - //TODO cleanup - return; + //TODO cleanup + return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ready to dl\n"); @@ -1062,8 +1617,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running curl tasks: %d\n", running); - ctask = ctasks_head; - for (; ctask != NULL; ctask = ctask->next) + for (ctask = ctasks_head; NULL != ctask; ctask = ctask->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CTask: %s\n", ctask->url); @@ -1078,7 +1632,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) do { - ctask = ctasks_head; + msg = curl_multi_info_read (curl_multi, &msgnum); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Messages left: %d\n", msgnum); @@ -1094,7 +1648,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Download curl failed"); - for (; ctask != NULL; ctask = ctask->next) + for (ctask = ctasks_head; NULL != ctask; ctask = ctask->next) { if (NULL == ctask->curl) continue; @@ -1103,17 +1657,18 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) continue; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Download curl failed for task %s: %s.\n", + "CURL: Download failed for task %s: %s.\n", ctask->url, curl_easy_strerror (msg->data.result)); - ctask->download_successful = GNUNET_NO; + ctask->download_is_finished = GNUNET_YES; ctask->download_error = GNUNET_YES; if (CURLE_OK == curl_easy_getinfo (ctask->curl, CURLINFO_RESPONSE_CODE, &resp_code)) ctask->curl_response_code = resp_code; ctask->ready_to_queue = MHD_YES; - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); + ctask->buf_status = BUF_WAIT_FOR_MHD; + run_mhd_now (ctask->mhd); GNUNET_CONTAINER_DLL_remove (ctasks_head, ctasks_tail, ctask); @@ -1125,26 +1680,37 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "cURL download completed.\n"); + "CURL: download completed.\n"); - for (; ctask != NULL; ctask = ctask->next) + for (ctask = ctasks_head; NULL != ctask; ctask = ctask->next) { if (NULL == ctask->curl) continue; - if (memcmp (msg->easy_handle, ctask->curl, sizeof (CURL)) != 0) + if (0 != memcmp (msg->easy_handle, ctask->curl, sizeof (CURL))) continue; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "cURL task %s found.\n", ctask->url); + "CURL: completed task %s found.\n", ctask->url); if (CURLE_OK == curl_easy_getinfo (ctask->curl, CURLINFO_RESPONSE_CODE, &resp_code)) ctask->curl_response_code = resp_code; + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CURL: Completed ctask!\n"); + if (GNUNET_SCHEDULER_NO_TASK == ctask->pp_task) + { + ctask->buf_status = BUF_WAIT_FOR_PP; + ctask->pp_task = GNUNET_SCHEDULER_add_now (&postprocess_buffer, + ctask); + } + ctask->ready_to_queue = MHD_YES; - ctask->download_successful = GNUNET_YES; + ctask->download_is_finished = GNUNET_YES; - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); + /* We MUST not modify the multi handle else we loose messages */ GNUNET_CONTAINER_DLL_remove (ctasks_head, ctasks_tail, ctask); GNUNET_CONTAINER_DLL_insert (clean_head, clean_tail, ctask); @@ -1154,7 +1720,7 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (ctask != NULL); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "curl end %s\n", curl_easy_strerror(msg->data.result)); + "CURL: %s\n", curl_easy_strerror(msg->data.result)); break; default: GNUNET_assert (0); @@ -1162,17 +1728,17 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } } while (msgnum > 0); - for (ctask=clean_head; ctask != NULL; ctask = ctask->next) + for (ctask=clean_head; NULL != ctask; ctask = ctask->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removing cURL task %s.\n", ctask->url); + "CURL: Removing task %s.\n", ctask->url); curl_multi_remove_handle (curl_multi, ctask->curl); curl_easy_cleanup (ctask->curl); ctask->curl = NULL; } num_ctasks=0; - for (ctask=ctasks_head; ctask != NULL; ctask = ctask->next) + for (ctask=ctasks_head; NULL != ctask; ctask = ctask->next) { num_ctasks++; } @@ -1180,25 +1746,23 @@ curl_task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (num_ctasks != running) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%d ctasks, %d curl running\n", num_ctasks, running); + "CURL: %d tasks, %d running\n", num_ctasks, running); } GNUNET_assert ( num_ctasks == running ); - run_httpds (); - } while (mret == CURLM_CALL_MULTI_PERFORM); - if (mret != CURLM_OK) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s failed at %s:%d: `%s'\n", + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CURL: %s failed at %s:%d: `%s'\n", "curl_multi_perform", __FILE__, __LINE__, curl_multi_strerror (mret)); } curl_download_prepare(); } + /** * Process LEHO lookup * @@ -1240,7 +1804,7 @@ process_leho_lookup (void *cls, if (0 != strcmp (ctask->leho, "")) { - sprintf (hosthdr, "%s%s", "Host: ", ctask->leho); + sprintf (hosthdr, "%s%s:%d", "Host: ", ctask->leho, ctask->port); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New HTTP header value: %s\n", hosthdr); ctask->headers = curl_slist_append (ctask->headers, hosthdr); @@ -1268,14 +1832,14 @@ process_leho_lookup (void *cls, "Curl resolve: %s\n", resolvename); ctask->resolver = curl_slist_append ( ctask->resolver, resolvename); curl_easy_setopt (ctask->curl, CURLOPT_RESOLVE, ctask->resolver); - sprintf (curlurl, "https://%s%s", ctask->leho, ctask->url); + sprintf (curlurl, "https://%s:%d%s", ctask->leho, ctask->port, ctask->url); curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "gethostbyname failed for %s!\n", ctask->host); - ctask->download_successful = GNUNET_NO; + ctask->download_is_finished = GNUNET_YES; ctask->download_error = GNUNET_YES; return; } @@ -1287,7 +1851,7 @@ process_leho_lookup (void *cls, "%s failed at %s:%d: `%s'\n", "curl_multi_add_handle", __FILE__, __LINE__, curl_multi_strerror (mret)); - ctask->download_successful = GNUNET_NO; + ctask->download_is_finished = GNUNET_YES; ctask->download_error = GNUNET_YES; return; } @@ -1325,7 +1889,7 @@ process_get_authority (void *cls, GNUNET_GNS_lookup_zone (gns_handle, ctask->host, - &local_gns_zone, + local_gns_zone, GNUNET_GNS_RECORD_LEHO, GNUNET_YES, //Only cached for performance shorten_zonekey, @@ -1333,15 +1897,16 @@ process_get_authority (void *cls, ctask); } -/** - * Task run whenever HTTP server operations are pending. - * - * @param cls unused - * @param tc sched context - */ -static void -do_httpd (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); +static void* +mhd_log_callback (void* cls, const char* url) +{ + struct ProxyCurlTask *ctask; + + ctask = GNUNET_malloc (sizeof (struct ProxyCurlTask)); + strcpy (ctask->url, url); + ctask->accepted = GNUNET_NO; + return ctask; +} /** * Main MHD callback for handling requests. @@ -1380,34 +1945,36 @@ create_response (void *cls, const char* page = "gnoxy"\ "cURL fail"; - char curlurl[512]; + char curlurl[MAX_HTTP_URI_LENGTH]; // buffer overflow! int ret = MHD_YES; + int i; - struct ProxyCurlTask *ctask; + struct ProxyCurlTask *ctask = *con_cls; + struct ProxyUploadData *fin_post; + struct curl_forms forms[5]; + struct ProxyUploadData *upload_data_iter; //FIXME handle - if (0 != strcmp (meth, "GET")) - return MHD_NO; - - if (0 != *upload_data_size) + if ((0 != strcasecmp (meth, MHD_HTTP_METHOD_GET)) && + (0 != strcasecmp (meth, MHD_HTTP_METHOD_PUT)) && + (0 != strcasecmp (meth, MHD_HTTP_METHOD_POST)) && + (0 != strcasecmp (meth, MHD_HTTP_METHOD_HEAD))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "MHD: %s NOT IMPLEMENTED!\n", meth); return MHD_NO; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "url %s\n", url); + } - if (NULL == *con_cls) + if (GNUNET_NO == ctask->accepted) { - ctask = GNUNET_malloc (sizeof (struct ProxyCurlTask)); - ctask->mhd = hd; - *con_cls = ctask; - - if (curl_multi == NULL) - curl_multi = curl_multi_init (); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Got %s request for %s\n", meth, url); + ctask->mhd = hd; ctask->curl = curl_easy_init(); - - if ((ctask->curl == NULL) || (curl_multi == NULL)) + ctask->curl_running = GNUNET_NO; + if (NULL == ctask->curl) { ctask->response = MHD_create_response_from_buffer (strlen (page), (void*)page, @@ -1419,90 +1986,209 @@ create_response (void *cls, GNUNET_free (ctask); return ret; } - - ctask->prev = NULL; - ctask->next = NULL; - ctask->headers = NULL; - ctask->resolver = NULL; - ctask->buffer_ptr = NULL; - ctask->download_in_progress = GNUNET_YES; - ctask->download_successful = GNUNET_NO; - ctask->buf_status = BUF_WAIT_FOR_CURL; - ctask->bytes_in_buffer = 0; - ctask->parse_content = GNUNET_NO; - ctask->connection = con; - ctask->ready_to_queue = MHD_NO; - ctask->fin = GNUNET_NO; - ctask->headers = NULL; - ctask->curl_response_code = MHD_HTTP_OK; - + + if (ctask->mhd->is_ssl) + ctask->port = HTTPS_PORT; + else + ctask->port = HTTP_PORT; MHD_get_connection_values (con, MHD_HEADER_KIND, &con_val_iter, ctask); - + curl_easy_setopt (ctask->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr); curl_easy_setopt (ctask->curl, CURLOPT_HEADERDATA, ctask); - curl_easy_setopt (ctask->curl, CURLOPT_WRITEFUNCTION, &callback_download); + curl_easy_setopt (ctask->curl, CURLOPT_WRITEFUNCTION, &curl_download_cb); curl_easy_setopt (ctask->curl, CURLOPT_WRITEDATA, ctask); curl_easy_setopt (ctask->curl, CURLOPT_FOLLOWLOCATION, 0); - //curl_easy_setopt (ctask->curl, CURLOPT_MAXREDIRS, 4); - /* no need to abort if the above failed */ + curl_easy_setopt (ctask->curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + if (GNUNET_NO == ctask->mhd->is_ssl) { - sprintf (curlurl, "http://%s%s", ctask->host, url); + sprintf (curlurl, "http://%s:%d%s", ctask->host, ctask->port, ctask->url); curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding new curl task for %s\n", curlurl); } - strcpy (ctask->url, url); - - //curl_easy_setopt (ctask->curl, CURLOPT_URL, curlurl); + + curl_easy_setopt (ctask->curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt (ctask->curl, CURLOPT_CONNECTTIMEOUT, 600L); curl_easy_setopt (ctask->curl, CURLOPT_TIMEOUT, 600L); + + /* Add GNS header */ + ctask->headers = curl_slist_append (ctask->headers, + "GNS: YES"); + ctask->accepted = GNUNET_YES; + ctask->download_in_progress = GNUNET_YES; + ctask->buf_status = BUF_WAIT_FOR_CURL; + ctask->connection = con; + ctask->curl_response_code = MHD_HTTP_OK; + ctask->buffer_read_ptr = ctask->buffer; + ctask->buffer_write_ptr = ctask->buffer; + ctask->pp_task = GNUNET_SCHEDULER_NO_TASK; + + + if (0 == strcasecmp (meth, MHD_HTTP_METHOD_PUT)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting up PUT\n"); + + curl_easy_setopt (ctask->curl, CURLOPT_UPLOAD, 1); + curl_easy_setopt (ctask->curl, CURLOPT_READDATA, ctask); + curl_easy_setopt (ctask->curl, CURLOPT_READFUNCTION, &put_read_callback); + ctask->headers = curl_slist_append (ctask->headers, + "Transfer-Encoding: chunked"); + } + + if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST)) + { + //FIXME handle multipart + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting up POST processor\n"); + ctask->post_handler = MHD_create_post_processor (con, + POSTBUFFERSIZE, + &con_post_data_iter, + ctask); + ctask->headers = curl_slist_append (ctask->headers, + "Transfer-Encoding: chunked"); + return MHD_YES; + } + + if (0 == strcasecmp (meth, MHD_HTTP_METHOD_HEAD)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting NOBODY\n"); + curl_easy_setopt (ctask->curl, CURLOPT_NOBODY, 1); + } + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding new curl task for %s\n", ctask->host); GNUNET_GNS_get_authority (gns_handle, ctask->host, &process_get_authority, ctask); - - ctask->response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, - 20, - &mhd_content_cb, - ctask, - NULL); - ctask->ready_to_queue = GNUNET_NO; ctask->fin = GNUNET_NO; + ctask->curl_running = GNUNET_YES; return MHD_YES; } ctask = (struct ProxyCurlTask *) *con_cls; + if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST)) + { + if (0 != *upload_data_size) + { + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Invoking POST processor\n"); + MHD_post_process (ctask->post_handler, + upload_data, *upload_data_size); + *upload_data_size = 0; + if ((GNUNET_NO == ctask->is_httppost) && + (GNUNET_NO == ctask->curl_running)) + { + curl_easy_setopt (ctask->curl, CURLOPT_POST, 1); + curl_easy_setopt (ctask->curl, CURLOPT_READFUNCTION, + &post_read_callback); + curl_easy_setopt (ctask->curl, CURLOPT_READDATA, ctask); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding new curl task for %s\n", ctask->host); + + GNUNET_GNS_get_authority (gns_handle, + ctask->host, + &process_get_authority, + ctask); + ctask->ready_to_queue = GNUNET_NO; + ctask->fin = GNUNET_NO; + ctask->curl_running = GNUNET_YES; + } + return MHD_YES; + } + else if (GNUNET_NO == ctask->post_done) + { + if (GNUNET_YES == ctask->is_httppost) + { + for (upload_data_iter = ctask->upload_data_head; + NULL != upload_data_iter; + upload_data_iter = upload_data_iter->next) + { + i = 0; + if (NULL != upload_data_iter->filename) + { + forms[i].option = CURLFORM_FILENAME; + forms[i].value = upload_data_iter->filename; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding filename %s\n", + forms[i].value); + i++; + } + if (NULL != upload_data_iter->content_type) + { + forms[i].option = CURLFORM_CONTENTTYPE; + forms[i].value = upload_data_iter->content_type; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding content type %s\n", + forms[i].value); + i++; + } + forms[i].option = CURLFORM_PTRCONTENTS; + forms[i].value = upload_data_iter->value; + forms[i+1].option = CURLFORM_END; - if (ctask->fin == GNUNET_YES) - return MHD_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding formdata for %s (len=%lld)\n", + upload_data_iter->key, + upload_data_iter->total_bytes); + + curl_formadd(&ctask->httppost, &ctask->httppost_last, + CURLFORM_COPYNAME, upload_data_iter->key, + CURLFORM_CONTENTSLENGTH, upload_data_iter->total_bytes, + CURLFORM_ARRAY, forms, + CURLFORM_END); + } + curl_easy_setopt (ctask->curl, CURLOPT_HTTPPOST, + ctask->httppost); - if (ctask->ready_to_queue == GNUNET_YES) - { - ctask->fin = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Adding new curl task for %s\n", ctask->host); + + GNUNET_GNS_get_authority (gns_handle, + ctask->host, + &process_get_authority, + ctask); + ctask->ready_to_queue = GNUNET_YES; + ctask->fin = GNUNET_NO; + ctask->curl_running = GNUNET_YES; + ctask->post_done = GNUNET_YES; + return MHD_YES; + } - ret = MHD_queue_response (con, ctask->curl_response_code, ctask->response); - GNUNET_SCHEDULER_add_now (&run_mhd, ctask->mhd); - return ret; + fin_post = GNUNET_malloc (sizeof (struct ProxyUploadData)); + GNUNET_CONTAINER_DLL_insert_tail (ctask->upload_data_head, + ctask->upload_data_tail, + fin_post); + ctask->post_done = GNUNET_YES; + return MHD_YES; + } } - + if (GNUNET_YES != ctask->ready_to_queue) + return MHD_YES; /* wait longer */ - - //MHD_destroy_response (response); + if (GNUNET_YES == ctask->fin) + return MHD_YES; - //return ret; - return MHD_YES; + ctask->fin = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Queueing response for %s\n", ctask->url); + ret = MHD_queue_response (con, ctask->curl_response_code, ctask->response); + run_mhd_now (ctask->mhd); + return ret; } - /** * run all httpd */ @@ -1511,7 +2197,7 @@ run_httpds () { struct MhdHttpList *hd; - for (hd=mhd_httpd_head; hd != NULL; hd = hd->next) + for (hd=mhd_httpd_head; NULL != hd; hd = hd->next) run_httpd (hd); } @@ -1550,7 +2236,7 @@ run_httpd (struct MhdHttpList *hd) haveto = MHD_get_timeout (hd->daemon, &timeout); - if (haveto == MHD_YES) + if (MHD_YES == haveto) tv.rel_value = (uint64_t) timeout; else tv = GNUNET_TIME_UNIT_FOREVER_REL; @@ -1558,7 +2244,7 @@ run_httpd (struct MhdHttpList *hd) GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); - if (hd->httpd_task != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != hd->httpd_task) GNUNET_SCHEDULER_cancel (hd->httpd_task); hd->httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, @@ -1582,13 +2268,15 @@ do_httpd (void *cls, { struct MhdHttpList *hd = cls; - hd->httpd_task = GNUNET_SCHEDULER_NO_TASK; - + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "MHD: Main loop\n"); + hd->httpd_task = GNUNET_SCHEDULER_NO_TASK; MHD_run (hd->daemon); run_httpd (hd); } + /** * Read data from socket * @@ -1633,12 +2321,11 @@ do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) else { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote"); - //Really!?!?!? - if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != s5r->rtask) GNUNET_SCHEDULER_cancel (s5r->rtask); - if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != s5r->wtask) GNUNET_SCHEDULER_cancel (s5r->wtask); - if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != s5r->fwdrtask) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); GNUNET_NETWORK_socket_close (s5r->remote_sock); GNUNET_NETWORK_socket_close (s5r->sock); @@ -1661,11 +2348,11 @@ do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void cleanup_s5r (struct Socks5Request *s5r) { - if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != s5r->rtask) GNUNET_SCHEDULER_cancel (s5r->rtask); - if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != s5r->fwdwtask) GNUNET_SCHEDULER_cancel (s5r->fwdwtask); - if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + if (GNUNET_SCHEDULER_NO_TASK != s5r->fwdrtask) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); if (NULL != s5r->remote_sock) @@ -1793,33 +2480,6 @@ add_handle_to_mhd (struct GNUNET_NETWORK_Handle *h, struct MHD_Daemon *daemon) return MHD_add_connection (daemon, fd, addr, len); } -/** - * Calculate size of file - * - * @param filename name of file - * @return filesize or 0 on error - */ -static long -get_file_size (const char* filename) -{ - FILE *fp; - - fp = fopen (filename, "rb"); - if (fp) - { - long size; - - if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp)))) - size = 0; - - fclose (fp); - - return size; - } - - return 0; -} - /** * Read file in filename * @@ -1828,90 +2488,82 @@ get_file_size (const char* filename) * @return data */ static char* -load_file (const char* filename, unsigned int* size) +load_file (const char* filename, + unsigned int* size) { - FILE *fp; char *buffer; + uint64_t fsize; - *size = get_file_size (filename); - if (*size == 0) + if (GNUNET_OK != + GNUNET_DISK_file_size (filename, &fsize, + GNUNET_YES, GNUNET_YES)) return NULL; - - fp = fopen (filename, "rb"); - if (!fp) + if (fsize > MAX_PEM_SIZE) return NULL; - + *size = (unsigned int) fsize; buffer = GNUNET_malloc (*size); - if (!buffer) - { - fclose (fp); - return NULL; - } - - if (*size != fread (buffer, 1, *size, fp)) + if (fsize != GNUNET_DISK_fn_read (filename, buffer, (size_t) fsize)) { GNUNET_free (buffer); - buffer = NULL; + return NULL; } - - fclose (fp); return buffer; } + /** * Load PEM key from file * * @param key where to store the data * @param keyfile path to the PEM file + * @return GNUNET_OK on success */ -static void -load_key_from_file (gnutls_x509_privkey_t key, char* keyfile) +static int +load_key_from_file (gnutls_x509_privkey_t key, const char* keyfile) { gnutls_datum_t key_data; - key_data.data = NULL; int ret; - key_data.data = (unsigned char*)load_file (keyfile, &key_data.size); - + key_data.data = (unsigned char*) load_file (keyfile, &key_data.size); ret = gnutls_x509_privkey_import (key, &key_data, GNUTLS_X509_FMT_PEM); - if (GNUTLS_E_SUCCESS != ret) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to import private key %s(ret=%d)\n", key_data.data, ret); + _("Unable to import private key from file `%s'\n"), + keyfile); GNUNET_break (0); } - GNUNET_free (key_data.data); + return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK; } + /** * Load cert from file * * @param crt struct to store data in * @param certfile path to pem file + * @return GNUNET_OK on success */ -static void +static int load_cert_from_file (gnutls_x509_crt_t crt, char* certfile) { gnutls_datum_t cert_data; cert_data.data = NULL; int ret; - cert_data.data = (unsigned char*)load_file (certfile, &cert_data.size); - + cert_data.data = (unsigned char*) load_file (certfile, &cert_data.size); ret = gnutls_x509_crt_import (crt, &cert_data, - GNUTLS_X509_FMT_PEM); + GNUTLS_X509_FMT_PEM); if (GNUTLS_E_SUCCESS != ret) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to import certificate %s(ret=%d)\n", certfile, ret); + _("Unable to import certificate %s\n"), certfile); GNUNET_break (0); } - GNUNET_free (cert_data.data); - + return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK; } @@ -2048,21 +2700,18 @@ accept_cb (void* cls, const struct sockaddr *addr, socklen_t addrlen) * @return MHD_YES on success */ static int -add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, char* domain) +add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, const char* domain) { struct MhdHttpList *hd = NULL; struct ProxyGNSCertificate *pgc; struct NetworkHandleList *nh; - for (hd = mhd_httpd_head; hd != NULL; hd = hd->next) - { + for (hd = mhd_httpd_head; NULL != hd; hd = hd->next) if (0 == strcmp (hd->domain, domain)) break; - } if (NULL == hd) - { - + { pgc = generate_gns_certificate (domain); hd = GNUNET_malloc (sizeof (struct MhdHttpList)); @@ -2074,18 +2723,28 @@ add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, char* domain) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No previous SSL instance found... starting new one for %s\n", domain); - - hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL, 4444, - &accept_cb, NULL, - &create_response, hd, + hd->daemon = MHD_start_daemon (MHD_USE_DEBUG + | MHD_USE_SSL +#if HAVE_MHD_NO_LISTEN_SOCKET + | MHD_USE_NO_LISTEN_SOCKET, + 0, +#else + , 4444, //Dummy +#endif + &accept_cb, NULL, + &create_response, hd, +#if !HAVE_MHD_NO_LISTEN_SOCKET MHD_OPTION_LISTEN_SOCKET, GNUNET_NETWORK_get_fd (mhd_unix_socket), - MHD_OPTION_CONNECTION_LIMIT, MHD_MAX_CONNECTIONS, - MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, - MHD_OPTION_NOTIFY_COMPLETED, - NULL, NULL, - MHD_OPTION_HTTPS_MEM_KEY, pgc->key, - MHD_OPTION_HTTPS_MEM_CERT, pgc->cert, - MHD_OPTION_END); +#endif + MHD_OPTION_CONNECTION_LIMIT, + MHD_MAX_CONNECTIONS, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, + MHD_OPTION_HTTPS_MEM_KEY, pgc->key, + MHD_OPTION_HTTPS_MEM_CERT, pgc->cert, + MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, + NULL, + MHD_OPTION_END); GNUNET_assert (hd->daemon != NULL); hd->httpd_task = GNUNET_SCHEDULER_NO_TASK; @@ -2385,8 +3044,6 @@ do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } - //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r); - } @@ -2430,7 +3087,6 @@ do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_read, s5r); - //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r); } @@ -2451,11 +3107,19 @@ do_shutdown (void *cls, struct NetworkHandleList *tmp_nh; struct ProxyCurlTask *ctask; struct ProxyCurlTask *ctask_tmp; + struct ProxyUploadData *pdata; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n"); gnutls_global_deinit (); + + if (NULL != local_gns_zone) + GNUNET_free (local_gns_zone); + if (NULL != local_private_zone) + GNUNET_free (local_private_zone); + if (NULL != local_shorten_zone) + GNUNET_free (local_shorten_zone); if (GNUNET_SCHEDULER_NO_TASK != curl_download_task) { @@ -2522,9 +3186,24 @@ do_shutdown (void *cls, if (NULL != ctask->response) MHD_destroy_response (ctask->response); + pdata = ctask->upload_data_head; + + //FIXME free pdata here + for (; pdata != NULL; pdata = ctask->upload_data_head) + { + GNUNET_CONTAINER_DLL_remove (ctask->upload_data_head, + ctask->upload_data_tail, + pdata); + GNUNET_free_non_null (pdata->filename); + GNUNET_free_non_null (pdata->content_type); + GNUNET_free_non_null (pdata->key); + GNUNET_free_non_null (pdata->value); + GNUNET_free (pdata); + } GNUNET_free (ctask); } + curl_multi_cleanup (curl_multi); GNUNET_GNS_disconnect (gns_handle); } @@ -2587,69 +3266,74 @@ load_local_zone_key (const struct GNUNET_CONFIGURATION_Handle *cfg) key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + local_gns_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); GNUNET_CRYPTO_short_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &local_gns_zone); - zone = &local_gns_zone; + local_gns_zone); + zone = local_gns_zone; GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zone: %s!\n", &zonename); GNUNET_CRYPTO_rsa_key_free(key); GNUNET_free(keyfile); - + keyfile = NULL; + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "PRIVATE_ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load private zone key config value!\n"); - return GNUNET_NO; } - if (GNUNET_NO == GNUNET_DISK_file_test (keyfile)) + if ((NULL != keyfile) && (GNUNET_NO == GNUNET_DISK_file_test (keyfile))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load private zone key %s!\n", keyfile); GNUNET_free(keyfile); - return GNUNET_NO; } - - key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); - GNUNET_CRYPTO_short_hash(&pkey, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &local_private_zone); - GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using private zone: %s!\n", &zonename); - GNUNET_CRYPTO_rsa_key_free(key); - GNUNET_free(keyfile); + else + { + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + local_private_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + GNUNET_CRYPTO_short_hash(&pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + local_private_zone); + GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using private zone: %s!\n", &zonename); + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + } + keyfile = NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "SHORTEN_ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load shorten zone key config value!\n"); - return GNUNET_NO; } - if (GNUNET_NO == GNUNET_DISK_file_test (keyfile)) + if ((NULL != keyfile) && (GNUNET_NO == GNUNET_DISK_file_test (keyfile))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to load shorten zone key %s!\n", keyfile); GNUNET_free(keyfile); - return GNUNET_NO; } - - key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); - GNUNET_CRYPTO_short_hash(&pkey, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &local_shorten_zone); - GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using shorten zone: %s!\n", &zonename); - GNUNET_CRYPTO_rsa_key_free(key); - GNUNET_free(keyfile); + else + { + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + local_shorten_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + GNUNET_CRYPTO_short_hash(&pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + local_shorten_zone); + GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using shorten zone: %s!\n", &zonename); + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + } return GNUNET_YES; } @@ -2668,19 +3352,26 @@ run (void *cls, char *const *args, const char *cfgfile, { struct sockaddr_in sa; struct MhdHttpList *hd; - struct sockaddr_un mhd_unix_sock_addr; - size_t len; - char* proxy_sockfile; char* cafile_cfg = NULL; char* cafile; +#if !HAVE_MHD_NO_LISTEN_SOCKET + size_t len; + char* proxy_sockfile; + struct sockaddr_un mhd_unix_sock_addr; +#endif - curl_multi = NULL; + curl_multi = curl_multi_init (); + if (NULL == curl_multi) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to create cURL multo handle!\n"); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading CA\n"); - cafile = cafile_opt; - if (NULL == cafile) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns-proxy", @@ -2695,14 +3386,19 @@ run (void *cls, char *const *args, const char *cfgfile, } cafile = cafile_cfg; } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using %s as CA\n", cafile); gnutls_global_init (); - gnutls_x509_crt_init (&proxy_ca.cert); gnutls_x509_privkey_init (&proxy_ca.key); - load_cert_from_file (proxy_ca.cert, cafile); - load_key_from_file (proxy_ca.key, cafile); + if ( (GNUNET_OK != load_cert_from_file (proxy_ca.cert, cafile)) || + (GNUNET_OK != load_key_from_file (proxy_ca.key, cafile)) ) + { + // FIXME: release resources... + return; + } GNUNET_free_non_null (cafile_cfg); @@ -2779,7 +3475,7 @@ run (void *cls, char *const *args, const char *cfgfile, mhd_httpd_head = NULL; mhd_httpd_tail = NULL; total_mhd_connections = 0; - +#ifndef HAVE_MHD_NO_LISTEN_SOCKET if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns-proxy", "PROXY_UNIXPATH", &proxy_sockfile)) @@ -2788,7 +3484,7 @@ run (void *cls, char *const *args, const char *cfgfile, "Specify PROXY_UNIXPATH in gns-proxy config section!\n"); return; } - + mhd_unix_socket = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); @@ -2830,18 +3526,28 @@ run (void *cls, char *const *args, const char *cfgfile, "Unable to listen on unix domain socket!\n"); return; } +#endif hd = GNUNET_malloc (sizeof (struct MhdHttpList)); hd->is_ssl = GNUNET_NO; strcpy (hd->domain, ""); - httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444, //Dummy port + httpd = MHD_start_daemon (MHD_USE_DEBUG +#if HAVE_MHD_NO_LISTEN_SOCKET + | MHD_USE_NO_LISTEN_SOCKET, + 0, +#else + , 4444, //Dummy port +#endif &accept_cb, NULL, &create_response, hd, +#if !HAVE_MHD_NO_LISTEN_SOCKET MHD_OPTION_LISTEN_SOCKET, GNUNET_NETWORK_get_fd (mhd_unix_socket), +#endif MHD_OPTION_CONNECTION_LIMIT, MHD_MAX_CONNECTIONS, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, + MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL, MHD_OPTION_END); GNUNET_assert (httpd != NULL); @@ -2895,3 +3601,7 @@ main (int argc, char *const *argv) return ret; } + + + +