diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-09-20 17:46:42 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-09-20 17:46:42 +0200 |
commit | d4f3a2eed509d1719b58031a9fa74cd2e669327f (patch) | |
tree | 753ba9fcbf0eb17ff55e34f970458d059e3bd431 | |
parent | 2f69f626b0e47a7affa206038c217cc0bb09e49c (diff) | |
download | twister-d4f3a2eed509d1719b58031a9fa74cd2e669327f.tar.gz twister-d4f3a2eed509d1719b58031a9fa74cd2e669327f.tar.bz2 twister-d4f3a2eed509d1719b58031a9fa74cd2e669327f.zip |
port state engine fixes from GNS proxy to twister service
-rw-r--r-- | m4/libtool.m4 | 12 | ||||
-rw-r--r-- | src/twister/taler-twister-service.c | 200 |
2 files changed, 166 insertions, 46 deletions
diff --git a/m4/libtool.m4 b/m4/libtool.m4 index ee80844..e67ed69 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -6438,7 +6438,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no @@ -6813,7 +6813,7 @@ if test yes != "$_lt_caught_CXX_error"; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then @@ -6878,7 +6878,7 @@ if test yes != "$_lt_caught_CXX_error"; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then @@ -7217,7 +7217,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support @@ -7301,7 +7301,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. @@ -7312,7 +7312,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' diff --git a/src/twister/taler-twister-service.c b/src/twister/taler-twister-service.c index d12bc67..071241d 100644 --- a/src/twister/taler-twister-service.c +++ b/src/twister/taler-twister-service.c @@ -40,12 +40,13 @@ #include <microhttpd.h> #include <taler/taler_util.h> - -/** - * We allow X runs of the progress callback before - * declaring the upload callback dead. +/** + * Keep logic of Marcello's fix for #5337? Unclear how it works, and + * may be superceeded by subsequent revisions, but kept for now to + * easily identify what might fix the issue (until CG can actually + * reproduce it nicely). */ -#define DOWNLOAD_PAUSED_TIMES_MAX 10 +#define MARCELLO_FIX 1 /** * Log curl error. @@ -76,6 +77,11 @@ enum RequestState REQUEST_STATE_UPLOAD_STARTED, /** + * We're done with the upload from MHD. + */ + REQUEST_STATE_UPLOAD_DONE, + + /** * We've finished uploading data via CURL and can now download. */ REQUEST_STATE_DOWNLOAD_STARTED, @@ -122,6 +128,21 @@ struct HttpRequest { /** + * Kept in DLL. + */ + struct HttpRequest *prev; + + /** + * Kept in DLL. + */ + struct HttpRequest *next; + + /** + * MHD request that triggered us. + */ + struct MHD_Connection *con; + + /** * Client socket read task */ struct GNUNET_SCHEDULER_Task *rtask; @@ -153,7 +174,7 @@ struct HttpRequest char *url; /** - * JSON we use to parse payloads (in both directions). + * JSON we use to parse payloads (in both directions). */ json_t *json; @@ -198,15 +219,22 @@ struct HttpRequest enum RequestState state; /** - * Indicates that the download callback is sleeping. + * Did we suspend MHD processing? */ - int download_paused; + int suspended; /** + * Did we pause CURL processing? + */ + int curl_paused; + +#if MARCELLO_FIX + /** * Indicates that the Web server returned a "Connection: close" * header line. */ int connection_closed; +#endif }; @@ -216,7 +244,17 @@ struct HttpRequest /** * The cURL download task (curl multi API). */ -static struct GNUNET_SCHEDULER_Task * curl_download_task; +static struct GNUNET_SCHEDULER_Task *curl_download_task; + +/** + * DLL of active HTTP requests. + */ +static struct HttpRequest *hr_head; + +/** + * DLL of active HTTP requests. + */ +static struct HttpRequest *hr_tail; /** * The cURL multi handle @@ -395,17 +433,17 @@ curl_check_hdr (void *buffer, *tok = '\0'; if (NULL != (tok = strchr (hdr_val, '\t'))) *tok = '\0'; - - if (0 == strcasecmp (hdr_type, - MHD_HTTP_HEADER_CONNECTION) - && (0 == strcasecmp (hdr_val, - "close"))) +#if MARCELLO_FIX + if ( (0 == strcasecmp (hdr_type, + MHD_HTTP_HEADER_CONNECTION) && + (0 == strcasecmp (hdr_val, + "close")) ) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server wants to close the TCP connection\n"); hr->connection_closed = GNUNET_YES; } - +#endif if (0 != strlen (hdr_val)) /* Rely in MHD to set those */ { @@ -463,6 +501,9 @@ create_mhd_response_from_hr (struct HttpRequest *hr) hr->io_len, JSON_DECODE_ANY, &error); + GNUNET_assert (GNUNET_YES == hr->suspended); + MHD_resume_connection (hr->con); + hr->suspended = GNUNET_NO; return GNUNET_OK; } @@ -489,11 +530,23 @@ curl_download_cb (void *ptr, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Curl download proceeding\n"); - if (REQUEST_STATE_DOWNLOAD_STARTED != hr->state) + if ( (REQUEST_STATE_UPLOAD_STARTED == hr->state) || + (REQUEST_STATE_UPLOAD_DONE == hr->state) ) + { + /* we're still not done with the upload, do not yet + start the download, the IO buffer is still full + with upload data. */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Pausing CURL download, waiting for UPLOAD to finish\n"); + hr->curl_paused = GNUNET_YES; + return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */ + } + + if (REQUEST_STATE_DOWNLOAD_STARTED != hr->state) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download callback goes to sleep\n"); - hr->download_paused = GNUNET_YES; + hr->curl_paused = GNUNET_YES; return CURL_WRITEFUNC_PAUSE; } @@ -509,7 +562,6 @@ curl_download_cb (void *ptr, GNUNET_MAX (total + hr->io_len, hr->io_size * 2 + 1024)); } - GNUNET_memcpy (&hr->io_buf[hr->io_len], ptr, total); @@ -541,18 +593,33 @@ curl_upload_cb (void *buf, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Upload cb is working...\n"); - if (REQUEST_STATE_UPLOAD_STARTED != hr->state) + if ( (0 == hr->io_len) && + (REQUEST_STATE_UPLOAD_DONE != hr->state) ) { - GNUNET_break (0); - return CURL_READFUNC_ABORT; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Pausing CURL UPLOAD, need more data\n"); + return CURL_READFUNC_PAUSE; } - if (0 == hr->io_len) + if ( (0 == hr->io_len) && + (REQUEST_STATE_UPLOAD_DONE == hr->state) ) { hr->state = REQUEST_STATE_DOWNLOAD_STARTED; + if (GNUNET_YES == hr->curl_paused) + { + hr->curl_paused = GNUNET_NO; + curl_easy_pause (hr->curl, + CURLPAUSE_CONT); + } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Completed CURL UPLOAD\n"); return 0; /* upload finished, can now download */ } + if ( (REQUEST_STATE_UPLOAD_STARTED != hr->state) && + (REQUEST_STATE_UPLOAD_DONE != hr->state) ) + { + GNUNET_break (0); + return CURL_READFUNC_ABORT; + } to_copy = GNUNET_MIN (hr->io_len, len); GNUNET_memcpy (buf, @@ -697,7 +764,7 @@ curl_task_download (void *cls) CURLINFO_PRIVATE, (char **) &hr )); - if (NULL == hr) + if (NULL == hr) { GNUNET_break (0); continue; @@ -719,6 +786,12 @@ curl_task_download (void *cls) GNUNET_assert (GNUNET_OK == create_mhd_response_from_hr (hr)); hr->state = REQUEST_STATE_DOWNLOAD_DONE; + if (GNUNET_YES == hr->suspended) + { + MHD_resume_connection (hr->con); + hr->suspended = GNUNET_NO; + } + run_mhd_now (); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -727,13 +800,18 @@ curl_task_download (void *cls) /* FIXME: indicate error somehow? * close MHD connection badly as well? */ hr->state = REQUEST_STATE_DOWNLOAD_DONE; + if (GNUNET_YES == hr->suspended) + { + MHD_resume_connection (hr->con); + hr->suspended = GNUNET_NO; + } + run_mhd_now (); break; } if (NULL == hr->response) hr->response = curl_failure_response; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Curl request for `%s' finished," - " response generated\n", + "Curl request for `%s' finished, response generated\n", hr->url); run_mhd_now (); break; @@ -765,6 +843,7 @@ curl_task_download (void *cls) curl_download_prepare (); } + static int curl_progress_cb (void *clientp, double dltotal, @@ -776,21 +855,22 @@ curl_progress_cb (void *clientp, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Progress callback..\n"); - - if ((GNUNET_YES == hr->download_paused) - && (GNUNET_YES == hr->connection_closed)) +#if MARCELLO_FIX + if ( (GNUNET_YES == hr->curl_paused) && + (GNUNET_YES == hr->connection_closed) ) { hr->state = REQUEST_STATE_DOWNLOAD_STARTED; - hr->download_paused = GNUNET_NO; + hr->curl_paused = GNUNET_NO; hr->connection_closed = GNUNET_NO; curl_easy_pause (hr->curl, CURLPAUSE_CONT); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unpausing the download callback\n"); } - +#endif return CURLE_OK; } + /* *************** MHD response generation ******************* */ @@ -1173,8 +1253,8 @@ delete_object (struct MHD_Connection *con, * value to the number of bytes NOT processed; * @param con_cls pointer to location where we store the * 'struct Request' - * @return MHD_YES if the connection was handled successfully, - * MHD_NO if the socket must be closed due to a serious + * @return #MHD_YES if the connection was handled successfully, + * #MHD_NO if the socket must be closed due to a serious * error while handling the request */ static int @@ -1238,11 +1318,24 @@ create_response (void *cls, hr->io_len += *upload_data_size; *upload_data_size = 0; + if (GNUNET_YES == hr->curl_paused) + { + hr->curl_paused = GNUNET_NO; + curl_easy_pause (hr->curl, + CURLPAUSE_CONT); + } return MHD_YES; } - /* Upload (*from the client*) finished, - * generate curl request to the proxied service. */ + /* Upload (*from the client*) finished */ + if (REQUEST_STATE_UPLOAD_STARTED == hr->state) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished processing UPLOAD\n"); + hr->state = REQUEST_STATE_UPLOAD_DONE; + } + + /* generate curl request to the proxied service. */ if (NULL == hr->curl) { /* Malform request body. Note, this flag will be @@ -1273,7 +1366,7 @@ create_response (void *cls, json_dumpb (hr->json, hr->io_buf, /* Existing io_len is enough to accomodate this encoding. */ - hr->io_len, + hr->io_len, JSON_COMPACT); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1298,7 +1391,7 @@ create_response (void *cls, json_dumpb (hr->json, hr->io_buf, /* Existing io_len is enough to accomodate this encoding. */ - hr->io_len, + hr->io_len, JSON_COMPACT); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1549,7 +1642,11 @@ create_response (void *cls, } if (REQUEST_STATE_DOWNLOAD_DONE != hr->state) + { + MHD_suspend_connection (con); + hr->suspended = GNUNET_YES; return MHD_YES; /* wait for curl */ + } if (0 != hack_response_code) { @@ -1570,7 +1667,8 @@ create_response (void *cls, { TALER_LOG_DEBUG ("Will delete path: %s\n", delete_path); - delete_object (con, hr); + delete_object (con, + hr); } if ('\0' != modify_path_dl[0]) @@ -1583,7 +1681,6 @@ create_response (void *cls, modify_path_dl); } - if (NULL != hr->json) { TALER_LOG_DEBUG ("Parsing final JSON.\n"); @@ -1623,6 +1720,7 @@ create_response (void *cls, header->type, header->value)); } + run_mhd_now (); return MHD_queue_response (con, hr->response_code, hr->response); @@ -1700,6 +1798,9 @@ mhd_completed_cb (void *cls, GNUNET_free (hr->url); GNUNET_free_non_null (hr->io_buf); + GNUNET_CONTAINER_DLL_remove (hr_head, + hr_tail, + hr); GNUNET_free (hr); *con_cls = NULL; } @@ -1739,7 +1840,11 @@ mhd_log_callback (void *cls, } hr = GNUNET_new (struct HttpRequest); + hr->con = connection; hr->url = GNUNET_strdup (url); + GNUNET_CONTAINER_DLL_insert (hr_head, + hr_tail, + hr); return hr; } @@ -1886,6 +1991,17 @@ do_shutdown (void *cls) (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n"); + /* MHD requires resuming before destroying the daemons */ + for (struct HttpRequest *hr = hr_head; + NULL != hr; + hr = hr->next) + { + if (hr->suspended) + { + hr->suspended = GNUNET_NO; + MHD_resume_connection (hr->con); + } + } kill_httpd (); if (NULL != curl_multi) { @@ -2046,6 +2162,7 @@ send_acknowledgement (struct GNUNET_SERVICE_Client *c) GNUNET_SERVICE_client_continue (c); } + /** * Control handler for malforming responses. * @@ -2063,6 +2180,7 @@ handle_malform (void *cls, send_acknowledgement (c); } + /** * Control handler for malforming requests. * @@ -2080,6 +2198,7 @@ handle_malform_upload (void *cls, send_acknowledgement (c); } + /** * Control handler for deleting JSON response objects * @@ -2094,7 +2213,6 @@ handle_modify_path_dl (void *cls, strcpy (modify_path_dl, src->path); strcpy (modify_value, src->value); - send_acknowledgement (c); } @@ -2114,10 +2232,10 @@ handle_modify_path_ul (void *cls, strcpy (modify_path_ul, src->path); strcpy (modify_value, src->value); - send_acknowledgement (c); } + /** * Control handler for flipping JSON strings into response objects * @@ -2151,6 +2269,7 @@ handle_flip_path_ul (void *cls, send_acknowledgement (c); } + /** * Control handler for deleting JSON fields from response objects * @@ -2167,6 +2286,7 @@ handle_delete_path (void *cls, send_acknowledgement (c); } + /** * Control handler for changing the response code * |