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