quickjs-tart

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

ws_data.c (7427B)


      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 #ifndef CURL_DISABLE_WEBSOCKETS
     27 
     28 static CURLcode check_recv(const struct curl_ws_frame *frame,
     29                            size_t r_offset, size_t nread, size_t exp_len)
     30 {
     31   if(!frame)
     32     return CURLE_OK;
     33 
     34   if(frame->flags & CURLWS_CLOSE) {
     35     curl_mfprintf(stderr, "recv_data: unexpected CLOSE frame from server, "
     36                   "got %ld bytes, offset=%ld, rflags %x\n",
     37                   (long)nread, (long)r_offset, frame->flags);
     38     return CURLE_RECV_ERROR;
     39   }
     40   if(!r_offset && !(frame->flags & CURLWS_BINARY)) {
     41     curl_mfprintf(stderr, "recv_data: wrong frame, got %ld bytes, offset=%ld, "
     42                   "rflags %x\n",
     43                   (long)nread, (long)r_offset, frame->flags);
     44     return CURLE_RECV_ERROR;
     45   }
     46   if(frame->offset != (curl_off_t)r_offset) {
     47     curl_mfprintf(stderr, "recv_data: frame offset, expected %ld, got %ld\n",
     48                   (long)r_offset, (long)frame->offset);
     49     return CURLE_RECV_ERROR;
     50   }
     51   if(frame->bytesleft != (curl_off_t)(exp_len - r_offset - nread)) {
     52     curl_mfprintf(stderr, "recv_data: frame bytesleft, "
     53                   "expected %ld, got %ld\n",
     54                   (long)(exp_len - r_offset - nread), (long)frame->bytesleft);
     55     return CURLE_RECV_ERROR;
     56   }
     57   if(r_offset + nread > exp_len) {
     58     curl_mfprintf(stderr, "recv_data: data length, expected %ld, now at %ld\n",
     59                   (long)exp_len, (long)(r_offset + nread));
     60     return CURLE_RECV_ERROR;
     61   }
     62   return CURLE_OK;
     63 }
     64 
     65 static CURLcode data_echo(CURL *curl, size_t count,
     66                           size_t plen_min, size_t plen_max)
     67 {
     68   CURLcode r = CURLE_OK;
     69   const struct curl_ws_frame *frame;
     70   size_t len;
     71   char *send_buf = NULL, *recv_buf = NULL;
     72   size_t i, scount = count, rcount = count;
     73   int rblock, sblock;
     74 
     75   send_buf = calloc(1, plen_max + 1);
     76   recv_buf = calloc(1, plen_max + 1);
     77   if(!send_buf || !recv_buf) {
     78     r = CURLE_OUT_OF_MEMORY;
     79     goto out;
     80   }
     81 
     82   for(i = 0; i < plen_max; ++i) {
     83     send_buf[i] = (char)('0' + ((int)i % 10));
     84   }
     85 
     86   for(len = plen_min; len <= plen_max; ++len) {
     87     size_t nwritten, nread, slen = len, rlen = len;
     88     char *sbuf = send_buf, *rbuf = recv_buf;
     89 
     90     memset(recv_buf, 0, plen_max);
     91     while(slen || rlen || scount || rcount) {
     92       sblock = rblock = 1;
     93       if(slen) {
     94         r = curl_ws_send(curl, sbuf, slen, &nwritten, 0, CURLWS_BINARY);
     95         sblock = (r == CURLE_AGAIN);
     96         if(!r || (r == CURLE_AGAIN)) {
     97           curl_mfprintf(stderr, "curl_ws_send(len=%ld) -> %d, %ld (%ld/%ld)\n",
     98                         (long)slen, r, (long)nwritten,
     99                         (long)(len - slen), (long)len);
    100           sbuf += nwritten;
    101           slen -= nwritten;
    102         }
    103         else
    104           goto out;
    105       }
    106       if(!slen && scount) { /* go again? */
    107         scount--;
    108         sbuf = send_buf;
    109         slen = len;
    110       }
    111 
    112       if(rlen) {
    113         size_t max_recv = (64 * 1024);
    114         r = curl_ws_recv(curl, rbuf, (rlen > max_recv) ? max_recv : rlen,
    115                          &nread, &frame);
    116         if(!r || (r == CURLE_AGAIN)) {
    117           rblock = (r == CURLE_AGAIN);
    118           curl_mfprintf(stderr, "curl_ws_recv(len=%ld) -> %d, %ld (%ld/%ld) "
    119                         "\n",
    120                         (long)rlen, r, (long)nread, (long)(len - rlen),
    121                         (long)len);
    122           if(!r) {
    123             r = check_recv(frame, len - rlen, nread, len);
    124             if(r)
    125               goto out;
    126           }
    127           rbuf += nread;
    128           rlen -= nread;
    129         }
    130         else
    131           goto out;
    132       }
    133       if(!rlen && rcount) { /* go again? */
    134         rcount--;
    135         rbuf = recv_buf;
    136         rlen = len;
    137       }
    138 
    139       if(rblock && sblock) {
    140         curl_mfprintf(stderr, "EAGAIN, sleep, try again\n");
    141         curlx_wait_ms(100);
    142       }
    143     }
    144 
    145     if(memcmp(send_buf, recv_buf, len)) {
    146       curl_mfprintf(stderr, "recv_data: data differs\n");
    147       dump("expected:", (unsigned char *)send_buf, len, 0);
    148       dump("received:", (unsigned char *)recv_buf, len, 0);
    149       r = CURLE_RECV_ERROR;
    150       goto out;
    151     }
    152   }
    153 
    154 out:
    155   if(!r)
    156     websocket_close(curl);
    157   free(send_buf);
    158   free(recv_buf);
    159   return r;
    160 }
    161 
    162 static void usage_ws_data(const char *msg)
    163 {
    164   if(msg)
    165     curl_mfprintf(stderr, "%s\n", msg);
    166   curl_mfprintf(stderr,
    167     "usage: [options] url\n"
    168     "  -m number  minimum frame size\n"
    169     "  -M number  maximum frame size\n"
    170   );
    171 }
    172 
    173 #endif
    174 
    175 static int test_ws_data(int argc, char *argv[])
    176 {
    177 #ifndef CURL_DISABLE_WEBSOCKETS
    178   CURL *curl;
    179   CURLcode res = CURLE_OK;
    180   const char *url;
    181   size_t plen_min = 0, plen_max = 0, count = 1;
    182   int ch;
    183 
    184   while((ch = cgetopt(argc, argv, "c:hm:M:")) != -1) {
    185     switch(ch) {
    186     case 'h':
    187       usage_ws_data(NULL);
    188       res = CURLE_BAD_FUNCTION_ARGUMENT;
    189       goto cleanup;
    190     case 'c':
    191       count = (size_t)strtol(coptarg, NULL, 10);
    192       break;
    193     case 'm':
    194       plen_min = (size_t)strtol(coptarg, NULL, 10);
    195       break;
    196     case 'M':
    197       plen_max = (size_t)strtol(coptarg, NULL, 10);
    198       break;
    199     default:
    200       usage_ws_data("invalid option");
    201       res = CURLE_BAD_FUNCTION_ARGUMENT;
    202       goto cleanup;
    203     }
    204   }
    205   argc -= coptind;
    206   argv += coptind;
    207 
    208   if(!plen_max)
    209     plen_max = plen_min;
    210 
    211   if(plen_max < plen_min) {
    212     curl_mfprintf(stderr, "maxlen must be >= minlen, got %ld-%ld\n",
    213                   (long)plen_min, (long)plen_max);
    214     res = CURLE_BAD_FUNCTION_ARGUMENT;
    215     goto cleanup;
    216   }
    217 
    218   if(argc != 1) {
    219     usage_ws_data(NULL);
    220     res = CURLE_BAD_FUNCTION_ARGUMENT;
    221     goto cleanup;
    222   }
    223   url = argv[0];
    224 
    225   curl_global_init(CURL_GLOBAL_ALL);
    226 
    227   curl = curl_easy_init();
    228   if(curl) {
    229     curl_easy_setopt(curl, CURLOPT_URL, url);
    230 
    231     /* use the callback style */
    232     curl_easy_setopt(curl, CURLOPT_USERAGENT, "ws-data");
    233     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    234     curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */
    235     res = curl_easy_perform(curl);
    236     curl_mfprintf(stderr, "curl_easy_perform() returned %u\n", (int)res);
    237     if(res == CURLE_OK)
    238       res = data_echo(curl, count, plen_min, plen_max);
    239 
    240     /* always cleanup */
    241     curl_easy_cleanup(curl);
    242   }
    243 
    244 cleanup:
    245   curl_global_cleanup();
    246   return (int)res;
    247 
    248 #else /* !CURL_DISABLE_WEBSOCKETS */
    249   (void)argc;
    250   (void)argv;
    251   curl_mfprintf(stderr, "WebSockets not enabled in libcurl\n");
    252   return 1;
    253 #endif /* CURL_DISABLE_WEBSOCKETS */
    254 }