quickjs-tart

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

cfilters.c (34042B)


      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 
     25 #include "curl_setup.h"
     26 
     27 #include "urldata.h"
     28 #include "strerror.h"
     29 #include "cfilters.h"
     30 #include "connect.h"
     31 #include "url.h"
     32 #include "sendf.h"
     33 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
     34 #include "multiif.h"
     35 #include "progress.h"
     36 #include "select.h"
     37 #include "curlx/warnless.h"
     38 #include "curlx/strparse.h"
     39 
     40 /* The last 3 #include files should be in this order */
     41 #include "curl_printf.h"
     42 #include "curl_memory.h"
     43 #include "memdebug.h"
     44 
     45 static void cf_cntrl_update_info(struct Curl_easy *data,
     46                                  struct connectdata *conn);
     47 
     48 #ifdef UNITTESTS
     49 /* used by unit2600.c */
     50 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
     51 {
     52   cf->connected = FALSE;
     53   if(cf->next)
     54     cf->next->cft->do_close(cf->next, data);
     55 }
     56 #endif
     57 
     58 CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
     59                               struct Curl_easy *data, bool *done)
     60 {
     61   (void)cf;
     62   (void)data;
     63   *done = TRUE;
     64   return CURLE_OK;
     65 }
     66 
     67 static void conn_report_connect_stats(struct Curl_easy *data,
     68                                       struct connectdata *conn);
     69 
     70 void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
     71                                 struct Curl_easy *data,
     72                                 struct easy_pollset *ps)
     73 {
     74   /* NOP */
     75   (void)cf;
     76   (void)data;
     77   (void)ps;
     78 }
     79 
     80 bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
     81                               const struct Curl_easy *data)
     82 {
     83   return cf->next ?
     84     cf->next->cft->has_data_pending(cf->next, data) : FALSE;
     85 }
     86 
     87 CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     88                           const void *buf, size_t len, bool eos,
     89                           size_t *pnwritten)
     90 {
     91   if(cf->next)
     92     return cf->next->cft->do_send(cf->next, data, buf, len, eos, pnwritten);
     93   *pnwritten = 0;
     94   return CURLE_RECV_ERROR;
     95 }
     96 
     97 CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     98                           char *buf, size_t len, size_t *pnread)
     99 {
    100   if(cf->next)
    101     return cf->next->cft->do_recv(cf->next, data, buf, len, pnread);
    102   *pnread = 0;
    103   return CURLE_SEND_ERROR;
    104 }
    105 
    106 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
    107                                struct Curl_easy *data,
    108                                bool *input_pending)
    109 {
    110   return cf->next ?
    111     cf->next->cft->is_alive(cf->next, data, input_pending) :
    112     FALSE; /* pessimistic in absence of data */
    113 }
    114 
    115 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
    116                                      struct Curl_easy *data)
    117 {
    118   return cf->next ?
    119     cf->next->cft->keep_alive(cf->next, data) :
    120     CURLE_OK;
    121 }
    122 
    123 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
    124                            struct Curl_easy *data,
    125                            int query, int *pres1, void *pres2)
    126 {
    127   return cf->next ?
    128     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
    129     CURLE_UNKNOWN_OPTION;
    130 }
    131 
    132 void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
    133                                 struct Curl_easy *data)
    134 {
    135   struct Curl_cfilter *cfn, *cf = *pcf;
    136 
    137   if(cf) {
    138     *pcf = NULL;
    139     while(cf) {
    140       cfn = cf->next;
    141       /* prevent destroying filter to mess with its sub-chain, since
    142        * we have the reference now and will call destroy on it.
    143        */
    144       cf->next = NULL;
    145       cf->cft->destroy(cf, data);
    146       free(cf);
    147       cf = cfn;
    148     }
    149   }
    150 }
    151 
    152 void Curl_conn_cf_discard_all(struct Curl_easy *data,
    153                               struct connectdata *conn, int index)
    154 {
    155   Curl_conn_cf_discard_chain(&conn->cfilter[index], data);
    156 }
    157 
    158 void Curl_conn_close(struct Curl_easy *data, int index)
    159 {
    160   struct Curl_cfilter *cf;
    161 
    162   DEBUGASSERT(data->conn);
    163   /* it is valid to call that without filters being present */
    164   cf = data->conn->cfilter[index];
    165   if(cf) {
    166     cf->cft->do_close(cf, data);
    167   }
    168   Curl_shutdown_clear(data, index);
    169 }
    170 
    171 CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
    172 {
    173   struct Curl_cfilter *cf;
    174   CURLcode result = CURLE_OK;
    175   timediff_t timeout_ms;
    176   struct curltime now;
    177 
    178   DEBUGASSERT(data->conn);
    179   /* Get the first connected filter that is not shut down already. */
    180   cf = data->conn->cfilter[sockindex];
    181   while(cf && (!cf->connected || cf->shutdown))
    182     cf = cf->next;
    183 
    184   if(!cf) {
    185     *done = TRUE;
    186     return CURLE_OK;
    187   }
    188 
    189   *done = FALSE;
    190   now = curlx_now();
    191   if(!Curl_shutdown_started(data, sockindex)) {
    192     CURL_TRC_M(data, "shutdown start on%s connection",
    193                sockindex ? " secondary" : "");
    194     Curl_shutdown_start(data, sockindex, 0, &now);
    195   }
    196   else {
    197     timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
    198     if(timeout_ms < 0) {
    199       /* info message, since this might be regarded as acceptable */
    200       infof(data, "shutdown timeout");
    201       return CURLE_OPERATION_TIMEDOUT;
    202     }
    203   }
    204 
    205   while(cf) {
    206     if(!cf->shutdown) {
    207       bool cfdone = FALSE;
    208       result = cf->cft->do_shutdown(cf, data, &cfdone);
    209       if(result) {
    210         CURL_TRC_CF(data, cf, "shut down failed with %d", result);
    211         return result;
    212       }
    213       else if(!cfdone) {
    214         CURL_TRC_CF(data, cf, "shut down not done yet");
    215         return CURLE_OK;
    216       }
    217       CURL_TRC_CF(data, cf, "shut down successfully");
    218       cf->shutdown = TRUE;
    219     }
    220     cf = cf->next;
    221   }
    222   *done = (!result);
    223   return result;
    224 }
    225 
    226 CURLcode Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
    227                       size_t len, size_t *pnread)
    228 {
    229   struct Curl_cfilter *cf;
    230 
    231   DEBUGASSERT(data);
    232   DEBUGASSERT(data->conn);
    233   cf = data->conn->cfilter[num];
    234   while(cf && !cf->connected)
    235     cf = cf->next;
    236   if(cf)
    237     return cf->cft->do_recv(cf, data, buf, len, pnread);
    238   failf(data, "recv: no filter connected");
    239   DEBUGASSERT(0);
    240   *pnread = 0;
    241   return CURLE_FAILED_INIT;
    242 }
    243 
    244 CURLcode Curl_cf_send(struct Curl_easy *data, int num,
    245                       const void *mem, size_t len, bool eos,
    246                       size_t *pnwritten)
    247 {
    248   struct Curl_cfilter *cf;
    249 
    250   DEBUGASSERT(data);
    251   DEBUGASSERT(data->conn);
    252   cf = data->conn->cfilter[num];
    253   while(cf && !cf->connected)
    254     cf = cf->next;
    255   if(cf) {
    256     return cf->cft->do_send(cf, data, mem, len, eos, pnwritten);
    257   }
    258   failf(data, "send: no filter connected");
    259   DEBUGASSERT(0);
    260   *pnwritten = 0;
    261   return CURLE_FAILED_INIT;
    262 }
    263 
    264 struct cf_io_ctx {
    265   struct Curl_easy *data;
    266   struct Curl_cfilter *cf;
    267 };
    268 
    269 static CURLcode cf_bufq_reader(void *writer_ctx,
    270                                unsigned char *buf, size_t blen,
    271                                size_t *pnread)
    272 {
    273   struct cf_io_ctx *io = writer_ctx;
    274   return Curl_conn_cf_recv(io->cf, io->data, (char *)buf, blen, pnread);
    275 }
    276 
    277 CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
    278                            struct Curl_easy *data,
    279                            struct bufq *bufq,
    280                            size_t maxlen,
    281                            size_t *pnread)
    282 {
    283   struct cf_io_ctx io;
    284 
    285   if(!cf || !data) {
    286     *pnread = 0;
    287     return CURLE_BAD_FUNCTION_ARGUMENT;
    288   }
    289   io.data = data;
    290   io.cf = cf;
    291   return Curl_bufq_sipn(bufq, maxlen, cf_bufq_reader, &io, pnread);
    292 }
    293 
    294 static CURLcode cf_bufq_writer(void *writer_ctx,
    295                                const unsigned char *buf, size_t buflen,
    296                                size_t *pnwritten)
    297 {
    298   struct cf_io_ctx *io = writer_ctx;
    299   return Curl_conn_cf_send(io->cf, io->data, (const char *)buf,
    300                            buflen, FALSE, pnwritten);
    301 }
    302 
    303 CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
    304                            struct Curl_easy *data,
    305                            struct bufq *bufq,
    306                            const unsigned char *buf, size_t blen,
    307                            size_t *pnwritten)
    308 {
    309   struct cf_io_ctx io;
    310 
    311   if(!cf || !data) {
    312     *pnwritten = 0;
    313     return CURLE_BAD_FUNCTION_ARGUMENT;
    314   }
    315   io.data = data;
    316   io.cf = cf;
    317   if(buf && blen)
    318     return Curl_bufq_write_pass(bufq, buf, blen, cf_bufq_writer, &io,
    319                                 pnwritten);
    320   else
    321     return Curl_bufq_pass(bufq, cf_bufq_writer, &io, pnwritten);
    322 }
    323 
    324 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
    325                         const struct Curl_cftype *cft,
    326                         void *ctx)
    327 {
    328   struct Curl_cfilter *cf;
    329   CURLcode result = CURLE_OUT_OF_MEMORY;
    330 
    331   DEBUGASSERT(cft);
    332   cf = calloc(1, sizeof(*cf));
    333   if(!cf)
    334     goto out;
    335 
    336   cf->cft = cft;
    337   cf->ctx = ctx;
    338   result = CURLE_OK;
    339 out:
    340   *pcf = cf;
    341   return result;
    342 }
    343 
    344 void Curl_conn_cf_add(struct Curl_easy *data,
    345                       struct connectdata *conn,
    346                       int index,
    347                       struct Curl_cfilter *cf)
    348 {
    349   (void)data;
    350   DEBUGASSERT(conn);
    351   DEBUGASSERT(!cf->conn);
    352   DEBUGASSERT(!cf->next);
    353 
    354   cf->next = conn->cfilter[index];
    355   cf->conn = conn;
    356   cf->sockindex = index;
    357   conn->cfilter[index] = cf;
    358   CURL_TRC_CF(data, cf, "added");
    359 }
    360 
    361 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
    362                                struct Curl_cfilter *cf_new)
    363 {
    364   struct Curl_cfilter *tail, **pnext;
    365 
    366   DEBUGASSERT(cf_at);
    367   DEBUGASSERT(cf_new);
    368   DEBUGASSERT(!cf_new->conn);
    369 
    370   tail = cf_at->next;
    371   cf_at->next = cf_new;
    372   do {
    373     cf_new->conn = cf_at->conn;
    374     cf_new->sockindex = cf_at->sockindex;
    375     pnext = &cf_new->next;
    376     cf_new = cf_new->next;
    377   } while(cf_new);
    378   *pnext = tail;
    379 }
    380 
    381 bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
    382                               struct Curl_cfilter *discard,
    383                               struct Curl_easy *data,
    384                               bool destroy_always)
    385 {
    386   struct Curl_cfilter **pprev = &cf->next;
    387   bool found = FALSE;
    388 
    389   /* remove from sub-chain and destroy */
    390   DEBUGASSERT(cf);
    391   while(*pprev) {
    392     if(*pprev == cf) {
    393       *pprev = discard->next;
    394       discard->next = NULL;
    395       found = TRUE;
    396       break;
    397     }
    398     pprev = &((*pprev)->next);
    399   }
    400   if(found || destroy_always) {
    401     discard->next = NULL;
    402     discard->cft->destroy(discard, data);
    403     free(discard);
    404   }
    405   return found;
    406 }
    407 
    408 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
    409                               struct Curl_easy *data,
    410                               bool *done)
    411 {
    412   if(cf)
    413     return cf->cft->do_connect(cf, data, done);
    414   return CURLE_FAILED_INIT;
    415 }
    416 
    417 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
    418 {
    419   if(cf)
    420     cf->cft->do_close(cf, data);
    421 }
    422 
    423 CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
    424                            const void *buf, size_t len, bool eos,
    425                            size_t *pnwritten)
    426 {
    427   if(cf)
    428     return cf->cft->do_send(cf, data, buf, len, eos, pnwritten);
    429   *pnwritten = 0;
    430   return CURLE_SEND_ERROR;
    431 }
    432 
    433 CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
    434                            char *buf, size_t len, size_t *pnread)
    435 {
    436   if(cf)
    437     return cf->cft->do_recv(cf, data, buf, len, pnread);
    438   *pnread = 0;
    439   return CURLE_RECV_ERROR;
    440 }
    441 
    442 CURLcode Curl_conn_connect(struct Curl_easy *data,
    443                            int sockindex,
    444                            bool blocking,
    445                            bool *done)
    446 {
    447 #define CF_CONN_NUM_POLLS_ON_STACK 5
    448   struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
    449   struct curl_pollfds cpfds;
    450   struct Curl_cfilter *cf;
    451   CURLcode result = CURLE_OK;
    452 
    453   DEBUGASSERT(data);
    454   DEBUGASSERT(data->conn);
    455 
    456   cf = data->conn->cfilter[sockindex];
    457   if(!cf) {
    458     *done = FALSE;
    459     return CURLE_FAILED_INIT;
    460   }
    461 
    462   *done = cf->connected;
    463   if(*done)
    464     return CURLE_OK;
    465 
    466   Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
    467   while(!*done) {
    468     if(Curl_conn_needs_flush(data, sockindex)) {
    469       DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
    470       result = Curl_conn_flush(data, sockindex);
    471       if(result && (result != CURLE_AGAIN))
    472         return result;
    473     }
    474 
    475     result = cf->cft->do_connect(cf, data, done);
    476     CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
    477                 blocking, result, *done);
    478     if(!result && *done) {
    479       /* Now that the complete filter chain is connected, let all filters
    480        * persist information at the connection. E.g. cf-socket sets the
    481        * socket and ip related information. */
    482       cf_cntrl_update_info(data, data->conn);
    483       conn_report_connect_stats(data, data->conn);
    484       data->conn->keepalive = curlx_now();
    485       Curl_verboseconnect(data, data->conn, sockindex);
    486       goto out;
    487     }
    488     else if(result) {
    489       CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
    490                   result);
    491       conn_report_connect_stats(data, data->conn);
    492       goto out;
    493     }
    494 
    495     if(!blocking)
    496       goto out;
    497     else {
    498       /* check allowed time left */
    499       const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
    500       curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
    501       struct easy_pollset ps;
    502       int rc;
    503 
    504       if(timeout_ms < 0) {
    505         /* no need to continue if time already is up */
    506         failf(data, "connect timeout");
    507         result = CURLE_OPERATION_TIMEDOUT;
    508         goto out;
    509       }
    510 
    511       CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
    512       Curl_pollfds_reset(&cpfds);
    513       memset(&ps, 0, sizeof(ps));
    514       /* In general, we want to send after connect, wait on that. */
    515       if(sockfd != CURL_SOCKET_BAD)
    516         Curl_pollset_set_out_only(data, &ps, sockfd);
    517       Curl_conn_adjust_pollset(data, data->conn, &ps);
    518       result = Curl_pollfds_add_ps(&cpfds, &ps);
    519       if(result)
    520         goto out;
    521 
    522       rc = Curl_poll(cpfds.pfds, cpfds.n,
    523                      CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
    524       CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
    525                   rc);
    526       if(rc < 0) {
    527         result = CURLE_COULDNT_CONNECT;
    528         goto out;
    529       }
    530       /* continue iterating */
    531     }
    532   }
    533 
    534 out:
    535   Curl_pollfds_cleanup(&cpfds);
    536   return result;
    537 }
    538 
    539 bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
    540 {
    541   return (conn->cfilter[sockindex] != NULL);
    542 }
    543 
    544 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
    545 {
    546   struct Curl_cfilter *cf;
    547 
    548   cf = conn->cfilter[sockindex];
    549   return cf && cf->connected;
    550 }
    551 
    552 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
    553 {
    554   struct Curl_cfilter *cf;
    555 
    556   cf = data->conn->cfilter[sockindex];
    557   while(cf) {
    558     if(cf->connected)
    559       return TRUE;
    560     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
    561       return FALSE;
    562     cf = cf->next;
    563   }
    564   return FALSE;
    565 }
    566 
    567 bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf)
    568 {
    569   for(; cf; cf = cf->next) {
    570     if(cf->cft->flags & CF_TYPE_SSL)
    571       return TRUE;
    572     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
    573       return FALSE;
    574   }
    575   return FALSE;
    576 }
    577 
    578 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
    579 {
    580   return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
    581 }
    582 
    583 bool Curl_conn_get_ssl_info(struct Curl_easy *data,
    584                             struct connectdata *conn, int sockindex,
    585                             struct curl_tlssessioninfo *info)
    586 {
    587   if(Curl_conn_is_ssl(conn, sockindex)) {
    588     struct Curl_cfilter *cf = conn->cfilter[sockindex];
    589     CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO,
    590                                NULL, (void *)info) : CURLE_UNKNOWN_OPTION;
    591     return !result;
    592   }
    593   return FALSE;
    594 }
    595 
    596 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
    597 {
    598   struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
    599 
    600   for(; cf; cf = cf->next) {
    601     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
    602       return TRUE;
    603     if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
    604       return FALSE;
    605   }
    606   return FALSE;
    607 }
    608 
    609 unsigned char Curl_conn_get_transport(struct Curl_easy *data,
    610                                       struct connectdata *conn)
    611 {
    612   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
    613   return Curl_conn_cf_get_transport(cf, data);
    614 }
    615 
    616 unsigned char Curl_conn_http_version(struct Curl_easy *data,
    617                                      struct connectdata *conn)
    618 {
    619   struct Curl_cfilter *cf;
    620   CURLcode result = CURLE_UNKNOWN_OPTION;
    621   unsigned char v = 0;
    622 
    623   cf = conn->cfilter[FIRSTSOCKET];
    624   for(; cf; cf = cf->next) {
    625     if(cf->cft->flags & CF_TYPE_HTTP) {
    626       int value = 0;
    627       result = cf->cft->query(cf, data, CF_QUERY_HTTP_VERSION, &value, NULL);
    628       if(!result && ((value < 0) || (value > 255)))
    629         result = CURLE_FAILED_INIT;
    630       else
    631         v = (unsigned char)value;
    632       break;
    633     }
    634     if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
    635       break;
    636   }
    637   return (unsigned char)(result ? 0 : v);
    638 }
    639 
    640 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
    641 {
    642   struct Curl_cfilter *cf;
    643 
    644   (void)data;
    645   DEBUGASSERT(data);
    646   DEBUGASSERT(data->conn);
    647 
    648   cf = data->conn->cfilter[sockindex];
    649   while(cf && !cf->connected) {
    650     cf = cf->next;
    651   }
    652   if(cf) {
    653     return cf->cft->has_data_pending(cf, data);
    654   }
    655   return FALSE;
    656 }
    657 
    658 bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
    659                               struct Curl_easy *data)
    660 {
    661   CURLcode result;
    662   int pending = 0;
    663   result = cf ? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH,
    664                                &pending, NULL) : CURLE_UNKNOWN_OPTION;
    665   return (result || !pending) ? FALSE : TRUE;
    666 }
    667 
    668 bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
    669 {
    670   return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data);
    671 }
    672 
    673 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
    674                                  struct Curl_easy *data,
    675                                  struct easy_pollset *ps)
    676 {
    677   /* Get the lowest not-connected filter, if there are any */
    678   while(cf && !cf->connected && cf->next && !cf->next->connected)
    679     cf = cf->next;
    680   /* Skip all filters that have already shut down */
    681   while(cf && cf->shutdown)
    682     cf = cf->next;
    683   /* From there on, give all filters a chance to adjust the pollset.
    684    * Lower filters are called later, so they may override */
    685   while(cf) {
    686     cf->cft->adjust_pollset(cf, data, ps);
    687     cf = cf->next;
    688   }
    689 }
    690 
    691 void Curl_conn_adjust_pollset(struct Curl_easy *data,
    692                               struct connectdata *conn,
    693                               struct easy_pollset *ps)
    694 {
    695   int i;
    696 
    697   DEBUGASSERT(data);
    698   DEBUGASSERT(conn);
    699   for(i = 0; i < 2; ++i) {
    700     Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
    701   }
    702 }
    703 
    704 int Curl_conn_cf_poll(struct Curl_cfilter *cf,
    705                       struct Curl_easy *data,
    706                       timediff_t timeout_ms)
    707 {
    708   struct easy_pollset ps;
    709   struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
    710   unsigned int i, npfds = 0;
    711 
    712   DEBUGASSERT(cf);
    713   DEBUGASSERT(data);
    714   DEBUGASSERT(data->conn);
    715   memset(&ps, 0, sizeof(ps));
    716   memset(pfds, 0, sizeof(pfds));
    717 
    718   Curl_conn_cf_adjust_pollset(cf, data, &ps);
    719   DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
    720   for(i = 0; i < ps.num; ++i) {
    721     short events = 0;
    722     if(ps.actions[i] & CURL_POLL_IN) {
    723       events |= POLLIN;
    724     }
    725     if(ps.actions[i] & CURL_POLL_OUT) {
    726       events |= POLLOUT;
    727     }
    728     if(events) {
    729       pfds[npfds].fd = ps.sockets[i];
    730       pfds[npfds].events = events;
    731       ++npfds;
    732     }
    733   }
    734 
    735   if(!npfds)
    736     DEBUGF(infof(data, "no sockets to poll!"));
    737   return Curl_poll(pfds, npfds, timeout_ms);
    738 }
    739 
    740 void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
    741                                 const char **phost, int *pport)
    742 {
    743   struct Curl_cfilter *cf, *cf_proxy = NULL;
    744 
    745   DEBUGASSERT(data->conn);
    746   cf = data->conn->cfilter[sockindex];
    747   /* Find the "lowest" tunneling proxy filter that has not connected yet. */
    748   while(cf && !cf->connected) {
    749     if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) ==
    750        (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY))
    751        cf_proxy = cf;
    752     cf = cf->next;
    753   }
    754   /* cf_proxy (!= NULL) is not connected yet. It is talking
    755    * to an interim host and any authentication or other things apply
    756    * to this interim host and port. */
    757   if(!cf_proxy || cf_proxy->cft->query(cf_proxy, data, CF_QUERY_HOST_PORT,
    758                                        pport, CURL_UNCONST(phost))) {
    759     /* Everything connected or query unsuccessful, the overall
    760      * connection's destination is the answer */
    761     *phost = data->conn->host.name;
    762     *pport = data->conn->remote_port;
    763   }
    764 }
    765 
    766 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
    767                            struct Curl_easy *data,
    768                            int event, int arg1, void *arg2)
    769 {
    770   (void)cf;
    771   (void)data;
    772   (void)event;
    773   (void)arg1;
    774   (void)arg2;
    775   return CURLE_OK;
    776 }
    777 
    778 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
    779                             struct Curl_easy *data,
    780                             bool ignore_result,
    781                             int event, int arg1, void *arg2)
    782 {
    783   CURLcode result = CURLE_OK;
    784 
    785   for(; cf; cf = cf->next) {
    786     if(Curl_cf_def_cntrl == cf->cft->cntrl)
    787       continue;
    788     result = cf->cft->cntrl(cf, data, event, arg1, arg2);
    789     if(!ignore_result && result)
    790       break;
    791   }
    792   return result;
    793 }
    794 
    795 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
    796                                       struct Curl_easy *data)
    797 {
    798   curl_socket_t sock;
    799   if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
    800     return sock;
    801   return CURL_SOCKET_BAD;
    802 }
    803 
    804 unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
    805                                          struct Curl_easy *data)
    806 {
    807   int transport = 0;
    808   if(cf && !cf->cft->query(cf, data, CF_QUERY_TRANSPORT, &transport, NULL))
    809     return (unsigned char)transport;
    810   return (unsigned char)(data->conn ? data->conn->transport_wanted : 0);
    811 }
    812 
    813 static const struct Curl_sockaddr_ex *
    814 cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data)
    815 {
    816   const struct Curl_sockaddr_ex *remote_addr = NULL;
    817   if(cf &&
    818      !cf->cft->query(cf, data, CF_QUERY_REMOTE_ADDR, NULL,
    819                      CURL_UNCONST(&remote_addr)))
    820     return remote_addr;
    821   return NULL;
    822 }
    823 
    824 CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
    825                                   struct Curl_easy *data,
    826                                   int *is_ipv6, struct ip_quadruple *ipquad)
    827 {
    828   if(cf)
    829     return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad);
    830   return CURLE_UNKNOWN_OPTION;
    831 }
    832 
    833 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
    834 {
    835   struct Curl_cfilter *cf;
    836 
    837   cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
    838   /* if the top filter has not connected, ask it (and its sub-filters)
    839    * for the socket. Otherwise conn->sock[sockindex] should have it.
    840    */
    841   if(cf && !cf->connected)
    842     return Curl_conn_cf_get_socket(cf, data);
    843   return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
    844 }
    845 
    846 const struct Curl_sockaddr_ex *
    847 Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex)
    848 {
    849   struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
    850   return cf ? cf_get_remote_addr(cf, data) : NULL;
    851 }
    852 
    853 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
    854 {
    855   if(data->conn) {
    856     struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
    857     if(cf)
    858       (void)Curl_conn_cf_cntrl(cf, data, TRUE,
    859                                CF_CTRL_FORGET_SOCKET, 0, NULL);
    860     fake_sclose(data->conn->sock[sockindex]);
    861     data->conn->sock[sockindex] = CURL_SOCKET_BAD;
    862   }
    863 }
    864 
    865 static CURLcode cf_cntrl_all(struct connectdata *conn,
    866                              struct Curl_easy *data,
    867                              bool ignore_result,
    868                              int event, int arg1, void *arg2)
    869 {
    870   CURLcode result = CURLE_OK;
    871   size_t i;
    872 
    873   for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
    874     result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
    875                                 event, arg1, arg2);
    876     if(!ignore_result && result)
    877       break;
    878   }
    879   return result;
    880 }
    881 
    882 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
    883 {
    884   return cf_cntrl_all(data->conn, data, FALSE,
    885                       CF_CTRL_DATA_SETUP, 0, NULL);
    886 }
    887 
    888 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
    889 {
    890   return cf_cntrl_all(data->conn, data, FALSE,
    891                       CF_CTRL_DATA_IDLE, 0, NULL);
    892 }
    893 
    894 
    895 CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex)
    896 {
    897   return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE,
    898                             CF_CTRL_FLUSH, 0, NULL);
    899 }
    900 
    901 /**
    902  * Notify connection filters that the transfer represented by `data`
    903  * is done with sending data (e.g. has uploaded everything).
    904  */
    905 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
    906 {
    907   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
    908 }
    909 
    910 /**
    911  * Notify connection filters that the transfer represented by `data`
    912  * is finished - eventually premature, e.g. before being complete.
    913  */
    914 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
    915 {
    916   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
    917 }
    918 
    919 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
    920 {
    921   return cf_cntrl_all(data->conn, data, FALSE,
    922                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
    923 }
    924 
    925 static void cf_cntrl_update_info(struct Curl_easy *data,
    926                                  struct connectdata *conn)
    927 {
    928   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
    929 }
    930 
    931 /**
    932  * Update connection statistics
    933  */
    934 static void conn_report_connect_stats(struct Curl_easy *data,
    935                                       struct connectdata *conn)
    936 {
    937   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
    938   if(cf) {
    939     struct curltime connected;
    940     struct curltime appconnected;
    941 
    942     memset(&connected, 0, sizeof(connected));
    943     cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
    944     if(connected.tv_sec || connected.tv_usec)
    945       Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
    946 
    947     memset(&appconnected, 0, sizeof(appconnected));
    948     cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
    949     if(appconnected.tv_sec || appconnected.tv_usec)
    950       Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
    951   }
    952 }
    953 
    954 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
    955                         bool *input_pending)
    956 {
    957   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
    958   return cf && !cf->conn->bits.close &&
    959          cf->cft->is_alive(cf, data, input_pending);
    960 }
    961 
    962 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
    963                               struct connectdata *conn,
    964                               int sockindex)
    965 {
    966   struct Curl_cfilter *cf = conn->cfilter[sockindex];
    967   return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK;
    968 }
    969 
    970 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
    971                                     struct connectdata *conn,
    972                                     int sockindex)
    973 {
    974   CURLcode result;
    975   int n = 0;
    976 
    977   struct Curl_cfilter *cf = conn->cfilter[sockindex];
    978   result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
    979                                &n, NULL) : CURLE_UNKNOWN_OPTION;
    980   return (result || n <= 0) ? 1 : (size_t)n;
    981 }
    982 
    983 int Curl_conn_get_stream_error(struct Curl_easy *data,
    984                                struct connectdata *conn,
    985                                int sockindex)
    986 {
    987   CURLcode result;
    988   int n = 0;
    989 
    990   struct Curl_cfilter *cf = conn->cfilter[sockindex];
    991   result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
    992                                &n, NULL) : CURLE_UNKNOWN_OPTION;
    993   return (result || n < 0) ? 0 : n;
    994 }
    995 
    996 int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
    997 {
    998   if(data && data->conn &&
    999      sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
   1000     return SECONDARYSOCKET;
   1001   return FIRSTSOCKET;
   1002 }
   1003 
   1004 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
   1005                         char *buf, size_t blen, size_t *pnread)
   1006 {
   1007   DEBUGASSERT(data);
   1008   DEBUGASSERT(data->conn);
   1009   if(data && data->conn && data->conn->recv[sockindex])
   1010     return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread);
   1011   *pnread = 0;
   1012   return CURLE_FAILED_INIT;
   1013 }
   1014 
   1015 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
   1016                         const void *buf, size_t blen, bool eos,
   1017                         size_t *pnwritten)
   1018 {
   1019   size_t write_len = blen;
   1020 
   1021   DEBUGASSERT(data);
   1022   DEBUGASSERT(data->conn);
   1023   DEBUGASSERT(sockindex >= 0 && sockindex < 2);
   1024 #ifdef DEBUGBUILD
   1025   if(write_len) {
   1026     /* Allow debug builds to override this logic to force short sends
   1027     */
   1028     const char *p = getenv("CURL_SMALLSENDS");
   1029     if(p) {
   1030       curl_off_t altsize;
   1031       if(!curlx_str_number(&p, &altsize, write_len))
   1032         write_len = (size_t)altsize;
   1033     }
   1034   }
   1035 #endif
   1036   if(write_len != blen)
   1037     eos = FALSE;
   1038   if(data && data->conn && data->conn->send[sockindex])
   1039     return data->conn->send[sockindex](data, sockindex, buf, write_len, eos,
   1040                                        pnwritten);
   1041   *pnwritten = 0;
   1042   return CURLE_FAILED_INIT;
   1043 }
   1044 
   1045 void Curl_pollset_reset(struct Curl_easy *data,
   1046                         struct easy_pollset *ps)
   1047 {
   1048   size_t i;
   1049   (void)data;
   1050   memset(ps, 0, sizeof(*ps));
   1051   for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++)
   1052     ps->sockets[i] = CURL_SOCKET_BAD;
   1053 }
   1054 
   1055 /**
   1056  *
   1057  */
   1058 void Curl_pollset_change(struct Curl_easy *data,
   1059                          struct easy_pollset *ps, curl_socket_t sock,
   1060                          int add_flags, int remove_flags)
   1061 {
   1062   unsigned int i;
   1063 
   1064   (void)data;
   1065   DEBUGASSERT(VALID_SOCK(sock));
   1066   if(!VALID_SOCK(sock))
   1067     return;
   1068 
   1069   DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
   1070   DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
   1071   DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
   1072   for(i = 0; i < ps->num; ++i) {
   1073     if(ps->sockets[i] == sock) {
   1074       ps->actions[i] &= (unsigned char)(~remove_flags);
   1075       ps->actions[i] |= (unsigned char)add_flags;
   1076       /* all gone? remove socket */
   1077       if(!ps->actions[i]) {
   1078         if((i + 1) < ps->num) {
   1079           memmove(&ps->sockets[i], &ps->sockets[i + 1],
   1080                   (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
   1081           memmove(&ps->actions[i], &ps->actions[i + 1],
   1082                   (ps->num - (i + 1)) * sizeof(ps->actions[0]));
   1083         }
   1084         --ps->num;
   1085       }
   1086       return;
   1087     }
   1088   }
   1089   /* not present */
   1090   if(add_flags) {
   1091     /* Having more SOCKETS per easy handle than what is defined
   1092      * is a programming error. This indicates that we need
   1093      * to raise this limit, making easy_pollset larger.
   1094      * Since we use this in tight loops, we do not want to make
   1095      * the pollset dynamic unnecessarily.
   1096      * The current maximum in practise is HTTP/3 eyeballing where
   1097      * we have up to 4 sockets involved in connection setup.
   1098      */
   1099     DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
   1100     if(i < MAX_SOCKSPEREASYHANDLE) {
   1101       ps->sockets[i] = sock;
   1102       ps->actions[i] = (unsigned char)add_flags;
   1103       ps->num = i + 1;
   1104     }
   1105   }
   1106 }
   1107 
   1108 void Curl_pollset_set(struct Curl_easy *data,
   1109                       struct easy_pollset *ps, curl_socket_t sock,
   1110                       bool do_in, bool do_out)
   1111 {
   1112   Curl_pollset_change(data, ps, sock,
   1113                       (do_in ? CURL_POLL_IN : 0)|
   1114                       (do_out ? CURL_POLL_OUT : 0),
   1115                       (!do_in ? CURL_POLL_IN : 0)|
   1116                       (!do_out ? CURL_POLL_OUT : 0));
   1117 }
   1118 
   1119 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
   1120                    int bitmap, curl_socket_t *socks)
   1121 {
   1122   if(bitmap) {
   1123     int i;
   1124     for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
   1125       if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
   1126         break;
   1127       }
   1128       if(bitmap & GETSOCK_READSOCK(i)) {
   1129         if(bitmap & GETSOCK_WRITESOCK(i))
   1130           Curl_pollset_add_inout(data, ps, socks[i]);
   1131         else
   1132           /* is READ, since we checked MASK_RW above */
   1133           Curl_pollset_add_in(data, ps, socks[i]);
   1134       }
   1135       else
   1136         Curl_pollset_add_out(data, ps, socks[i]);
   1137     }
   1138   }
   1139 }
   1140 
   1141 void Curl_pollset_add_socks(struct Curl_easy *data,
   1142                             struct easy_pollset *ps,
   1143                             int (*get_socks_cb)(struct Curl_easy *data,
   1144                                                 curl_socket_t *socks))
   1145 {
   1146   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
   1147   int bitmap;
   1148 
   1149   bitmap = get_socks_cb(data, socks);
   1150   ps_add(data, ps, bitmap, socks);
   1151 }
   1152 
   1153 void Curl_pollset_check(struct Curl_easy *data,
   1154                         struct easy_pollset *ps, curl_socket_t sock,
   1155                         bool *pwant_read, bool *pwant_write)
   1156 {
   1157   unsigned int i;
   1158 
   1159   (void)data;
   1160   DEBUGASSERT(VALID_SOCK(sock));
   1161   for(i = 0; i < ps->num; ++i) {
   1162     if(ps->sockets[i] == sock) {
   1163       *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
   1164       *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
   1165       return;
   1166     }
   1167   }
   1168   *pwant_read = *pwant_write = FALSE;
   1169 }
   1170 
   1171 bool Curl_pollset_want_read(struct Curl_easy *data,
   1172                             struct easy_pollset *ps,
   1173                             curl_socket_t sock)
   1174 {
   1175   unsigned int i;
   1176   (void)data;
   1177   for(i = 0; i < ps->num; ++i) {
   1178     if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
   1179       return TRUE;
   1180   }
   1181   return FALSE;
   1182 }