quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

lib2405.c (11020B)


      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 /*
     26  * The purpose of this test is to test behavior of curl_multi_waitfds
     27  * function in different scenarios:
     28  *  empty multi handle (expected zero descriptors),
     29  *  HTTP1 amd HTTP2 (no multiplexing) two transfers (expected two descriptors),
     30  *  HTTP2 with multiplexing (expected one descriptors)
     31  *  Improper inputs to the API result in CURLM_BAD_FUNCTION_ARGUMENT.
     32  *  Sending an empty ufds, and size = 0 will return the number of fds needed.
     33  *  Sending a non-empty ufds, but smaller than the fds needed will result in a
     34  *    CURLM_OUT_OF_MEMORY, and a number of fds that is >= to the number needed.
     35  *
     36  *  It is also expected that all transfers run by multi-handle should complete
     37  *  successfully.
     38  */
     39 
     40 #include "first.h"
     41 
     42 #include "memdebug.h"
     43 
     44 /* ---------------------------------------------------------------- */
     45 
     46 #define test_check(expected_fds) \
     47   if(res != CURLE_OK) { \
     48     curl_mfprintf(stderr, "test failed with code: %d\n", res); \
     49     goto test_cleanup; \
     50   } \
     51   else if(fd_count != expected_fds) { \
     52     curl_mfprintf(stderr, "Max number of waitfds: %d not as expected: %d\n", \
     53       fd_count, expected_fds); \
     54     res = TEST_ERR_FAILURE; \
     55     goto test_cleanup; \
     56   }
     57 
     58 #define test_run_check(option, expected_fds) do { \
     59   res = test_run(URL, option, &fd_count); \
     60   test_check(expected_fds); \
     61 } while(0)
     62 
     63 /* ---------------------------------------------------------------- */
     64 
     65 enum {
     66   TEST_USE_HTTP1 = 0,
     67   TEST_USE_HTTP2,
     68   TEST_USE_HTTP2_MPLEX
     69 };
     70 
     71 static size_t emptyWriteFunc(void *ptr, size_t size, size_t nmemb,
     72     void *data) {
     73   (void)ptr; (void)data;
     74   return size * nmemb;
     75 }
     76 
     77 static CURLcode set_easy(char *URL, CURL *easy, long option)
     78 {
     79   CURLcode res = CURLE_OK;
     80 
     81   /* First set the URL that is about to receive our POST. */
     82   easy_setopt(easy, CURLOPT_URL, URL);
     83 
     84   /* get verbose debug output please */
     85   easy_setopt(easy, CURLOPT_VERBOSE, 1L);
     86 
     87   switch(option) {
     88   case TEST_USE_HTTP1:
     89     /* go http1 */
     90     easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
     91     break;
     92 
     93   case TEST_USE_HTTP2:
     94     /* go http2 */
     95     easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
     96     break;
     97 
     98   case TEST_USE_HTTP2_MPLEX:
     99     /* go http2 with multiplexing */
    100     easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
    101     easy_setopt(easy, CURLOPT_PIPEWAIT, 1L);
    102     break;
    103   }
    104 
    105   /* no peer verify */
    106   easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L);
    107   easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, 0L);
    108 
    109   /* include headers */
    110   easy_setopt(easy, CURLOPT_HEADER, 1L);
    111 
    112   /* empty write function */
    113   easy_setopt(easy, CURLOPT_WRITEFUNCTION, emptyWriteFunc);
    114 
    115 test_cleanup:
    116   return res;
    117 }
    118 
    119 static CURLcode test_run(char *URL, long option, unsigned int *max_fd_count)
    120 {
    121   CURLMcode mc = CURLM_OK;
    122   CURLM *multi = NULL;
    123   CURLM *multi1 = NULL;
    124 
    125   CURL *easy1 = NULL;
    126   CURL *easy2 = NULL;
    127 
    128   unsigned int max_count = 0;
    129 
    130   int still_running; /* keep number of running handles */
    131   CURLMsg *msg; /* for picking up messages with the transfer status */
    132   int msgs_left; /* how many messages are left */
    133 
    134   CURLcode result;
    135   CURLcode res = CURLE_OK;
    136 
    137   struct curl_waitfd ufds[10];
    138   struct curl_waitfd ufds1[10];
    139   int numfds;
    140 
    141   easy_init(easy1);
    142   easy_init(easy2);
    143 
    144   if(set_easy(URL, easy1, option) != CURLE_OK)
    145     goto test_cleanup;
    146 
    147   if(set_easy(URL, easy2, option) != CURLE_OK)
    148     goto test_cleanup;
    149 
    150   multi_init(multi);
    151   multi_init(multi1);
    152 
    153   if(option == TEST_USE_HTTP2_MPLEX)
    154     multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
    155 
    156   multi_add_handle(multi, easy1);
    157   multi_add_handle(multi, easy2);
    158 
    159   while(!mc) {
    160     /* get the count of file descriptors from the transfers */
    161     unsigned int fd_count = 0;
    162     unsigned int fd_count_chk = 0;
    163 
    164     mc = curl_multi_perform(multi, &still_running);
    165     if(!still_running || mc != CURLM_OK)
    166       break;
    167 
    168     /* verify improper inputs are treated correctly. */
    169     mc = curl_multi_waitfds(multi, NULL, 0, NULL);
    170 
    171     if(mc != CURLM_BAD_FUNCTION_ARGUMENT) {
    172       curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of "
    173                     "CURLM_BAD_FUNCTION_ARGUMENT.\n", mc);
    174       res = TEST_ERR_FAILURE;
    175       break;
    176     }
    177 
    178     mc = curl_multi_waitfds(multi, NULL, 1, NULL);
    179 
    180     if(mc != CURLM_BAD_FUNCTION_ARGUMENT) {
    181       curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of "
    182                     "CURLM_BAD_FUNCTION_ARGUMENT.\n", mc);
    183       res = TEST_ERR_FAILURE;
    184       break;
    185     }
    186 
    187     mc = curl_multi_waitfds(multi, NULL, 1, &fd_count);
    188 
    189     if(mc != CURLM_BAD_FUNCTION_ARGUMENT) {
    190       curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of "
    191                     "CURLM_BAD_FUNCTION_ARGUMENT.\n", mc);
    192       res = TEST_ERR_FAILURE;
    193       break;
    194     }
    195 
    196     mc = curl_multi_waitfds(multi, ufds, 10, &fd_count);
    197 
    198     if(mc != CURLM_OK) {
    199       curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
    200       res = TEST_ERR_FAILURE;
    201       break;
    202     }
    203 
    204     if(!fd_count)
    205       continue; /* no descriptors yet */
    206 
    207     /* verify that sending nothing but the fd_count results in at least the
    208      * same number of fds */
    209     mc = curl_multi_waitfds(multi, NULL, 0, &fd_count_chk);
    210 
    211     if(mc != CURLM_OK) {
    212       curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
    213       res = TEST_ERR_FAILURE;
    214       break;
    215     }
    216 
    217     if(fd_count_chk < fd_count) {
    218       curl_mfprintf(stderr,
    219                     "curl_multi_waitfds() should return at least the number "
    220                     "of fds needed\n");
    221       res = TEST_ERR_FAILURE;
    222       break;
    223     }
    224 
    225     /* checking case when we don't have enough space for waitfds */
    226     mc = curl_multi_waitfds(multi, ufds1, fd_count - 1, &fd_count_chk);
    227 
    228     if(mc != CURLM_OUT_OF_MEMORY) {
    229       curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of "
    230                     "CURLM_OUT_OF_MEMORY.\n", mc);
    231       res = TEST_ERR_FAILURE;
    232       break;
    233     }
    234 
    235     if(fd_count_chk < fd_count) {
    236       curl_mfprintf(stderr,
    237                     "curl_multi_waitfds() should return the amount of fds "
    238                     "needed if enough isn't passed in.\n");
    239       res = TEST_ERR_FAILURE;
    240       break;
    241     }
    242 
    243     /* sending ufds with zero size, is valid */
    244     mc = curl_multi_waitfds(multi, ufds, 0, NULL);
    245 
    246     if(mc != CURLM_OUT_OF_MEMORY) {
    247       curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of "
    248                     "CURLM_OUT_OF_MEMORY.\n", mc);
    249       res = TEST_ERR_FAILURE;
    250       break;
    251     }
    252 
    253     mc = curl_multi_waitfds(multi, ufds, 0, &fd_count_chk);
    254 
    255     if(mc != CURLM_OUT_OF_MEMORY) {
    256       curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of "
    257                     "CURLM_OUT_OF_MEMORY.\n", mc);
    258       res = TEST_ERR_FAILURE;
    259       break;
    260     }
    261 
    262     if(fd_count_chk < fd_count) {
    263       curl_mfprintf(stderr,
    264                     "curl_multi_waitfds() should return the amount of fds "
    265                     "needed if enough isn't passed in.\n");
    266       res = TEST_ERR_FAILURE;
    267       break;
    268     }
    269 
    270     if(fd_count > max_count)
    271       max_count = fd_count;
    272 
    273     /* Do polling on descriptors in ufds in Multi 1 */
    274     mc = curl_multi_poll(multi1, ufds, fd_count, 500, &numfds);
    275 
    276     if(mc != CURLM_OK) {
    277       curl_mfprintf(stderr, "curl_multi_poll() failed, code %d.\\n", mc);
    278       res = TEST_ERR_FAILURE;
    279       break;
    280     }
    281   }
    282 
    283   for(;;) {
    284     msg = curl_multi_info_read(multi, &msgs_left);
    285     if(!msg)
    286       break;
    287     if(msg->msg == CURLMSG_DONE) {
    288       result = msg->data.result;
    289 
    290       if(!res)
    291         res = result;
    292     }
    293   }
    294 
    295   curl_multi_remove_handle(multi, easy1);
    296   curl_multi_remove_handle(multi, easy2);
    297 
    298 test_cleanup:
    299   curl_easy_cleanup(easy1);
    300   curl_easy_cleanup(easy2);
    301 
    302   curl_multi_cleanup(multi);
    303   curl_multi_cleanup(multi1);
    304 
    305   if(max_fd_count)
    306     *max_fd_count = max_count;
    307 
    308   return res;
    309 }
    310 
    311 static CURLcode empty_multi_test(void)
    312 {
    313   CURLMcode mc = CURLM_OK;
    314   CURLM *multi = NULL;
    315   CURL *easy = NULL;
    316 
    317   struct curl_waitfd ufds[10];
    318 
    319   CURLcode res = CURLE_OK;
    320   unsigned int fd_count = 0;
    321 
    322   multi_init(multi);
    323 
    324   /* calling curl_multi_waitfds() on an empty multi handle.  */
    325   mc = curl_multi_waitfds(multi, ufds, 10, &fd_count);
    326 
    327   if(mc != CURLM_OK) {
    328     curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
    329     res = TEST_ERR_FAILURE;
    330     goto test_cleanup;
    331   }
    332   else if(fd_count > 0) {
    333     curl_mfprintf(stderr, "curl_multi_waitfds() returned non-zero count of "
    334                   "waitfds: %d.\n", fd_count);
    335     res = TEST_ERR_FAILURE;
    336     goto test_cleanup;
    337   }
    338 
    339   /* calling curl_multi_waitfds() on multi handle with added easy handle. */
    340   easy_init(easy);
    341 
    342   if(set_easy((char *)CURL_UNCONST("http://example.com"), easy,
    343               TEST_USE_HTTP1) != CURLE_OK)
    344     goto test_cleanup;
    345 
    346   multi_add_handle(multi, easy);
    347 
    348   mc = curl_multi_waitfds(multi, ufds, 10, &fd_count);
    349 
    350   if(mc != CURLM_OK) {
    351     curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc);
    352     res = TEST_ERR_FAILURE;
    353     goto test_cleanup;
    354   }
    355   else if(fd_count > 0) {
    356     curl_mfprintf(stderr, "curl_multi_waitfds() returned non-zero count of "
    357                   "waitfds: %d.\n", fd_count);
    358     res = TEST_ERR_FAILURE;
    359     goto test_cleanup;
    360   }
    361 
    362   curl_multi_remove_handle(multi, easy);
    363 
    364 test_cleanup:
    365   curl_easy_cleanup(easy);
    366   curl_multi_cleanup(multi);
    367   return res;
    368 }
    369 
    370 static CURLcode test_lib2405(char *URL)
    371 {
    372   CURLcode res = CURLE_OK;
    373   unsigned int fd_count = 0;
    374 
    375   global_init(CURL_GLOBAL_ALL);
    376 
    377   /* Testing curl_multi_waitfds on empty and not started handles */
    378   res = empty_multi_test();
    379   if(res != CURLE_OK)
    380     goto test_cleanup;
    381 
    382   /* HTTP1, expected 2 waitfds - one for each transfer */
    383   test_run_check(TEST_USE_HTTP1, 2);
    384 
    385   /* HTTP2, expected 2 waitfds - one for each transfer */
    386   test_run_check(TEST_USE_HTTP2, 2);
    387 
    388   /* HTTP2 with multiplexing, expected 1 waitfds - one for all transfers */
    389   test_run_check(TEST_USE_HTTP2_MPLEX, 1);
    390 
    391 test_cleanup:
    392   curl_global_cleanup();
    393   return res;
    394 }