lib2405.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Dmitry Karpov <dkarpov1970@gmail.com>
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. /*
  25. * The purpose of this test is to test behavior of curl_multi_waitfds
  26. * function in different scenarios:
  27. * empty multi handle (expected zero descriptors),
  28. * HTTP1 amd HTTP2 (no multiplexing) two transfers (expected two descriptors),
  29. * HTTP2 with multiplexing (expected one descriptors)
  30. *
  31. * It is also expected that all transfers run by multi-handle should complete
  32. * successfully.
  33. */
  34. #include "test.h"
  35. #include "testutil.h"
  36. #include "warnless.h"
  37. #include "memdebug.h"
  38. /* ---------------------------------------------------------------- */
  39. #define test_check(expected_fds) \
  40. if(res != CURLE_OK) { \
  41. fprintf(stderr, "test failed with code: %d\n", res); \
  42. goto test_cleanup; \
  43. } \
  44. else if(fd_count != expected_fds) { \
  45. fprintf(stderr, "Max number of waitfds: %d not as expected: %d\n", \
  46. fd_count, expected_fds); \
  47. res = TEST_ERR_FAILURE; \
  48. goto test_cleanup; \
  49. }
  50. #define test_run_check(option, expected_fds) do { \
  51. res = test_run(URL, option, &fd_count); \
  52. test_check(expected_fds); \
  53. } while(0)
  54. /* ---------------------------------------------------------------- */
  55. enum {
  56. TEST_USE_HTTP1 = 0,
  57. TEST_USE_HTTP2,
  58. TEST_USE_HTTP2_MPLEX
  59. };
  60. static size_t emptyWriteFunc(void *ptr, size_t size, size_t nmemb,
  61. void *data) {
  62. (void)ptr; (void)data;
  63. return size * nmemb;
  64. }
  65. static CURLcode set_easy(char *URL, CURL *easy, long option)
  66. {
  67. CURLcode res = CURLE_OK;
  68. /* First set the URL that is about to receive our POST. */
  69. easy_setopt(easy, CURLOPT_URL, URL);
  70. /* get verbose debug output please */
  71. easy_setopt(easy, CURLOPT_VERBOSE, 1L);
  72. switch(option) {
  73. case TEST_USE_HTTP1:
  74. /* go http1 */
  75. easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  76. break;
  77. case TEST_USE_HTTP2:
  78. /* go http2 */
  79. easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  80. break;
  81. case TEST_USE_HTTP2_MPLEX:
  82. /* go http2 with multiplexing */
  83. easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  84. easy_setopt(easy, CURLOPT_PIPEWAIT, 1L);
  85. break;
  86. }
  87. /* no peer verify */
  88. easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L);
  89. easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, 0L);
  90. /* include headers */
  91. easy_setopt(easy, CURLOPT_HEADER, 1L);
  92. /* empty write function */
  93. easy_setopt(easy, CURLOPT_WRITEFUNCTION, emptyWriteFunc);
  94. test_cleanup:
  95. return res;
  96. }
  97. static CURLcode test_run(char *URL, long option, unsigned int *max_fd_count)
  98. {
  99. CURLMcode mc = CURLM_OK;
  100. CURLM *multi = NULL;
  101. CURLM *multi1 = NULL;
  102. CURL *easy1 = NULL;
  103. CURL *easy2 = NULL;
  104. unsigned int max_count = 0;
  105. int still_running; /* keep number of running handles */
  106. CURLMsg *msg; /* for picking up messages with the transfer status */
  107. int msgs_left; /* how many messages are left */
  108. CURLcode result;
  109. CURLcode res = CURLE_OK;
  110. struct curl_waitfd ufds[10];
  111. struct curl_waitfd ufds1[10];
  112. int numfds;
  113. easy_init(easy1);
  114. easy_init(easy2);
  115. if(set_easy(URL, easy1, option) != CURLE_OK)
  116. goto test_cleanup;
  117. if(set_easy(URL, easy2, option) != CURLE_OK)
  118. goto test_cleanup;
  119. multi_init(multi);
  120. multi_init(multi1);
  121. if(option == TEST_USE_HTTP2_MPLEX)
  122. multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
  123. multi_add_handle(multi, easy1);
  124. multi_add_handle(multi, easy2);
  125. while(!mc) {
  126. /* get the count of file descriptors from the transfers */
  127. unsigned int fd_count = 0;
  128. mc = curl_multi_perform(multi, &still_running);
  129. if(!still_running || mc != CURLM_OK)
  130. break;
  131. mc = curl_multi_waitfds(multi, ufds, 10, &fd_count);
  132. if(mc != CURLM_OK) {
  133. fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
  134. res = TEST_ERR_FAILURE;
  135. break;
  136. }
  137. if(!fd_count)
  138. continue; /* no descriptors yet */
  139. /* checking case when we don't have enough space for waitfds */
  140. mc = curl_multi_waitfds(multi, ufds1, fd_count - 1, NULL);
  141. if(mc != CURLM_OUT_OF_MEMORY) {
  142. fprintf(stderr, "curl_multi_waitfds() return code %d instead of "
  143. "CURLM_OUT_OF_MEMORY.\n", mc);
  144. res = TEST_ERR_FAILURE;
  145. break;
  146. }
  147. if(fd_count > max_count)
  148. max_count = fd_count;
  149. /* Do polling on descriptors in ufds in Multi 1 */
  150. mc = curl_multi_poll(multi1, ufds, fd_count, 500, &numfds);
  151. if(mc != CURLM_OK) {
  152. fprintf(stderr, "curl_multi_poll() failed, code %d.\\n", mc);
  153. res = TEST_ERR_FAILURE;
  154. break;
  155. }
  156. }
  157. for(;;) {
  158. msg = curl_multi_info_read(multi, &msgs_left);
  159. if(!msg)
  160. break;
  161. if(msg->msg == CURLMSG_DONE) {
  162. result = msg->data.result;
  163. if(!res)
  164. res = result;
  165. }
  166. }
  167. curl_multi_remove_handle(multi, easy1);
  168. curl_multi_remove_handle(multi, easy2);
  169. test_cleanup:
  170. curl_easy_cleanup(easy1);
  171. curl_easy_cleanup(easy2);
  172. curl_multi_cleanup(multi);
  173. curl_multi_cleanup(multi1);
  174. if(max_fd_count)
  175. *max_fd_count = max_count;
  176. return res;
  177. }
  178. static CURLcode empty_multi_test(void)
  179. {
  180. CURLMcode mc = CURLM_OK;
  181. CURLM *multi = NULL;
  182. CURL *easy = NULL;
  183. struct curl_waitfd ufds[10];
  184. CURLcode res = CURLE_OK;
  185. unsigned int fd_count = 0;
  186. multi_init(multi);
  187. /* calling curl_multi_waitfds() on an empty multi handle. */
  188. mc = curl_multi_waitfds(multi, ufds, 10, &fd_count);
  189. if(mc != CURLM_OK) {
  190. fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
  191. res = TEST_ERR_FAILURE;
  192. goto test_cleanup;
  193. }
  194. else if(fd_count > 0) {
  195. fprintf(stderr, "curl_multi_waitfds() returned non-zero count of "
  196. "waitfds: %d.\n", fd_count);
  197. res = TEST_ERR_FAILURE;
  198. goto test_cleanup;
  199. }
  200. /* calling curl_multi_waitfds() on multi handle with added easy handle. */
  201. easy_init(easy);
  202. if(set_easy((char *)"http://example.com", easy, TEST_USE_HTTP1) != CURLE_OK)
  203. goto test_cleanup;
  204. multi_add_handle(multi, easy);
  205. mc = curl_multi_waitfds(multi, ufds, 10, &fd_count);
  206. if(mc != CURLM_OK) {
  207. fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
  208. res = TEST_ERR_FAILURE;
  209. goto test_cleanup;
  210. }
  211. else if(fd_count > 0) {
  212. fprintf(stderr, "curl_multi_waitfds() returned non-zero count of "
  213. "waitfds: %d.\n", fd_count);
  214. res = TEST_ERR_FAILURE;
  215. goto test_cleanup;
  216. }
  217. curl_multi_remove_handle(multi, easy);
  218. test_cleanup:
  219. curl_easy_cleanup(easy);
  220. curl_multi_cleanup(multi);
  221. return res;
  222. }
  223. CURLcode test(char *URL)
  224. {
  225. CURLcode res = CURLE_OK;
  226. unsigned int fd_count = 0;
  227. global_init(CURL_GLOBAL_ALL);
  228. /* Testing curl_multi_waitfds on empty and not started handles */
  229. res = empty_multi_test();
  230. if(res != CURLE_OK)
  231. goto test_cleanup;
  232. /* HTTP1, expected 2 waitfds - one for each transfer */
  233. test_run_check(TEST_USE_HTTP1, 2);
  234. /* HTTP2, expected 2 waitfds - one for each transfer */
  235. test_run_check(TEST_USE_HTTP2, 2);
  236. /* HTTP2 with multiplexing, expected 1 waitfds - one for all transfers */
  237. test_run_check(TEST_USE_HTTP2_MPLEX, 1);
  238. test_cleanup:
  239. curl_global_cleanup();
  240. return res;
  241. }