libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 14a46d9c0958f7e3ac481af5175d6c53dd614ee7
parent 2f282f18d14f7d8709aabb0ba55b5414f3c45336
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Mon, 10 Jan 2022 22:47:46 +0300

test_quiesce: added more checking and error reporting

Diffstat:
Msrc/testcurl/Makefile.am | 2+-
Asrc/testcurl/mhd_has_param.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/testcurl/test_quiesce.c | 576++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
3 files changed, 403 insertions(+), 228 deletions(-)

diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am @@ -186,7 +186,7 @@ test_get_SOURCES = \ test_get.c test_quiesce_SOURCES = \ - test_quiesce.c + test_quiesce.c mhd_has_param.h mhd_has_in_name.h test_quiesce_CFLAGS = \ $(PTHREAD_CFLAGS) $(AM_CFLAGS) test_quiesce_LDADD = \ diff --git a/src/testcurl/mhd_has_param.h b/src/testcurl/mhd_has_param.h @@ -0,0 +1,53 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2016-2022 Karlson2k (Evgeny Grin) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file testcurl/mhd_has_param.h + * @brief Static functions and macros helpers for testsuite. + * @author Karlson2k (Evgeny Grin) + */ + +#include <string.h> + + +/** + * Check whether one of strings in array is equal to @a param. + * String @a argv[0] is ignored. + * @param argc number of strings in @a argv, as passed to main function + * @param argv array of strings, as passed to main function + * @param param parameter to look for. + * @return zero if @a argv is NULL, @a param is NULL or empty string, + * @a argc is less then 2 or @a param is not found in @a argv, + * non-zero if one of strings in @a argv is equal to @a param. + */ +static int +has_param (int argc, char *const argv[], const char *param) +{ + int i; + if (! argv || ! param || ! param[0]) + return 0; + + for (i = 1; i < argc; i++) + { + if (argv[i] && (strcmp (argv[i], param) == 0) ) + return ! 0; + } + + return 0; +} diff --git a/src/testcurl/test_quiesce.c b/src/testcurl/test_quiesce.c @@ -1,7 +1,7 @@ /* This file is part of libmicrohttpd Copyright (C) 2013, 2015 Christian Grothoff - Copyright (C) 2014-2021 Evgeny Grin (Karlson2k) + Copyright (C) 2014-2022 Evgeny Grin (Karlson2k) libmicrohttpd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -35,6 +35,8 @@ #include <sys/types.h> #include <pthread.h> #include "mhd_sockets.h" /* only macros used */ +#include "mhd_has_in_name.h" +#include "mhd_has_param.h" #ifndef WINDOWS @@ -50,6 +52,120 @@ #endif +#if defined(HAVE___FUNC__) +#define externalErrorExit(ignore) \ + _externalErrorExit_func(NULL, __func__, __LINE__) +#define externalErrorExitDesc(errDesc) \ + _externalErrorExit_func(errDesc, __func__, __LINE__) +#define libcurlErrorExit(ignore) \ + _libcurlErrorExit_func(NULL, __func__, __LINE__) +#define libcurlErrorExitDesc(errDesc) \ + _libcurlErrorExit_func(errDesc, __func__, __LINE__) +#define mhdErrorExit(ignore) \ + _mhdErrorExit_func(NULL, __func__, __LINE__) +#define mhdErrorExitDesc(errDesc) \ + _mhdErrorExit_func(errDesc, __func__, __LINE__) +#elif defined(HAVE___FUNCTION__) +#define externalErrorExit(ignore) \ + _externalErrorExit_func(NULL, __FUNCTION__, __LINE__) +#define externalErrorExitDesc(errDesc) \ + _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__) +#define libcurlErrorExit(ignore) \ + _libcurlErrorExit_func(NULL, __FUNCTION__, __LINE__) +#define libcurlErrorExitDesc(errDesc) \ + _libcurlErrorExit_func(errDesc, __FUNCTION__, __LINE__) +#define mhdErrorExit(ignore) \ + _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__) +#define mhdErrorExitDesc(errDesc) \ + _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__) +#else +#define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) +#define externalErrorExitDesc(errDesc) \ + _externalErrorExit_func(errDesc, NULL, __LINE__) +#define libcurlErrorExit(ignore) _libcurlErrorExit_func(NULL, NULL, __LINE__) +#define libcurlErrorExitDesc(errDesc) \ + _libcurlErrorExit_func(errDesc, NULL, __LINE__) +#define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__) +#define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__) +#endif + + +_MHD_NORETURN static void +_externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) +{ + if ((NULL != errDesc) && (0 != errDesc[0])) + fprintf (stderr, "%s", errDesc); + else + fprintf (stderr, "System or external library call failed"); + if ((NULL != funcName) && (0 != funcName[0])) + fprintf (stderr, " in %s", funcName); + if (0 < lineNum) + fprintf (stderr, " at line %d", lineNum); + + fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, + strerror (errno)); +#ifdef MHD_WINSOCK_SOCKETS + fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); +#endif /* MHD_WINSOCK_SOCKETS */ + fflush (stderr); + exit (99); +} + + +static char libcurl_errbuf[CURL_ERROR_SIZE] = ""; + +_MHD_NORETURN static void +_libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum) +{ + if ((NULL != errDesc) && (0 != errDesc[0])) + fprintf (stderr, "%s", errDesc); + else + fprintf (stderr, "CURL library call failed"); + if ((NULL != funcName) && (0 != funcName[0])) + fprintf (stderr, " in %s", funcName); + if (0 < lineNum) + fprintf (stderr, " at line %d", lineNum); + + fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, + strerror (errno)); + if (0 != libcurl_errbuf[0]) + fprintf (stderr, "Last libcurl error details: %s\n", libcurl_errbuf); + + fflush (stderr); + exit (99); +} + + +_MHD_NORETURN static void +_mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) +{ + if ((NULL != errDesc) && (0 != errDesc[0])) + fprintf (stderr, "%s", errDesc); + else + fprintf (stderr, "MHD unexpected error"); + if ((NULL != funcName) && (0 != funcName[0])) + fprintf (stderr, " in %s", funcName); + if (0 < lineNum) + fprintf (stderr, " at line %d", lineNum); + + fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, + strerror (errno)); + + fflush (stderr); + exit (8); +} + + +/* Could be increased to facilitate debugging */ +#define TIMEOUTS_VAL 4 + +#define MHD_URI_BASE_PATH "/hello_world" + +/* Global parameters */ +static int verbose; /**< Be verbose */ +static int oneone; /**< If false use HTTP/1.0 for requests*/ +static int global_port; /**< MHD daemons listen port number */ + struct CBC { char *buf; @@ -57,8 +173,6 @@ struct CBC size_t size; }; -static int port; - static size_t copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) { @@ -84,11 +198,13 @@ ahc_echo (void *cls, static int ptr; const char *me = cls; struct MHD_Response *response; - enum MHD_Result ret; (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ if (0 != strcmp (me, method)) - return MHD_NO; /* unexpected method */ + { + fprintf (stderr, "Unexpected HTTP method '%s'. ", method); + externalErrorExit (); + } if (&ptr != *unused) { *unused = &ptr; @@ -98,11 +214,16 @@ ahc_echo (void *cls, response = MHD_create_response_from_buffer (strlen (url), (void *) url, MHD_RESPMEM_MUST_COPY); - ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + if (NULL == response) + mhdErrorExitDesc ("MHD_create_response failed"); + /* Make sure that connection will not be reused */ + if (MHD_NO == MHD_add_response_header (response, MHD_HTTP_HEADER_CONNECTION, + "close")) + mhdErrorExitDesc ("MHD_add_response_header() failed"); + if (MHD_NO == MHD_queue_response (connection, MHD_HTTP_OK, response)) + mhdErrorExitDesc ("MHD_queue_response() failed"); MHD_destroy_response (response); - if (ret == MHD_NO) - abort (); - return ret; + return MHD_YES; } @@ -112,7 +233,14 @@ request_completed (void *cls, struct MHD_Connection *connection, { int *done = (int *) cls; (void) connection; (void) con_cls; (void) code; /* Unused. Silent compiler warning. */ + if (MHD_REQUEST_TERMINATED_COMPLETED_OK != code) + { + fprintf (stderr, "Unexpected termination code: %d. ", (int) code); + mhdErrorExit (); + } *done = 1; + if (verbose) + printf ("Notify callback has been called with OK code.\n"); } @@ -126,9 +254,12 @@ ServeOneRequest (void *param) MHD_socket fd, max; time_t start; struct timeval tv; - int done = 0; + volatile int done = 0; + + if (NULL == param) + externalErrorExit (); - fd = (MHD_socket) (intptr_t) param; + fd = *((MHD_socket *) param); d = MHD_start_daemon (MHD_USE_ERROR_LOG, 0, NULL, NULL, &ahc_echo, "GET", @@ -136,47 +267,44 @@ ServeOneRequest (void *param) MHD_OPTION_NOTIFY_COMPLETED, &request_completed, &done, MHD_OPTION_END); if (d == NULL) - return "MHD_start_daemon() failed"; + mhdErrorExit (); + + if (verbose) + printf ("Started MHD daemon in ServeOneRequest().\n"); start = time (NULL); - while ((time (NULL) - start < 5) && done == 0) + while ((time (NULL) - start < TIMEOUTS_VAL * 2) && done == 0) { max = 0; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) - { - MHD_stop_daemon (d); - MHD_socket_close_chk_ (fd); - return "MHD_get_fdset() failed"; - } + mhdErrorExit ("MHD_get_fdset() failed"); tv.tv_sec = 0; - tv.tv_usec = 1000; + tv.tv_usec = 100000; if (-1 == MHD_SYS_select_ (max + 1, &rs, &ws, &es, &tv)) { #ifdef MHD_POSIX_SOCKETS if (EINTR != errno) - abort (); + externalErrorExitDesc ("Unexpected select() error"); #else - if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 != - ws. - fd_count) - || (0 != es.fd_count) ) - abort (); - Sleep (1000); + if ((WSAEINVAL != WSAGetLastError ()) || + (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) + externalErrorExitDesc ("Unexpected select() error"); + Sleep (tv.tv_sec * 1000 + tv.tv_usec / 1000); #endif } MHD_run (d); } + if (! done) + mhdErrorExit ("ServeOneRequest() failed and finished by timeout"); fd = MHD_quiesce_daemon (d); if (MHD_INVALID_SOCKET == fd) - { - MHD_stop_daemon (d); - return "MHD_quiesce_daemon() failed in ServeOneRequest()"; - } + mhdErrorExit ("MHD_quiesce_daemon() failed in ServeOneRequest()"); + MHD_stop_daemon (d); - return done ? NULL : "Requests was not served by ServeOneRequest()"; + return NULL; } @@ -186,19 +314,29 @@ setupCURL (void *cbc) CURL *c; c = curl_easy_init (); - curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world"); - curl_easy_setopt (c, CURLOPT_PORT, (long) port); - curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); - curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc); - curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); - curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, 150L); - curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, 150L); - curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - /* NOTE: use of CONNECTTIMEOUT without also - setting NOSIGNAL results in really weird - crashes on my system!*/ - curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); - + if (NULL == c) + libcurlErrorExitDesc ("curl_easy_init() failed"); + + if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_URL, + "http://127.0.0.1" MHD_URI_BASE_PATH)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, (long) global_port)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, + &copyBuffer)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, + (long) (TIMEOUTS_VAL / 2))) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT, + (long) TIMEOUTS_VAL)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER, + libcurl_errbuf)) || + (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L)) || + ((oneone) ? + (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_1)) : + (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_0)))) + libcurlErrorExitDesc ("curl_easy_setopt() failed"); return c; } @@ -215,38 +353,37 @@ testGet (int type, int pool_count, int poll_flag) pthread_t thrd; const char *thrdRet; - if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) - port = 0; - else - port = 1480; + if (verbose) + printf ("testGet(%d, %d, %d) test started.\n", + type, pool_count, poll_flag); cbc.buf = buf; - cbc.size = 2048; + cbc.size = sizeof(buf); cbc.pos = 0; if (pool_count > 0) { d = MHD_start_daemon (type | MHD_USE_ERROR_LOG | MHD_USE_ITC | poll_flag, - port, NULL, NULL, &ahc_echo, "GET", - MHD_OPTION_THREAD_POOL_SIZE, pool_count, + global_port, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_THREAD_POOL_SIZE, + (unsigned int) pool_count, MHD_OPTION_END); } else { d = MHD_start_daemon (type | MHD_USE_ERROR_LOG | MHD_USE_ITC | poll_flag, - port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + global_port, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_END); } if (d == NULL) - return 1; - if (0 == port) + mhdErrorExitDesc ("MHD_start_daemon() failed"); + if (0 == global_port) { const union MHD_DaemonInfo *dinfo; dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); if ((NULL == dinfo) || (0 == dinfo->port) ) - { - MHD_stop_daemon (d); return 32; - } - port = (int) dinfo->port; + mhdErrorExit (); + global_port = (int) dinfo->port; } c = setupCURL (&cbc); @@ -254,108 +391,101 @@ testGet (int type, int pool_count, int poll_flag) if (CURLE_OK != (errornum = curl_easy_perform (c))) { fprintf (stderr, - "curl_easy_perform failed: `%s'\n", + "curl_easy_perform() failed: '%s'. ", curl_easy_strerror (errornum)); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2; + libcurlErrorExit (); } - if (cbc.pos != strlen ("/hello_world")) + if (cbc.pos != strlen (MHD_URI_BASE_PATH)) { - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 4; + fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", + (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, + (unsigned) strlen (MHD_URI_BASE_PATH)); + mhdErrorExitDesc ("Wrong returned data length"); } - if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + if (0 != strncmp (MHD_URI_BASE_PATH, cbc.buf, strlen (MHD_URI_BASE_PATH))) { - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 8; + fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, cbc.buf); + mhdErrorExitDesc ("Wrong returned data"); } + if (verbose) + printf ("Received valid response data.\n"); fd = MHD_quiesce_daemon (d); if (MHD_INVALID_SOCKET == fd) - { - fprintf (stderr, - "MHD_quiesce_daemon failed.\n"); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2; - } + mhdErrorExitDesc ("MHD_quiesce_daemon failed"); + if (0 != pthread_create (&thrd, NULL, &ServeOneRequest, - (void *) (intptr_t) fd)) - { - fprintf (stderr, "pthread_create failed\n"); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 16; - } + (void *) &fd)) + externalErrorExitDesc ("pthread_create() failed"); + /* No need for the thread sync as socket is already listening, + * so libcurl may start connecting before MHD is started in another thread */ cbc.pos = 0; if (CURLE_OK != (errornum = curl_easy_perform (c))) { fprintf (stderr, - "curl_easy_perform failed: `%s'\n", + "curl_easy_perform() failed: `%s'\n", curl_easy_strerror (errornum)); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2; + mhdErrorExit (); } - if (0 != pthread_join (thrd, (void **) &thrdRet)) + if (cbc.pos != strlen (MHD_URI_BASE_PATH)) { - fprintf (stderr, "pthread_join failed\n"); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 16; + fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", + (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, + (unsigned) strlen (MHD_URI_BASE_PATH)); + mhdErrorExitDesc ("Wrong returned data length"); } - if (NULL != thrdRet) + if (0 != strncmp (MHD_URI_BASE_PATH, cbc.buf, strlen (MHD_URI_BASE_PATH))) { - fprintf (stderr, "ServeOneRequest() error: %s\n", thrdRet); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 16; + fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, cbc.buf); + mhdErrorExitDesc ("Wrong returned data"); } - if (cbc.pos != strlen ("/hello_world")) - { - fprintf (stderr, "%s\n", cbc.buf); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - MHD_socket_close_chk_ (fd); - return 4; - } - if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + if (0 != pthread_join (thrd, (void **) &thrdRet)) + externalErrorExitDesc ("pthread_join() failed"); + if (NULL != thrdRet) + externalErrorExitDesc ("ServeOneRequest() returned non-NULL result"); + + if (verbose) { - fprintf (stderr, "%s\n", cbc.buf); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - MHD_socket_close_chk_ (fd); - return 8; + printf ("ServeOneRequest() thread was joined.\n"); + fflush (stdout); } - /* at this point, the forked server quit, and the new - * server has quiesced, so new requests should fail + /* at this point, the forked server quiesced and quit, + * so new requests should fail */ + cbc.pos = 0; if (CURLE_OK == curl_easy_perform (c)) { - fprintf (stderr, "curl_easy_perform should fail\n"); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - MHD_socket_close_chk_ (fd); - return 2; + fprintf (stderr, "curl_easy_perform() succeed while it should fail. "); + fprintf (stderr, "Got %u bytes ('%.*s'), " + "valid data would be %u bytes (%s). ", + (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, + (unsigned) strlen (MHD_URI_BASE_PATH), MHD_URI_BASE_PATH); + mhdErrorExitDesc ("Unexpected succeed request"); } + if (verbose) + printf ("curl_easy_perform() failed as expected.\n"); curl_easy_cleanup (c); MHD_stop_daemon (d); MHD_socket_close_chk_ (fd); + if (verbose) + { + printf ("testGet(%d, %d, %d) test succeed.\n", + type, pool_count, poll_flag); + fflush (stdout); + } + return 0; } static int -testExternalGet () +testExternalGet (void) { struct MHD_Daemon *d; CURL *c; @@ -366,12 +496,6 @@ testExternalGet () fd_set rs; fd_set ws; fd_set es; - MHD_socket maxsock; -#ifdef MHD_WINSOCK_SOCKETS - int maxposixs; /* Max socket number unused on W32 */ -#else /* MHD_POSIX_SOCKETS */ -#define maxposixs maxsock -#endif /* MHD_POSIX_SOCKETS */ int running; struct CURLMsg *msg; time_t start; @@ -379,56 +503,48 @@ testExternalGet () int i; MHD_socket fd; - if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) - port = 0; - else - port = 1481; + if (verbose) + printf ("testExternalGet test started.\n"); + fd = MHD_INVALID_SOCKET; multi = NULL; cbc.buf = buf; - cbc.size = 2048; + cbc.size = sizeof(buf); cbc.pos = 0; d = MHD_start_daemon (MHD_USE_ERROR_LOG, - port, + global_port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); if (d == NULL) - return 256; - if (0 == port) + mhdErrorExitDesc ("Failed to start MHD daemon"); + if (0 == global_port) { const union MHD_DaemonInfo *dinfo; dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); if ((NULL == dinfo) || (0 == dinfo->port) ) - { - MHD_stop_daemon (d); return 32; - } - port = (int) dinfo->port; - } - c = setupCURL (&cbc); - - multi = curl_multi_init (); - if (multi == NULL) - { - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 512; - } - mret = curl_multi_add_handle (multi, c); - if (mret != CURLM_OK) - { - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 1024; + mhdErrorExit (); + global_port = (int) dinfo->port; } for (i = 0; i < 2; i++) { + c = setupCURL (&cbc); + + multi = curl_multi_init (); + if (multi == NULL) + libcurlErrorExit (); + + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + libcurlErrorExit (); + start = time (NULL); - while ( (time (NULL) - start < 5) && + while ( (time (NULL) - start < TIMEOUTS_VAL * 2) && (NULL != multi) ) { + MHD_socket maxsock; + int maxposixs; maxsock = MHD_INVALID_SOCKET; maxposixs = -1; FD_ZERO (&rs); @@ -437,44 +553,26 @@ testExternalGet () curl_multi_perform (multi, &running); mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); if (mret != CURLM_OK) - { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2048; - } + libcurlErrorExit (); if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) - { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 4096; - } + mhdErrorExit (); +#ifndef MHD_WINSOCK_SOCKETS + if (maxsock > maxposixs) + maxposixs = maxsock; +#endif /* MHD_POSIX_SOCKETS */ tv.tv_sec = 0; - tv.tv_usec = 1000; + tv.tv_usec = 100000; if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) { - #ifdef MHD_POSIX_SOCKETS +#ifdef MHD_POSIX_SOCKETS if (EINTR != errno) - { - fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", - (int) errno, __LINE__); - fflush (stderr); - exit (99); - } - #else + externalErrorExitDesc ("Unexpected select() error"); +#else if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) - { - fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", - (int) WSAGetLastError (), __LINE__); - fflush (stderr); - exit (99); - } - Sleep (1); - #endif + externalErrorExitDesc ("Unexpected select() error"); + Sleep (tv.tv_sec * 1000 + tv.tv_usec / 1000); +#endif } curl_multi_perform (multi, &running); if (0 == running) @@ -486,26 +584,57 @@ testExternalGet () if (msg->msg == CURLMSG_DONE) { if (msg->data.result == CURLE_OK) + { curl_fine = 1; + if (verbose) + printf ("libcurl reported success.\n"); + } else if (i == 0) { fprintf (stderr, - "%s failed at %s:%d: `%s'\n", - "curl_multi_perform", - __FILE__, - __LINE__, curl_easy_strerror (msg->data.result)); + "curl_multi_perform() failed with '%s'. ", + curl_easy_strerror (msg->data.result)); + mhdErrorExit (); } } } - if ((i == 0) && (! curl_fine)) + if (i == 0) { - fprintf (stderr, "libcurl haven't returned OK code\n"); - abort (); + if (! curl_fine) + { + fprintf (stderr, "libcurl haven't returned OK code\n"); + mhdErrorExit (); + } + /* MHD is running, result should be correct */ + if (cbc.pos != strlen (MHD_URI_BASE_PATH)) + { + fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ", + (unsigned) cbc.pos, (int) cbc.pos, cbc.buf, + (unsigned) strlen (MHD_URI_BASE_PATH)); + mhdErrorExitDesc ("Wrong returned data length"); + } + if (0 != strncmp (MHD_URI_BASE_PATH, cbc.buf, + strlen (MHD_URI_BASE_PATH))) + { + fprintf (stderr, "Got invalid response '%.*s'. ", (int) cbc.pos, + cbc.buf); + mhdErrorExitDesc ("Wrong returned data"); + } + if (verbose) + { + printf ("First request was successful.\n"); + fflush (stdout); + } } - else if ((i == 1) && (curl_fine)) + else if (i == 1) { - fprintf (stderr, "libcurl returned OK code, while it shouldn't\n"); - abort (); + if (curl_fine) + { + fprintf (stderr, "libcurl returned OK code, while it shouldn't\n"); + mhdErrorExit (); + } + if (verbose) + printf ("Second request failed as expected.\n"); } curl_multi_remove_handle (multi, c); curl_multi_cleanup (multi); @@ -517,45 +646,31 @@ testExternalGet () MHD_run (d); } + if (NULL != multi) + mhdErrorExitDesc ("Test failed and finished by timeout"); + if (0 == i) { /* quiesce the daemon on the 1st iteration, so the 2nd should fail */ fd = MHD_quiesce_daemon (d); if (MHD_INVALID_SOCKET == fd) - { - fprintf (stderr, - "MHD_quiesce_daemon failed.\n"); - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 2; - } - c = setupCURL (&cbc); - multi = curl_multi_init (); - mret = curl_multi_add_handle (multi, c); - if (mret != CURLM_OK) - { - curl_multi_remove_handle (multi, c); - curl_multi_cleanup (multi); - curl_easy_cleanup (c); - MHD_stop_daemon (d); - return 32768; - } + mhdErrorExitDesc ("MHD_quiesce_daemon() failed"); } } - if (NULL != multi) + MHD_stop_daemon (d); + if (MHD_INVALID_SOCKET == fd) { - curl_multi_remove_handle (multi, c); - curl_easy_cleanup (c); - curl_multi_cleanup (multi); + fprintf (stderr, "Failed to MHD_quiesce_daemon() at some point. "); + externalErrorExit (); } - MHD_stop_daemon (d); MHD_socket_close_chk_ (fd); - if (cbc.pos != strlen ("/hello_world")) - return 8192; - if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) - return 16384; + + if (verbose) + { + printf ("testExternalGet succeed.\n"); + fflush (stdout); + } + return 0; } @@ -564,10 +679,17 @@ int main (int argc, char *const *argv) { unsigned int errorCount = 0; - (void) argc; (void) argv; /* Unused. Silent compiler warning. */ + oneone = ! has_in_name (argv[0], "10"); + verbose = ! has_param (argc, argv, "-q") || has_param (argc, argv, "--quiet"); if (0 != curl_global_init (CURL_GLOBAL_WIN32)) return 2; + + if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) + global_port = 0; + else + global_port = 1480 + (oneone ? 1 : 0); + errorCount += testExternalGet (); if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) {