• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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" /* for Curl_safefree() */
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 "warnless.h"
38 
39 /* The last 3 #include files should be in this order */
40 #include "curl_printf.h"
41 #include "curl_memory.h"
42 #include "memdebug.h"
43 
44 #ifndef ARRAYSIZE
45 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
46 #endif
47 
48 #ifdef DEBUGBUILD
49 /* used by unit2600.c */
Curl_cf_def_close(struct Curl_cfilter * cf,struct Curl_easy * data)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 static void conn_report_connect_stats(struct Curl_easy *data,
59                                       struct connectdata *conn);
60 
Curl_cf_def_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)61 void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
62                           const char **phost, const char **pdisplay_host,
63                           int *pport)
64 {
65   if(cf->next)
66     cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
67   else {
68     *phost = cf->conn->host.name;
69     *pdisplay_host = cf->conn->host.dispname;
70     *pport = cf->conn->port;
71   }
72 }
73 
Curl_cf_def_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)74 void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
75                                  struct Curl_easy *data,
76                                  struct easy_pollset *ps)
77 {
78   /* NOP */
79   (void)cf;
80   (void)data;
81   (void)ps;
82 }
83 
Curl_cf_def_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)84 bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
85                               const struct Curl_easy *data)
86 {
87   return cf->next?
88     cf->next->cft->has_data_pending(cf->next, data) : FALSE;
89 }
90 
Curl_cf_def_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)91 ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
92                           const void *buf, size_t len, CURLcode *err)
93 {
94   return cf->next?
95     cf->next->cft->do_send(cf->next, data, buf, len, err) :
96     CURLE_RECV_ERROR;
97 }
98 
Curl_cf_def_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)99 ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
100                           char *buf, size_t len, CURLcode *err)
101 {
102   return cf->next?
103     cf->next->cft->do_recv(cf->next, data, buf, len, err) :
104     CURLE_SEND_ERROR;
105 }
106 
Curl_cf_def_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)107 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
108                                struct Curl_easy *data,
109                                bool *input_pending)
110 {
111   return cf->next?
112     cf->next->cft->is_alive(cf->next, data, input_pending) :
113     FALSE; /* pessimistic in absence of data */
114 }
115 
Curl_cf_def_conn_keep_alive(struct Curl_cfilter * cf,struct Curl_easy * data)116 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
117                                      struct Curl_easy *data)
118 {
119   return cf->next?
120     cf->next->cft->keep_alive(cf->next, data) :
121     CURLE_OK;
122 }
123 
Curl_cf_def_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)124 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
125                            struct Curl_easy *data,
126                            int query, int *pres1, void *pres2)
127 {
128   return cf->next?
129     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
130     CURLE_UNKNOWN_OPTION;
131 }
132 
Curl_conn_cf_discard_chain(struct Curl_cfilter ** pcf,struct Curl_easy * data)133 void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
134                                 struct Curl_easy *data)
135 {
136   struct Curl_cfilter *cfn, *cf = *pcf;
137 
138   if(cf) {
139     *pcf = NULL;
140     while(cf) {
141       cfn = cf->next;
142       /* prevent destroying filter to mess with its sub-chain, since
143        * we have the reference now and will call destroy on it.
144        */
145       cf->next = NULL;
146       cf->cft->destroy(cf, data);
147       free(cf);
148       cf = cfn;
149     }
150   }
151 }
152 
Curl_conn_cf_discard_all(struct Curl_easy * data,struct connectdata * conn,int index)153 void Curl_conn_cf_discard_all(struct Curl_easy *data,
154                               struct connectdata *conn, int index)
155 {
156   Curl_conn_cf_discard_chain(&conn->cfilter[index], data);
157 }
158 
Curl_conn_close(struct Curl_easy * data,int index)159 void Curl_conn_close(struct Curl_easy *data, int index)
160 {
161   struct Curl_cfilter *cf;
162 
163   DEBUGASSERT(data->conn);
164   /* it is valid to call that without filters being present */
165   cf = data->conn->cfilter[index];
166   if(cf) {
167     cf->cft->do_close(cf, data);
168   }
169 }
170 
Curl_conn_recv(struct Curl_easy * data,int num,char * buf,size_t len,CURLcode * code)171 ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
172                        size_t len, CURLcode *code)
173 {
174   struct Curl_cfilter *cf;
175 
176   DEBUGASSERT(data);
177   DEBUGASSERT(data->conn);
178   cf = data->conn->cfilter[num];
179   while(cf && !cf->connected) {
180     cf = cf->next;
181   }
182   if(cf) {
183     return cf->cft->do_recv(cf, data, buf, len, code);
184   }
185   failf(data, "recv: no filter connected");
186   *code = CURLE_FAILED_INIT;
187   return -1;
188 }
189 
Curl_conn_send(struct Curl_easy * data,int num,const void * mem,size_t len,CURLcode * code)190 ssize_t Curl_conn_send(struct Curl_easy *data, int num,
191                        const void *mem, size_t len, CURLcode *code)
192 {
193   struct Curl_cfilter *cf;
194 
195   DEBUGASSERT(data);
196   DEBUGASSERT(data->conn);
197   cf = data->conn->cfilter[num];
198   while(cf && !cf->connected) {
199     cf = cf->next;
200   }
201   if(cf) {
202     return cf->cft->do_send(cf, data, mem, len, code);
203   }
204   failf(data, "send: no filter connected");
205   DEBUGASSERT(0);
206   *code = CURLE_FAILED_INIT;
207   return -1;
208 }
209 
Curl_cf_create(struct Curl_cfilter ** pcf,const struct Curl_cftype * cft,void * ctx)210 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
211                         const struct Curl_cftype *cft,
212                         void *ctx)
213 {
214   struct Curl_cfilter *cf;
215   CURLcode result = CURLE_OUT_OF_MEMORY;
216 
217   DEBUGASSERT(cft);
218   cf = calloc(1, sizeof(*cf));
219   if(!cf)
220     goto out;
221 
222   cf->cft = cft;
223   cf->ctx = ctx;
224   result = CURLE_OK;
225 out:
226   *pcf = cf;
227   return result;
228 }
229 
Curl_conn_cf_add(struct Curl_easy * data,struct connectdata * conn,int index,struct Curl_cfilter * cf)230 void Curl_conn_cf_add(struct Curl_easy *data,
231                       struct connectdata *conn,
232                       int index,
233                       struct Curl_cfilter *cf)
234 {
235   (void)data;
236   DEBUGASSERT(conn);
237   DEBUGASSERT(!cf->conn);
238   DEBUGASSERT(!cf->next);
239 
240   cf->next = conn->cfilter[index];
241   cf->conn = conn;
242   cf->sockindex = index;
243   conn->cfilter[index] = cf;
244   CURL_TRC_CF(data, cf, "added");
245 }
246 
Curl_conn_cf_insert_after(struct Curl_cfilter * cf_at,struct Curl_cfilter * cf_new)247 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
248                                struct Curl_cfilter *cf_new)
249 {
250   struct Curl_cfilter *tail, **pnext;
251 
252   DEBUGASSERT(cf_at);
253   DEBUGASSERT(cf_new);
254   DEBUGASSERT(!cf_new->conn);
255 
256   tail = cf_at->next;
257   cf_at->next = cf_new;
258   do {
259     cf_new->conn = cf_at->conn;
260     cf_new->sockindex = cf_at->sockindex;
261     pnext = &cf_new->next;
262     cf_new = cf_new->next;
263   } while(cf_new);
264   *pnext = tail;
265 }
266 
Curl_conn_cf_discard_sub(struct Curl_cfilter * cf,struct Curl_cfilter * discard,struct Curl_easy * data,bool destroy_always)267 bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
268                               struct Curl_cfilter *discard,
269                               struct Curl_easy *data,
270                               bool destroy_always)
271 {
272   struct Curl_cfilter **pprev = &cf->next;
273   bool found = FALSE;
274 
275   /* remove from sub-chain and destroy */
276   DEBUGASSERT(cf);
277   while(*pprev) {
278     if(*pprev == cf) {
279       *pprev = discard->next;
280       discard->next = NULL;
281       found = TRUE;
282       break;
283     }
284     pprev = &((*pprev)->next);
285   }
286   if(found || destroy_always) {
287     discard->next = NULL;
288     discard->cft->destroy(discard, data);
289     free(discard);
290   }
291   return found;
292 }
293 
Curl_conn_cf_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)294 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
295                               struct Curl_easy *data,
296                               bool blocking, bool *done)
297 {
298   if(cf)
299     return cf->cft->do_connect(cf, data, blocking, done);
300   return CURLE_FAILED_INIT;
301 }
302 
Curl_conn_cf_close(struct Curl_cfilter * cf,struct Curl_easy * data)303 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
304 {
305   if(cf)
306     cf->cft->do_close(cf, data);
307 }
308 
Curl_conn_cf_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)309 ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
310                           const void *buf, size_t len, CURLcode *err)
311 {
312   if(cf)
313     return cf->cft->do_send(cf, data, buf, len, err);
314   *err = CURLE_SEND_ERROR;
315   return -1;
316 }
317 
Curl_conn_cf_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)318 ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
319                           char *buf, size_t len, CURLcode *err)
320 {
321   if(cf)
322     return cf->cft->do_recv(cf, data, buf, len, err);
323   *err = CURLE_RECV_ERROR;
324   return -1;
325 }
326 
Curl_conn_connect(struct Curl_easy * data,int sockindex,bool blocking,bool * done)327 CURLcode Curl_conn_connect(struct Curl_easy *data,
328                            int sockindex,
329                            bool blocking,
330                            bool *done)
331 {
332   struct Curl_cfilter *cf;
333   CURLcode result = CURLE_OK;
334 
335   DEBUGASSERT(data);
336   DEBUGASSERT(data->conn);
337 
338   cf = data->conn->cfilter[sockindex];
339   DEBUGASSERT(cf);
340   if(!cf)
341     return CURLE_FAILED_INIT;
342 
343   *done = cf->connected;
344   if(!*done) {
345     result = cf->cft->do_connect(cf, data, blocking, done);
346     if(!result && *done) {
347       Curl_conn_ev_update_info(data, data->conn);
348       conn_report_connect_stats(data, data->conn);
349       data->conn->keepalive = Curl_now();
350     }
351     else if(result) {
352       conn_report_connect_stats(data, data->conn);
353     }
354   }
355 
356   return result;
357 }
358 
Curl_conn_is_connected(struct connectdata * conn,int sockindex)359 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
360 {
361   struct Curl_cfilter *cf;
362 
363   cf = conn->cfilter[sockindex];
364   return cf && cf->connected;
365 }
366 
Curl_conn_is_ip_connected(struct Curl_easy * data,int sockindex)367 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
368 {
369   struct Curl_cfilter *cf;
370 
371   cf = data->conn->cfilter[sockindex];
372   while(cf) {
373     if(cf->connected)
374       return TRUE;
375     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
376       return FALSE;
377     cf = cf->next;
378   }
379   return FALSE;
380 }
381 
Curl_conn_cf_is_ssl(struct Curl_cfilter * cf)382 bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf)
383 {
384   for(; cf; cf = cf->next) {
385     if(cf->cft->flags & CF_TYPE_SSL)
386       return TRUE;
387     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
388       return FALSE;
389   }
390   return FALSE;
391 }
392 
Curl_conn_is_ssl(struct connectdata * conn,int sockindex)393 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
394 {
395   return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
396 }
397 
Curl_conn_is_multiplex(struct connectdata * conn,int sockindex)398 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
399 {
400   struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
401 
402   for(; cf; cf = cf->next) {
403     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
404       return TRUE;
405     if(cf->cft->flags & CF_TYPE_IP_CONNECT
406        || cf->cft->flags & CF_TYPE_SSL)
407       return FALSE;
408   }
409   return FALSE;
410 }
411 
Curl_conn_data_pending(struct Curl_easy * data,int sockindex)412 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
413 {
414   struct Curl_cfilter *cf;
415 
416   (void)data;
417   DEBUGASSERT(data);
418   DEBUGASSERT(data->conn);
419 
420   cf = data->conn->cfilter[sockindex];
421   while(cf && !cf->connected) {
422     cf = cf->next;
423   }
424   if(cf) {
425     return cf->cft->has_data_pending(cf, data);
426   }
427   return FALSE;
428 }
429 
Curl_conn_cf_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)430 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
431                                  struct Curl_easy *data,
432                                  struct easy_pollset *ps)
433 {
434   /* Get the lowest not-connected filter, if there are any */
435   while(cf && !cf->connected && cf->next && !cf->next->connected)
436     cf = cf->next;
437   /* From there on, give all filters a chance to adjust the pollset.
438    * Lower filters are called later, so they may override */
439   while(cf) {
440     cf->cft->adjust_pollset(cf, data, ps);
441     cf = cf->next;
442   }
443 }
444 
Curl_conn_adjust_pollset(struct Curl_easy * data,struct easy_pollset * ps)445 void Curl_conn_adjust_pollset(struct Curl_easy *data,
446                                struct easy_pollset *ps)
447 {
448   int i;
449 
450   DEBUGASSERT(data);
451   DEBUGASSERT(data->conn);
452   for(i = 0; i < 2; ++i) {
453     Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
454   }
455 }
456 
Curl_conn_get_host(struct Curl_easy * data,int sockindex,const char ** phost,const char ** pdisplay_host,int * pport)457 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
458                         const char **phost, const char **pdisplay_host,
459                         int *pport)
460 {
461   struct Curl_cfilter *cf;
462 
463   DEBUGASSERT(data->conn);
464   cf = data->conn->cfilter[sockindex];
465   if(cf) {
466     cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
467   }
468   else {
469     /* Some filter ask during shutdown for this, mainly for debugging
470      * purposes. We hand out the defaults, however this is not always
471      * accurate, as the connection might be tunneled, etc. But all that
472      * state is already gone here. */
473     *phost = data->conn->host.name;
474     *pdisplay_host = data->conn->host.dispname;
475     *pport = data->conn->remote_port;
476   }
477 }
478 
Curl_cf_def_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)479 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
480                                 struct Curl_easy *data,
481                                 int event, int arg1, void *arg2)
482 {
483   (void)cf;
484   (void)data;
485   (void)event;
486   (void)arg1;
487   (void)arg2;
488   return CURLE_OK;
489 }
490 
Curl_conn_cf_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)491 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
492                             struct Curl_easy *data,
493                             bool ignore_result,
494                             int event, int arg1, void *arg2)
495 {
496   CURLcode result = CURLE_OK;
497 
498   for(; cf; cf = cf->next) {
499     if(Curl_cf_def_cntrl == cf->cft->cntrl)
500       continue;
501     result = cf->cft->cntrl(cf, data, event, arg1, arg2);
502     if(!ignore_result && result)
503       break;
504   }
505   return result;
506 }
507 
Curl_conn_cf_get_socket(struct Curl_cfilter * cf,struct Curl_easy * data)508 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
509                                       struct Curl_easy *data)
510 {
511   curl_socket_t sock;
512   if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
513     return sock;
514   return CURL_SOCKET_BAD;
515 }
516 
Curl_conn_get_socket(struct Curl_easy * data,int sockindex)517 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
518 {
519   struct Curl_cfilter *cf;
520 
521   cf = data->conn? data->conn->cfilter[sockindex] : NULL;
522   /* if the top filter has not connected, ask it (and its sub-filters)
523    * for the socket. Otherwise conn->sock[sockindex] should have it.
524    */
525   if(cf && !cf->connected)
526     return Curl_conn_cf_get_socket(cf, data);
527   return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
528 }
529 
Curl_conn_forget_socket(struct Curl_easy * data,int sockindex)530 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
531 {
532   if(data->conn) {
533     struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
534     if(cf)
535       (void)Curl_conn_cf_cntrl(cf, data, TRUE,
536                                CF_CTRL_FORGET_SOCKET, 0, NULL);
537     fake_sclose(data->conn->sock[sockindex]);
538     data->conn->sock[sockindex] = CURL_SOCKET_BAD;
539   }
540 }
541 
cf_cntrl_all(struct connectdata * conn,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)542 static CURLcode cf_cntrl_all(struct connectdata *conn,
543                              struct Curl_easy *data,
544                              bool ignore_result,
545                              int event, int arg1, void *arg2)
546 {
547   CURLcode result = CURLE_OK;
548   size_t i;
549 
550   for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
551     result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
552                                 event, arg1, arg2);
553     if(!ignore_result && result)
554       break;
555   }
556   return result;
557 }
558 
Curl_conn_ev_data_attach(struct connectdata * conn,struct Curl_easy * data)559 void Curl_conn_ev_data_attach(struct connectdata *conn,
560                               struct Curl_easy *data)
561 {
562   cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
563 }
564 
Curl_conn_ev_data_detach(struct connectdata * conn,struct Curl_easy * data)565 void Curl_conn_ev_data_detach(struct connectdata *conn,
566                               struct Curl_easy *data)
567 {
568   cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
569 }
570 
Curl_conn_ev_data_setup(struct Curl_easy * data)571 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
572 {
573   return cf_cntrl_all(data->conn, data, FALSE,
574                       CF_CTRL_DATA_SETUP, 0, NULL);
575 }
576 
Curl_conn_ev_data_idle(struct Curl_easy * data)577 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
578 {
579   return cf_cntrl_all(data->conn, data, FALSE,
580                       CF_CTRL_DATA_IDLE, 0, NULL);
581 }
582 
583 /**
584  * Notify connection filters that the transfer represented by `data`
585  * is donw with sending data (e.g. has uploaded everything).
586  */
Curl_conn_ev_data_done_send(struct Curl_easy * data)587 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
588 {
589   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
590 }
591 
592 /**
593  * Notify connection filters that the transfer represented by `data`
594  * is finished - eventually premature, e.g. before being complete.
595  */
Curl_conn_ev_data_done(struct Curl_easy * data,bool premature)596 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
597 {
598   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
599 }
600 
Curl_conn_ev_data_pause(struct Curl_easy * data,bool do_pause)601 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
602 {
603   return cf_cntrl_all(data->conn, data, FALSE,
604                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
605 }
606 
Curl_conn_ev_update_info(struct Curl_easy * data,struct connectdata * conn)607 void Curl_conn_ev_update_info(struct Curl_easy *data,
608                               struct connectdata *conn)
609 {
610   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
611 }
612 
613 /**
614  * Update connection statistics
615  */
conn_report_connect_stats(struct Curl_easy * data,struct connectdata * conn)616 static void conn_report_connect_stats(struct Curl_easy *data,
617                                       struct connectdata *conn)
618 {
619   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
620   if(cf) {
621     struct curltime connected;
622     struct curltime appconnected;
623 
624     memset(&connected, 0, sizeof(connected));
625     cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
626     if(connected.tv_sec || connected.tv_usec)
627       Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
628 
629     memset(&appconnected, 0, sizeof(appconnected));
630     cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
631     if(appconnected.tv_sec || appconnected.tv_usec)
632       Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
633   }
634 }
635 
Curl_conn_is_alive(struct Curl_easy * data,struct connectdata * conn,bool * input_pending)636 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
637                         bool *input_pending)
638 {
639   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
640   return cf && !cf->conn->bits.close &&
641          cf->cft->is_alive(cf, data, input_pending);
642 }
643 
Curl_conn_keep_alive(struct Curl_easy * data,struct connectdata * conn,int sockindex)644 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
645                               struct connectdata *conn,
646                               int sockindex)
647 {
648   struct Curl_cfilter *cf = conn->cfilter[sockindex];
649   return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
650 }
651 
Curl_conn_get_max_concurrent(struct Curl_easy * data,struct connectdata * conn,int sockindex)652 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
653                                      struct connectdata *conn,
654                                      int sockindex)
655 {
656   CURLcode result;
657   int n = 0;
658 
659   struct Curl_cfilter *cf = conn->cfilter[sockindex];
660   result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
661                               &n, NULL) : CURLE_UNKNOWN_OPTION;
662   return (result || n <= 0)? 1 : (size_t)n;
663 }
664 
665 
Curl_pollset_reset(struct Curl_easy * data,struct easy_pollset * ps)666 void Curl_pollset_reset(struct Curl_easy *data,
667                         struct easy_pollset *ps)
668 {
669   size_t i;
670   (void)data;
671   memset(ps, 0, sizeof(*ps));
672   for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
673     ps->sockets[i] = CURL_SOCKET_BAD;
674 }
675 
676 /**
677  *
678  */
Curl_pollset_change(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,int add_flags,int remove_flags)679 void Curl_pollset_change(struct Curl_easy *data,
680                        struct easy_pollset *ps, curl_socket_t sock,
681                        int add_flags, int remove_flags)
682 {
683   unsigned int i;
684 
685   (void)data;
686   DEBUGASSERT(VALID_SOCK(sock));
687   if(!VALID_SOCK(sock))
688     return;
689 
690   DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
691   DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
692   DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
693   for(i = 0; i < ps->num; ++i) {
694     if(ps->sockets[i] == sock) {
695       ps->actions[i] &= (unsigned char)(~remove_flags);
696       ps->actions[i] |= (unsigned char)add_flags;
697       /* all gone? remove socket */
698       if(!ps->actions[i]) {
699         if((i + 1) < ps->num) {
700           memmove(&ps->sockets[i], &ps->sockets[i + 1],
701                   (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
702           memmove(&ps->actions[i], &ps->actions[i + 1],
703                   (ps->num - (i + 1)) * sizeof(ps->actions[0]));
704         }
705         --ps->num;
706       }
707       return;
708     }
709   }
710   /* not present */
711   if(add_flags) {
712     /* Having more SOCKETS per easy handle than what is defined
713      * is a programming error. This indicates that we need
714      * to raise this limit, making easy_pollset larger.
715      * Since we use this in tight loops, we do not want to make
716      * the pollset dynamic unnecessarily.
717      * The current maximum in practise is HTTP/3 eyeballing where
718      * we have up to 4 sockets involved in connection setup.
719      */
720     DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
721     if(i < MAX_SOCKSPEREASYHANDLE) {
722       ps->sockets[i] = sock;
723       ps->actions[i] = (unsigned char)add_flags;
724       ps->num = i + 1;
725     }
726   }
727 }
728 
Curl_pollset_set(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool do_in,bool do_out)729 void Curl_pollset_set(struct Curl_easy *data,
730                       struct easy_pollset *ps, curl_socket_t sock,
731                       bool do_in, bool do_out)
732 {
733   Curl_pollset_change(data, ps, sock,
734                       (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
735                       (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
736 }
737 
ps_add(struct Curl_easy * data,struct easy_pollset * ps,int bitmap,curl_socket_t * socks)738 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
739                    int bitmap, curl_socket_t *socks)
740 {
741   if(bitmap) {
742     int i;
743     for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
744       if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
745         break;
746       }
747       if(bitmap & GETSOCK_READSOCK(i)) {
748         if(bitmap & GETSOCK_WRITESOCK(i))
749           Curl_pollset_add_inout(data, ps, socks[i]);
750         else
751           /* is READ, since we checked MASK_RW above */
752           Curl_pollset_add_in(data, ps, socks[i]);
753       }
754       else
755         Curl_pollset_add_out(data, ps, socks[i]);
756     }
757   }
758 }
759 
Curl_pollset_add_socks(struct Curl_easy * data,struct easy_pollset * ps,int (* get_socks_cb)(struct Curl_easy * data,curl_socket_t * socks))760 void Curl_pollset_add_socks(struct Curl_easy *data,
761                             struct easy_pollset *ps,
762                             int (*get_socks_cb)(struct Curl_easy *data,
763                                                 curl_socket_t *socks))
764 {
765   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
766   int bitmap;
767 
768   bitmap = get_socks_cb(data, socks);
769   ps_add(data, ps, bitmap, socks);
770 }
771 
Curl_pollset_check(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool * pwant_read,bool * pwant_write)772 void Curl_pollset_check(struct Curl_easy *data,
773                         struct easy_pollset *ps, curl_socket_t sock,
774                         bool *pwant_read, bool *pwant_write)
775 {
776   unsigned int i;
777 
778   (void)data;
779   DEBUGASSERT(VALID_SOCK(sock));
780   for(i = 0; i < ps->num; ++i) {
781     if(ps->sockets[i] == sock) {
782       *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
783       *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
784       return;
785     }
786   }
787   *pwant_read = *pwant_write = FALSE;
788 }
789