test_get_iovec.c (21043B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007-2021 Christian Grothoff 4 Copyright (C) 2014-2022 Evgeny Grin 5 6 libmicrohttpd is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published 8 by the Free Software Foundation; either version 2, or (at your 9 option) any later version. 10 11 libmicrohttpd is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with libmicrohttpd; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 */ 21 22 /** 23 * @file test_get_iovec.c 24 * @brief Testcase for libmicrohttpd response from scatter/gather array 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 * @author Lawrence Sebald 28 */ 29 30 /* 31 * This test is largely derived from the test_get_sendfile.c file, with the 32 * daemon using MHD_create_response_from_iovec instead of working from an fd. 33 */ 34 35 #include "mhd_options.h" 36 #include "platform.h" 37 #include <curl/curl.h> 38 #include <microhttpd.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <time.h> 42 #include <sys/types.h> 43 #include <fcntl.h> 44 #ifdef HAVE_STDBOOL_H 45 #include <stdbool.h> 46 #endif 47 #include <errno.h> 48 #include "mhd_sockets.h" 49 #include "mhd_has_in_name.h" 50 51 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 52 test into a marked, classifiable test error (TESTING.md, P5). */ 53 #include "mhd_panic_tripwire.h" 54 55 #ifndef WINDOWS 56 #include <sys/socket.h> 57 #include <unistd.h> 58 #endif 59 60 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 61 #undef MHD_CPU_COUNT 62 #endif 63 #if ! defined(MHD_CPU_COUNT) 64 #define MHD_CPU_COUNT 2 65 #endif 66 67 #define TESTSTR_IOVLEN 20480 68 #define TESTSTR_IOVCNT 20 69 #define TESTSTR_SIZE (TESTSTR_IOVCNT * TESTSTR_IOVLEN) 70 71 static int oneone; 72 73 static int readbuf[TESTSTR_SIZE * 2 / sizeof(int)]; 74 75 struct CBC 76 { 77 char *buf; 78 size_t pos; 79 size_t size; 80 }; 81 82 83 static size_t 84 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 85 { 86 struct CBC *cbc = ctx; 87 88 if (cbc->pos + size * nmemb > cbc->size) 89 _exit (7); /* overflow */ 90 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 91 cbc->pos += size * nmemb; 92 return size * nmemb; 93 } 94 95 96 static void 97 iov_free_callback (void *cls) 98 { 99 free (cls); 100 } 101 102 103 struct iovncont_data 104 { 105 void *ptrs[TESTSTR_IOVCNT]; 106 }; 107 108 static void 109 iovncont_free_callback (void *cls) 110 { 111 struct iovncont_data *data = (struct iovncont_data *) cls; 112 unsigned int i; 113 114 for (i = 0; i < TESTSTR_IOVCNT; ++i) 115 free (data->ptrs[i]); 116 free (data); 117 } 118 119 120 static int 121 check_read_data (const void *ptr, size_t len) 122 { 123 const int *buf; 124 size_t i; 125 126 if (len % sizeof(int)) 127 return -1; 128 129 buf = (const int *) ptr; 130 131 for (i = 0; i < len / sizeof(int); ++i) 132 { 133 if (buf[i] != (int) i) 134 return -1; 135 } 136 137 return 0; 138 } 139 140 141 static enum MHD_Result 142 ahc_cont (void *cls, 143 struct MHD_Connection *connection, 144 const char *url, 145 const char *method, 146 const char *version, 147 const char *upload_data, size_t *upload_data_size, 148 void **req_cls) 149 { 150 static int ptr; 151 struct MHD_Response *response; 152 enum MHD_Result ret; 153 int *data; 154 struct MHD_IoVec iov[TESTSTR_IOVCNT]; 155 int i; 156 (void) cls; 157 (void) url; (void) version; /* Unused. Silent compiler warning. */ 158 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 159 160 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 161 return MHD_NO; /* unexpected method */ 162 if (&ptr != *req_cls) 163 { 164 *req_cls = &ptr; 165 return MHD_YES; 166 } 167 *req_cls = NULL; 168 169 /* Create some test data. */ 170 if (NULL == (data = malloc (TESTSTR_SIZE))) 171 return MHD_NO; 172 173 for (i = 0; i < (int) (TESTSTR_SIZE / sizeof(int)); ++i) 174 { 175 data[i] = i; 176 } 177 178 for (i = 0; i < TESTSTR_IOVCNT; ++i) 179 { 180 iov[i].iov_base = data + (((size_t) i) 181 * (TESTSTR_SIZE / TESTSTR_IOVCNT / sizeof(int))); 182 iov[i].iov_len = TESTSTR_SIZE / TESTSTR_IOVCNT; 183 } 184 185 response = MHD_create_response_from_iovec (iov, 186 TESTSTR_IOVCNT, 187 &iov_free_callback, 188 data); 189 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 190 MHD_destroy_response (response); 191 if (ret == MHD_NO) 192 abort (); 193 return ret; 194 } 195 196 197 static enum MHD_Result 198 ahc_ncont (void *cls, 199 struct MHD_Connection *connection, 200 const char *url, 201 const char *method, 202 const char *version, 203 const char *upload_data, size_t *upload_data_size, 204 void **req_cls) 205 { 206 static int ptr; 207 struct MHD_Response *response; 208 enum MHD_Result ret; 209 struct MHD_IoVec iov[TESTSTR_IOVCNT]; 210 struct iovncont_data *clear_cls; 211 int i, j; 212 (void) cls; 213 (void) url; (void) version; /* Unused. Silent compiler warning. */ 214 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 215 216 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 217 return MHD_NO; /* unexpected method */ 218 if (&ptr != *req_cls) 219 { 220 *req_cls = &ptr; 221 return MHD_YES; 222 } 223 *req_cls = NULL; 224 225 clear_cls = malloc (sizeof(struct iovncont_data)); 226 if (NULL == clear_cls) 227 abort (); 228 memset (iov, 0, sizeof(struct MHD_IoVec) * TESTSTR_IOVCNT); 229 230 /* Create some test data. */ 231 for (j = TESTSTR_IOVCNT - 1; j >= 0; --j) 232 { 233 int *data; 234 data = malloc (TESTSTR_IOVLEN); 235 if (NULL == data) 236 abort (); 237 clear_cls->ptrs[j] = (void *) data; 238 239 for (i = 0; i < (int) (TESTSTR_IOVLEN / sizeof(int)); ++i) 240 { 241 data[i] = i + (j * (int) (TESTSTR_IOVLEN / sizeof(int))); 242 } 243 iov[j].iov_base = (const void *) data; 244 iov[j].iov_len = TESTSTR_IOVLEN; 245 246 } 247 248 response = MHD_create_response_from_iovec (iov, 249 TESTSTR_IOVCNT, 250 &iovncont_free_callback, 251 clear_cls); 252 ret = MHD_queue_response (connection, 253 MHD_HTTP_OK, 254 response); 255 MHD_destroy_response (response); 256 if (ret == MHD_NO) 257 abort (); 258 return ret; 259 } 260 261 262 static unsigned int 263 testInternalGet (bool contiguous) 264 { 265 struct MHD_Daemon *d; 266 CURL *c; 267 struct CBC cbc; 268 CURLcode errornum; 269 uint16_t port; 270 271 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 272 port = 0; 273 else 274 { 275 port = 1200; 276 if (oneone) 277 port += 10; 278 } 279 280 cbc.buf = (char *) readbuf; 281 cbc.size = sizeof(readbuf); 282 cbc.pos = 0; 283 284 if (contiguous) 285 { 286 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 287 port, NULL, NULL, &ahc_cont, NULL, MHD_OPTION_END); 288 } 289 else 290 { 291 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 292 port, NULL, NULL, &ahc_ncont, NULL, MHD_OPTION_END); 293 } 294 295 if (d == NULL) 296 return 1; 297 if (0 == port) 298 { 299 const union MHD_DaemonInfo *dinfo; 300 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 301 if ((NULL == dinfo) || (0 == dinfo->port) ) 302 { 303 MHD_stop_daemon (d); return 32; 304 } 305 port = dinfo->port; 306 } 307 c = curl_easy_init (); 308 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 309 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 310 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 311 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 312 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 313 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 314 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 315 if (oneone) 316 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 317 else 318 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 319 /* NOTE: use of CONNECTTIMEOUT without also 320 setting NOSIGNAL results in really weird 321 crashes on my system!*/ 322 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 323 if (CURLE_OK != (errornum = curl_easy_perform (c))) 324 { 325 fprintf (stderr, 326 "curl_easy_perform failed: `%s'\n", 327 curl_easy_strerror (errornum)); 328 curl_easy_cleanup (c); 329 MHD_stop_daemon (d); 330 return 2; 331 } 332 curl_easy_cleanup (c); 333 MHD_stop_daemon (d); 334 if (cbc.pos != TESTSTR_SIZE) 335 return 4; 336 if (0 != check_read_data (cbc.buf, cbc.pos)) 337 return 8; 338 return 0; 339 } 340 341 342 static unsigned int 343 testMultithreadedGet (void) 344 { 345 struct MHD_Daemon *d; 346 CURL *c; 347 struct CBC cbc; 348 CURLcode errornum; 349 uint16_t port; 350 351 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 352 port = 0; 353 else 354 { 355 port = 1201; 356 if (oneone) 357 port += 10; 358 } 359 360 cbc.buf = (char *) readbuf; 361 cbc.size = sizeof(readbuf); 362 cbc.pos = 0; 363 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 364 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 365 | MHD_USE_AUTO, 366 port, NULL, NULL, &ahc_cont, NULL, MHD_OPTION_END); 367 if (d == NULL) 368 return 16; 369 if (0 == port) 370 { 371 const union MHD_DaemonInfo *dinfo; 372 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 373 if ((NULL == dinfo) || (0 == dinfo->port) ) 374 { 375 MHD_stop_daemon (d); return 32; 376 } 377 port = dinfo->port; 378 } 379 c = curl_easy_init (); 380 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 381 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 382 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 383 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 384 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 385 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 386 if (oneone) 387 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 388 else 389 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 390 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 391 /* NOTE: use of CONNECTTIMEOUT without also 392 setting NOSIGNAL results in really weird 393 crashes on my system! */ 394 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 395 if (CURLE_OK != (errornum = curl_easy_perform (c))) 396 { 397 fprintf (stderr, 398 "curl_easy_perform failed: `%s'\n", 399 curl_easy_strerror (errornum)); 400 curl_easy_cleanup (c); 401 MHD_stop_daemon (d); 402 return 32; 403 } 404 curl_easy_cleanup (c); 405 MHD_stop_daemon (d); 406 if (cbc.pos != TESTSTR_SIZE) 407 return 64; 408 if (0 != check_read_data (cbc.buf, cbc.pos)) 409 return 128; 410 return 0; 411 } 412 413 414 static unsigned int 415 testMultithreadedPoolGet (void) 416 { 417 struct MHD_Daemon *d; 418 CURL *c; 419 struct CBC cbc; 420 CURLcode errornum; 421 uint16_t port; 422 423 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 424 port = 0; 425 else 426 { 427 port = 1202; 428 if (oneone) 429 port += 10; 430 } 431 432 cbc.buf = (char *) readbuf; 433 cbc.size = sizeof(readbuf); 434 cbc.pos = 0; 435 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG 436 | MHD_USE_AUTO, 437 port, NULL, NULL, &ahc_cont, NULL, 438 MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT, 439 MHD_OPTION_END); 440 if (d == NULL) 441 return 16; 442 if (0 == port) 443 { 444 const union MHD_DaemonInfo *dinfo; 445 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 446 if ((NULL == dinfo) || (0 == dinfo->port) ) 447 { 448 MHD_stop_daemon (d); return 32; 449 } 450 port = dinfo->port; 451 } 452 c = curl_easy_init (); 453 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 454 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 455 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 456 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 457 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 458 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 459 if (oneone) 460 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 461 else 462 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 463 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 464 /* NOTE: use of CONNECTTIMEOUT without also 465 setting NOSIGNAL results in really weird 466 crashes on my system!*/ 467 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 468 if (CURLE_OK != (errornum = curl_easy_perform (c))) 469 { 470 fprintf (stderr, 471 "curl_easy_perform failed: `%s'\n", 472 curl_easy_strerror (errornum)); 473 curl_easy_cleanup (c); 474 MHD_stop_daemon (d); 475 return 32; 476 } 477 curl_easy_cleanup (c); 478 MHD_stop_daemon (d); 479 if (cbc.pos != TESTSTR_SIZE) 480 return 64; 481 if (0 != check_read_data (cbc.buf, cbc.pos)) 482 return 128; 483 return 0; 484 } 485 486 487 static unsigned int 488 testExternalGet (int thread_unsafe) 489 { 490 struct MHD_Daemon *d; 491 CURL *c; 492 struct CBC cbc; 493 CURLM *multi; 494 CURLMcode mret; 495 fd_set rs; 496 fd_set ws; 497 fd_set es; 498 MHD_socket maxsock; 499 #ifdef MHD_WINSOCK_SOCKETS 500 int maxposixs; /* Max socket number unused on W32 */ 501 #else /* MHD_POSIX_SOCKETS */ 502 #define maxposixs maxsock 503 #endif /* MHD_POSIX_SOCKETS */ 504 int running; 505 struct CURLMsg *msg; 506 time_t start; 507 struct timeval tv; 508 uint16_t port; 509 510 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 511 port = 0; 512 else 513 { 514 port = 1203; 515 if (oneone) 516 port += 10; 517 } 518 519 multi = NULL; 520 cbc.buf = (char *) readbuf; 521 cbc.size = sizeof(readbuf); 522 cbc.pos = 0; 523 d = MHD_start_daemon (MHD_USE_ERROR_LOG 524 | (thread_unsafe ? MHD_USE_NO_THREAD_SAFETY : 0), 525 port, NULL, NULL, &ahc_cont, NULL, 526 MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE, 527 MHD_OPTION_END); 528 if (d == NULL) 529 return 256; 530 if (0 == port) 531 { 532 const union MHD_DaemonInfo *dinfo; 533 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 534 if ((NULL == dinfo) || (0 == dinfo->port) ) 535 { 536 MHD_stop_daemon (d); return 32; 537 } 538 port = dinfo->port; 539 } 540 c = curl_easy_init (); 541 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/"); 542 curl_easy_setopt (c, CURLOPT_PORT, (long) port); 543 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 544 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 545 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 546 if (oneone) 547 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 548 else 549 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 550 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 551 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 552 /* NOTE: use of CONNECTTIMEOUT without also 553 setting NOSIGNAL results in really weird 554 crashes on my system! */ 555 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 556 557 558 multi = curl_multi_init (); 559 if (multi == NULL) 560 { 561 curl_easy_cleanup (c); 562 MHD_stop_daemon (d); 563 return 512; 564 } 565 mret = curl_multi_add_handle (multi, c); 566 if (mret != CURLM_OK) 567 { 568 curl_multi_cleanup (multi); 569 curl_easy_cleanup (c); 570 MHD_stop_daemon (d); 571 return 1024; 572 } 573 start = time (NULL); 574 while ((time (NULL) - start < 5) && (multi != NULL)) 575 { 576 maxsock = MHD_INVALID_SOCKET; 577 maxposixs = -1; 578 FD_ZERO (&rs); 579 FD_ZERO (&ws); 580 FD_ZERO (&es); 581 curl_multi_perform (multi, &running); 582 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); 583 if (mret != CURLM_OK) 584 { 585 curl_multi_remove_handle (multi, c); 586 curl_multi_cleanup (multi); 587 curl_easy_cleanup (c); 588 MHD_stop_daemon (d); 589 return 2048; 590 } 591 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 592 { 593 curl_multi_remove_handle (multi, c); 594 curl_multi_cleanup (multi); 595 curl_easy_cleanup (c); 596 MHD_stop_daemon (d); 597 return 4096; 598 } 599 tv.tv_sec = 0; 600 tv.tv_usec = 1000; 601 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 602 { 603 #ifdef MHD_POSIX_SOCKETS 604 if (EINTR != errno) 605 { 606 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 607 (int) errno, __LINE__); 608 fflush (stderr); 609 exit (99); 610 } 611 #else 612 if ((WSAEINVAL != WSAGetLastError ()) || 613 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 614 { 615 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 616 (int) WSAGetLastError (), __LINE__); 617 fflush (stderr); 618 exit (99); 619 } 620 Sleep (1); 621 #endif 622 } 623 curl_multi_perform (multi, &running); 624 if (0 == running) 625 { 626 int pending; 627 int curl_fine = 0; 628 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 629 { 630 if (msg->msg == CURLMSG_DONE) 631 { 632 if (msg->data.result == CURLE_OK) 633 curl_fine = 1; 634 else 635 { 636 fprintf (stderr, 637 "%s failed at %s:%d: `%s'\n", 638 "curl_multi_perform", 639 __FILE__, 640 __LINE__, curl_easy_strerror (msg->data.result)); 641 abort (); 642 } 643 } 644 } 645 if (! curl_fine) 646 { 647 fprintf (stderr, "libcurl haven't returned OK code\n"); 648 abort (); 649 } 650 curl_multi_remove_handle (multi, c); 651 curl_multi_cleanup (multi); 652 curl_easy_cleanup (c); 653 c = NULL; 654 multi = NULL; 655 } 656 MHD_run (d); 657 } 658 if (multi != NULL) 659 { 660 curl_multi_remove_handle (multi, c); 661 curl_easy_cleanup (c); 662 curl_multi_cleanup (multi); 663 } 664 MHD_stop_daemon (d); 665 if (cbc.pos != TESTSTR_SIZE) 666 return 8192; 667 if (0 != check_read_data (cbc.buf, cbc.pos)) 668 return 16384; 669 return 0; 670 } 671 672 673 static unsigned int 674 testUnknownPortGet (void) 675 { 676 struct MHD_Daemon *d; 677 const union MHD_DaemonInfo *di; 678 CURL *c; 679 struct CBC cbc; 680 CURLcode errornum; 681 uint16_t port; 682 char buf[2048]; 683 684 struct sockaddr_in addr; 685 socklen_t addr_len = sizeof(addr); 686 memset (&addr, 0, sizeof(addr)); 687 addr.sin_family = AF_INET; 688 addr.sin_port = 0; 689 addr.sin_addr.s_addr = INADDR_ANY; 690 691 cbc.buf = (char *) readbuf; 692 cbc.size = sizeof(readbuf); 693 cbc.pos = 0; 694 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, 695 0, NULL, NULL, &ahc_cont, NULL, 696 MHD_OPTION_SOCK_ADDR, &addr, 697 MHD_OPTION_END); 698 if (d == NULL) 699 return 32768; 700 701 if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 702 { 703 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); 704 if (di == NULL) 705 return 65536; 706 707 if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len)) 708 return 131072; 709 710 if (addr.sin_family != AF_INET) 711 return 26214; 712 port = ntohs (addr.sin_port); 713 } 714 else 715 { 716 const union MHD_DaemonInfo *dinfo; 717 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 718 if ((NULL == dinfo) || (0 == dinfo->port) ) 719 { 720 MHD_stop_daemon (d); return 32; 721 } 722 port = dinfo->port; 723 } 724 725 snprintf (buf, sizeof(buf), "http://127.0.0.1:%u/", 726 (unsigned int) port); 727 728 c = curl_easy_init (); 729 curl_easy_setopt (c, CURLOPT_URL, buf); 730 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 731 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 732 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 733 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 734 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 735 if (oneone) 736 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 737 else 738 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 739 /* NOTE: use of CONNECTTIMEOUT without also 740 setting NOSIGNAL results in really weird 741 crashes on my system! */ 742 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 743 if (CURLE_OK != (errornum = curl_easy_perform (c))) 744 { 745 fprintf (stderr, 746 "curl_easy_perform failed: `%s'\n", 747 curl_easy_strerror (errornum)); 748 curl_easy_cleanup (c); 749 MHD_stop_daemon (d); 750 return 524288; 751 } 752 curl_easy_cleanup (c); 753 MHD_stop_daemon (d); 754 if (cbc.pos != TESTSTR_SIZE) 755 return 1048576; 756 if (0 != check_read_data (cbc.buf, cbc.pos)) 757 return 2097152; 758 return 0; 759 } 760 761 762 int 763 main (int argc, char *const *argv) 764 { 765 unsigned int errorCount = 0; 766 (void) argc; /* Unused. Silent compiler warning. */ 767 768 if ((NULL == argv) || (0 == argv[0])) 769 return 99; 770 oneone = has_in_name (argv[0], "11"); 771 772 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 773 return 2; 774 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) 775 { 776 errorCount += testInternalGet (true); 777 errorCount += testInternalGet (false); 778 errorCount += testMultithreadedGet (); 779 errorCount += testMultithreadedPoolGet (); 780 errorCount += testUnknownPortGet (); 781 errorCount += testExternalGet (0); 782 } 783 errorCount += testExternalGet (! 0); 784 if (errorCount != 0) 785 fprintf (stderr, "Error (code: %u)\n", errorCount); 786 curl_global_cleanup (); 787 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 788 }