quickjs-tart

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

lib582.c (9754B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      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 #include "first.h"
     25 
     26 #include "memdebug.h"
     27 
     28 struct t582_Sockets {
     29   curl_socket_t *sockets;
     30   int count;      /* number of sockets actually stored in array */
     31   int max_count;  /* max number of sockets that fit in allocated array */
     32 };
     33 
     34 struct t582_ReadWriteSockets {
     35   struct t582_Sockets read, write;
     36 };
     37 
     38 /**
     39  * Remove a file descriptor from a sockets array.
     40  */
     41 static void t582_removeFd(struct t582_Sockets *sockets, curl_socket_t fd,
     42                           int mention)
     43 {
     44   int i;
     45 
     46   if(mention)
     47     curl_mfprintf(stderr, "Remove socket fd %d\n", (int) fd);
     48 
     49   for(i = 0; i < sockets->count; ++i) {
     50     if(sockets->sockets[i] == fd) {
     51       if(i < sockets->count - 1)
     52         memmove(&sockets->sockets[i], &sockets->sockets[i + 1],
     53                 sizeof(curl_socket_t) * (sockets->count - (i + 1)));
     54       --sockets->count;
     55     }
     56   }
     57 }
     58 
     59 /**
     60  * Add a file descriptor to a sockets array.
     61  */
     62 static void t582_addFd(struct t582_Sockets *sockets, curl_socket_t fd,
     63                        const char *what)
     64 {
     65   /**
     66    * To ensure we only have each file descriptor once, we remove it then add
     67    * it again.
     68    */
     69   curl_mfprintf(stderr, "Add socket fd %d for %s\n", (int) fd, what);
     70   t582_removeFd(sockets, fd, 0);
     71   /*
     72    * Allocate array storage when required.
     73    */
     74   if(!sockets->sockets) {
     75     sockets->sockets = malloc(sizeof(curl_socket_t) * 20U);
     76     if(!sockets->sockets)
     77       return;
     78     sockets->max_count = 20;
     79   }
     80   else if(sockets->count >= sockets->max_count) {
     81     /* this can't happen in normal cases */
     82     curl_mfprintf(stderr, "too many file handles error\n");
     83     exit(2);
     84   }
     85   /*
     86    * Add file descriptor to array.
     87    */
     88   sockets->sockets[sockets->count] = fd;
     89   ++sockets->count;
     90 }
     91 
     92 /**
     93  * Callback invoked by curl to poll reading / writing of a socket.
     94  */
     95 static int t582_curlSocketCallback(CURL *easy, curl_socket_t s, int action,
     96                                    void *userp, void *socketp)
     97 {
     98   struct t582_ReadWriteSockets *sockets = userp;
     99 
    100   (void)easy; /* unused */
    101   (void)socketp; /* unused */
    102 
    103   if(action == CURL_POLL_IN || action == CURL_POLL_INOUT)
    104     t582_addFd(&sockets->read, s, "read");
    105 
    106   if(action == CURL_POLL_OUT || action == CURL_POLL_INOUT)
    107     t582_addFd(&sockets->write, s, "write");
    108 
    109   if(action == CURL_POLL_REMOVE) {
    110     t582_removeFd(&sockets->read, s, 1);
    111     t582_removeFd(&sockets->write, s, 0);
    112   }
    113 
    114   return 0;
    115 }
    116 
    117 /**
    118  * Callback invoked by curl to set a timeout.
    119  */
    120 static int t582_curlTimerCallback(CURLM *multi, long timeout_ms, void *userp)
    121 {
    122   struct curltime *timeout = userp;
    123 
    124   (void)multi; /* unused */
    125   if(timeout_ms != -1) {
    126     *timeout = curlx_now();
    127     timeout->tv_usec += (int)timeout_ms * 1000;
    128   }
    129   else {
    130     timeout->tv_sec = -1;
    131   }
    132   return 0;
    133 }
    134 
    135 /**
    136  * Check for curl completion.
    137  */
    138 static int t582_checkForCompletion(CURLM *curl, int *success)
    139 {
    140   int result = 0;
    141   *success = 0;
    142   while(1) {
    143     int numMessages;
    144     CURLMsg *message = curl_multi_info_read(curl, &numMessages);
    145     if(!message)
    146       break;
    147     if(message->msg == CURLMSG_DONE) {
    148       result = 1;
    149       if(message->data.result == CURLE_OK)
    150         *success = 1;
    151       else
    152         *success = 0;
    153     }
    154     else {
    155       curl_mfprintf(stderr, "Got an unexpected message from curl: %i\n",
    156                     (int)message->msg);
    157       result = 1;
    158       *success = 0;
    159     }
    160   }
    161   return result;
    162 }
    163 
    164 static int t582_getMicroSecondTimeout(struct curltime *timeout)
    165 {
    166   struct curltime now;
    167   ssize_t result;
    168   now = curlx_now();
    169   result = (ssize_t)((timeout->tv_sec - now.tv_sec) * 1000000 +
    170     timeout->tv_usec - now.tv_usec);
    171   if(result < 0)
    172     result = 0;
    173 
    174   return curlx_sztosi(result);
    175 }
    176 
    177 /**
    178  * Update a fd_set with all of the sockets in use.
    179  */
    180 static void t582_updateFdSet(struct t582_Sockets *sockets, fd_set* fdset,
    181                              curl_socket_t *maxFd)
    182 {
    183   int i;
    184   for(i = 0; i < sockets->count; ++i) {
    185 #if defined(__DJGPP__)
    186 #pragma GCC diagnostic push
    187 #pragma GCC diagnostic ignored "-Warith-conversion"
    188 #endif
    189     FD_SET(sockets->sockets[i], fdset);
    190 #if defined(__DJGPP__)
    191 #pragma GCC diagnostic pop
    192 #endif
    193     if(*maxFd < sockets->sockets[i] + 1) {
    194       *maxFd = sockets->sockets[i] + 1;
    195     }
    196   }
    197 }
    198 
    199 static void notifyCurl(CURLM *curl, curl_socket_t s, int evBitmask,
    200                        const char *info)
    201 {
    202   int numhandles = 0;
    203   CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles);
    204   if(result != CURLM_OK) {
    205     curl_mfprintf(stderr, "Curl error on %s (%i) %s\n",
    206                   info, result, curl_multi_strerror(result));
    207   }
    208 }
    209 
    210 /**
    211  * Invoke curl when a file descriptor is set.
    212  */
    213 static void t582_checkFdSet(CURLM *curl, struct t582_Sockets *sockets,
    214                             fd_set *fdset, int evBitmask, const char *name)
    215 {
    216   int i;
    217   for(i = 0; i < sockets->count; ++i) {
    218     if(FD_ISSET(sockets->sockets[i], fdset)) {
    219       notifyCurl(curl, sockets->sockets[i], evBitmask, name);
    220     }
    221   }
    222 }
    223 
    224 static CURLcode test_lib582(char *URL)
    225 {
    226   CURLcode res = CURLE_OK;
    227   CURL *curl = NULL;
    228   FILE *hd_src = NULL;
    229   int hd;
    230   struct_stat file_info;
    231   CURLM *m = NULL;
    232   struct t582_ReadWriteSockets sockets = {{NULL, 0, 0}, {NULL, 0, 0}};
    233   int success = 0;
    234   struct curltime timeout = {0};
    235   timeout.tv_sec = (time_t)-1;
    236 
    237   assert(test_argc >= 5);
    238 
    239   start_test_timing();
    240 
    241   if(!libtest_arg3) {
    242     curl_mfprintf(stderr, "Usage: lib582 [url] [filename] [username]\n");
    243     return TEST_ERR_USAGE;
    244   }
    245 
    246   hd_src = fopen(libtest_arg2, "rb");
    247   if(!hd_src) {
    248     curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n",
    249                   errno, strerror(errno));
    250     curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2);
    251     return TEST_ERR_FOPEN;
    252   }
    253 
    254   /* get the file size of the local file */
    255 #ifdef UNDER_CE
    256   hd = stat(libtest_arg2, &file_info);
    257 #else
    258   hd = fstat(fileno(hd_src), &file_info);
    259 #endif
    260   if(hd == -1) {
    261     /* can't open file, bail out */
    262     curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n",
    263                   errno, strerror(errno));
    264     curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2);
    265     fclose(hd_src);
    266     return TEST_ERR_FSTAT;
    267   }
    268   curl_mfprintf(stderr, "Set to upload %d bytes\n", (int)file_info.st_size);
    269 
    270   res_global_init(CURL_GLOBAL_ALL);
    271   if(res != CURLE_OK) {
    272     fclose(hd_src);
    273     return res;
    274   }
    275 
    276   easy_init(curl);
    277 
    278   /* enable uploading */
    279   easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    280 
    281   /* specify target */
    282   easy_setopt(curl, CURLOPT_URL, URL);
    283 
    284   /* go verbose */
    285   easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    286 
    287   /* now specify which file to upload */
    288   easy_setopt(curl, CURLOPT_READDATA, hd_src);
    289 
    290   easy_setopt(curl, CURLOPT_USERPWD, libtest_arg3);
    291   easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, test_argv[4]);
    292   easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, test_argv[5]);
    293   easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    294 
    295   easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
    296 
    297   multi_init(m);
    298 
    299   multi_setopt(m, CURLMOPT_SOCKETFUNCTION, t582_curlSocketCallback);
    300   multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets);
    301 
    302   multi_setopt(m, CURLMOPT_TIMERFUNCTION, t582_curlTimerCallback);
    303   multi_setopt(m, CURLMOPT_TIMERDATA, &timeout);
    304 
    305   multi_add_handle(m, curl);
    306 
    307   while(!t582_checkForCompletion(m, &success)) {
    308     fd_set readSet, writeSet;
    309     curl_socket_t maxFd = 0;
    310     struct timeval tv = {0};
    311     tv.tv_sec = 10;
    312 
    313     FD_ZERO(&readSet);
    314     FD_ZERO(&writeSet);
    315     t582_updateFdSet(&sockets.read, &readSet, &maxFd);
    316     t582_updateFdSet(&sockets.write, &writeSet, &maxFd);
    317 
    318     if(timeout.tv_sec != (time_t)-1) {
    319       int usTimeout = t582_getMicroSecondTimeout(&timeout);
    320       tv.tv_sec = usTimeout / 1000000;
    321       tv.tv_usec = usTimeout % 1000000;
    322     }
    323     else if(maxFd <= 0) {
    324       tv.tv_sec = 0;
    325       tv.tv_usec = 100000;
    326     }
    327 
    328     select_test((int)maxFd, &readSet, &writeSet, NULL, &tv);
    329 
    330     /* Check the sockets for reading / writing */
    331     t582_checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN, "read");
    332     t582_checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT, "write");
    333 
    334     if(timeout.tv_sec != (time_t)-1 &&
    335        t582_getMicroSecondTimeout(&timeout) == 0) {
    336       /* Curl's timer has elapsed. */
    337       notifyCurl(m, CURL_SOCKET_TIMEOUT, 0, "timeout");
    338     }
    339 
    340     abort_on_test_timeout();
    341   }
    342 
    343   if(!success) {
    344     curl_mfprintf(stderr, "Error uploading file.\n");
    345     res = TEST_ERR_MAJOR_BAD;
    346   }
    347 
    348 test_cleanup:
    349 
    350   /* proper cleanup sequence - type PB */
    351 
    352   curl_multi_remove_handle(m, curl);
    353   curl_easy_cleanup(curl);
    354   curl_multi_cleanup(m);
    355   curl_global_cleanup();
    356 
    357   /* close the local file */
    358   fclose(hd_src);
    359 
    360   /* free local memory */
    361   free(sockets.read.sockets);
    362   free(sockets.write.sockets);
    363 
    364   return res;
    365 }