xref: /curl/lib/cfilters.c (revision c6655f70)
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->primary.remote_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_cf_recv(struct Curl_easy * data,int num,char * buf,size_t len,CURLcode * code)171 ssize_t Curl_cf_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   *code = CURLE_OK;
179   cf = data->conn->cfilter[num];
180   while(cf && !cf->connected) {
181     cf = cf->next;
182   }
183   if(cf) {
184     ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
185     DEBUGASSERT(nread >= 0 || *code);
186     DEBUGASSERT(nread < 0 || !*code);
187     return nread;
188   }
189   failf(data, "recv: no filter connected");
190   *code = CURLE_FAILED_INIT;
191   return -1;
192 }
193 
Curl_cf_send(struct Curl_easy * data,int num,const void * mem,size_t len,CURLcode * code)194 ssize_t Curl_cf_send(struct Curl_easy *data, int num,
195                      const void *mem, size_t len, CURLcode *code)
196 {
197   struct Curl_cfilter *cf;
198 
199   DEBUGASSERT(data);
200   DEBUGASSERT(data->conn);
201   *code = CURLE_OK;
202   cf = data->conn->cfilter[num];
203   while(cf && !cf->connected) {
204     cf = cf->next;
205   }
206   if(cf) {
207     ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
208     DEBUGASSERT(nwritten >= 0 || *code);
209     DEBUGASSERT(nwritten < 0 || !*code || !len);
210     return nwritten;
211   }
212   failf(data, "send: no filter connected");
213   DEBUGASSERT(0);
214   *code = CURLE_FAILED_INIT;
215   return -1;
216 }
217 
Curl_cf_create(struct Curl_cfilter ** pcf,const struct Curl_cftype * cft,void * ctx)218 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
219                         const struct Curl_cftype *cft,
220                         void *ctx)
221 {
222   struct Curl_cfilter *cf;
223   CURLcode result = CURLE_OUT_OF_MEMORY;
224 
225   DEBUGASSERT(cft);
226   cf = calloc(1, sizeof(*cf));
227   if(!cf)
228     goto out;
229 
230   cf->cft = cft;
231   cf->ctx = ctx;
232   result = CURLE_OK;
233 out:
234   *pcf = cf;
235   return result;
236 }
237 
Curl_conn_cf_add(struct Curl_easy * data,struct connectdata * conn,int index,struct Curl_cfilter * cf)238 void Curl_conn_cf_add(struct Curl_easy *data,
239                       struct connectdata *conn,
240                       int index,
241                       struct Curl_cfilter *cf)
242 {
243   (void)data;
244   DEBUGASSERT(conn);
245   DEBUGASSERT(!cf->conn);
246   DEBUGASSERT(!cf->next);
247 
248   cf->next = conn->cfilter[index];
249   cf->conn = conn;
250   cf->sockindex = index;
251   conn->cfilter[index] = cf;
252   CURL_TRC_CF(data, cf, "added");
253 }
254 
Curl_conn_cf_insert_after(struct Curl_cfilter * cf_at,struct Curl_cfilter * cf_new)255 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
256                                struct Curl_cfilter *cf_new)
257 {
258   struct Curl_cfilter *tail, **pnext;
259 
260   DEBUGASSERT(cf_at);
261   DEBUGASSERT(cf_new);
262   DEBUGASSERT(!cf_new->conn);
263 
264   tail = cf_at->next;
265   cf_at->next = cf_new;
266   do {
267     cf_new->conn = cf_at->conn;
268     cf_new->sockindex = cf_at->sockindex;
269     pnext = &cf_new->next;
270     cf_new = cf_new->next;
271   } while(cf_new);
272   *pnext = tail;
273 }
274 
Curl_conn_cf_discard_sub(struct Curl_cfilter * cf,struct Curl_cfilter * discard,struct Curl_easy * data,bool destroy_always)275 bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
276                               struct Curl_cfilter *discard,
277                               struct Curl_easy *data,
278                               bool destroy_always)
279 {
280   struct Curl_cfilter **pprev = &cf->next;
281   bool found = FALSE;
282 
283   /* remove from sub-chain and destroy */
284   DEBUGASSERT(cf);
285   while(*pprev) {
286     if(*pprev == cf) {
287       *pprev = discard->next;
288       discard->next = NULL;
289       found = TRUE;
290       break;
291     }
292     pprev = &((*pprev)->next);
293   }
294   if(found || destroy_always) {
295     discard->next = NULL;
296     discard->cft->destroy(discard, data);
297     free(discard);
298   }
299   return found;
300 }
301 
Curl_conn_cf_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)302 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
303                               struct Curl_easy *data,
304                               bool blocking, bool *done)
305 {
306   if(cf)
307     return cf->cft->do_connect(cf, data, blocking, done);
308   return CURLE_FAILED_INIT;
309 }
310 
Curl_conn_cf_close(struct Curl_cfilter * cf,struct Curl_easy * data)311 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
312 {
313   if(cf)
314     cf->cft->do_close(cf, data);
315 }
316 
Curl_conn_cf_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)317 ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
318                           const void *buf, size_t len, CURLcode *err)
319 {
320   if(cf)
321     return cf->cft->do_send(cf, data, buf, len, err);
322   *err = CURLE_SEND_ERROR;
323   return -1;
324 }
325 
Curl_conn_cf_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)326 ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
327                           char *buf, size_t len, CURLcode *err)
328 {
329   if(cf)
330     return cf->cft->do_recv(cf, data, buf, len, err);
331   *err = CURLE_RECV_ERROR;
332   return -1;
333 }
334 
Curl_conn_connect(struct Curl_easy * data,int sockindex,bool blocking,bool * done)335 CURLcode Curl_conn_connect(struct Curl_easy *data,
336                            int sockindex,
337                            bool blocking,
338                            bool *done)
339 {
340   struct Curl_cfilter *cf;
341   CURLcode result = CURLE_OK;
342 
343   DEBUGASSERT(data);
344   DEBUGASSERT(data->conn);
345 
346   cf = data->conn->cfilter[sockindex];
347   DEBUGASSERT(cf);
348   if(!cf)
349     return CURLE_FAILED_INIT;
350 
351   *done = cf->connected;
352   if(!*done) {
353     result = cf->cft->do_connect(cf, data, blocking, done);
354     if(!result && *done) {
355       Curl_conn_ev_update_info(data, data->conn);
356       conn_report_connect_stats(data, data->conn);
357       data->conn->keepalive = Curl_now();
358     }
359     else if(result) {
360       conn_report_connect_stats(data, data->conn);
361     }
362   }
363 
364   return result;
365 }
366 
Curl_conn_is_connected(struct connectdata * conn,int sockindex)367 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
368 {
369   struct Curl_cfilter *cf;
370 
371   cf = conn->cfilter[sockindex];
372   return cf && cf->connected;
373 }
374 
Curl_conn_is_ip_connected(struct Curl_easy * data,int sockindex)375 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
376 {
377   struct Curl_cfilter *cf;
378 
379   cf = data->conn->cfilter[sockindex];
380   while(cf) {
381     if(cf->connected)
382       return TRUE;
383     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
384       return FALSE;
385     cf = cf->next;
386   }
387   return FALSE;
388 }
389 
Curl_conn_cf_is_ssl(struct Curl_cfilter * cf)390 bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf)
391 {
392   for(; cf; cf = cf->next) {
393     if(cf->cft->flags & CF_TYPE_SSL)
394       return TRUE;
395     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
396       return FALSE;
397   }
398   return FALSE;
399 }
400 
Curl_conn_is_ssl(struct connectdata * conn,int sockindex)401 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
402 {
403   return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
404 }
405 
Curl_conn_is_multiplex(struct connectdata * conn,int sockindex)406 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
407 {
408   struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
409 
410   for(; cf; cf = cf->next) {
411     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
412       return TRUE;
413     if(cf->cft->flags & CF_TYPE_IP_CONNECT
414        || cf->cft->flags & CF_TYPE_SSL)
415       return FALSE;
416   }
417   return FALSE;
418 }
419 
Curl_conn_data_pending(struct Curl_easy * data,int sockindex)420 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
421 {
422   struct Curl_cfilter *cf;
423 
424   (void)data;
425   DEBUGASSERT(data);
426   DEBUGASSERT(data->conn);
427 
428   cf = data->conn->cfilter[sockindex];
429   while(cf && !cf->connected) {
430     cf = cf->next;
431   }
432   if(cf) {
433     return cf->cft->has_data_pending(cf, data);
434   }
435   return FALSE;
436 }
437 
Curl_conn_cf_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)438 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
439                                  struct Curl_easy *data,
440                                  struct easy_pollset *ps)
441 {
442   /* Get the lowest not-connected filter, if there are any */
443   while(cf && !cf->connected && cf->next && !cf->next->connected)
444     cf = cf->next;
445   /* From there on, give all filters a chance to adjust the pollset.
446    * Lower filters are called later, so they may override */
447   while(cf) {
448     cf->cft->adjust_pollset(cf, data, ps);
449     cf = cf->next;
450   }
451 }
452 
Curl_conn_adjust_pollset(struct Curl_easy * data,struct easy_pollset * ps)453 void Curl_conn_adjust_pollset(struct Curl_easy *data,
454                                struct easy_pollset *ps)
455 {
456   int i;
457 
458   DEBUGASSERT(data);
459   DEBUGASSERT(data->conn);
460   for(i = 0; i < 2; ++i) {
461     Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
462   }
463 }
464 
Curl_conn_get_host(struct Curl_easy * data,int sockindex,const char ** phost,const char ** pdisplay_host,int * pport)465 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
466                         const char **phost, const char **pdisplay_host,
467                         int *pport)
468 {
469   struct Curl_cfilter *cf;
470 
471   DEBUGASSERT(data->conn);
472   cf = data->conn->cfilter[sockindex];
473   if(cf) {
474     cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
475   }
476   else {
477     /* Some filter ask during shutdown for this, mainly for debugging
478      * purposes. We hand out the defaults, however this is not always
479      * accurate, as the connection might be tunneled, etc. But all that
480      * state is already gone here. */
481     *phost = data->conn->host.name;
482     *pdisplay_host = data->conn->host.dispname;
483     *pport = data->conn->remote_port;
484   }
485 }
486 
Curl_cf_def_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)487 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
488                                 struct Curl_easy *data,
489                                 int event, int arg1, void *arg2)
490 {
491   (void)cf;
492   (void)data;
493   (void)event;
494   (void)arg1;
495   (void)arg2;
496   return CURLE_OK;
497 }
498 
Curl_conn_cf_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)499 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
500                             struct Curl_easy *data,
501                             bool ignore_result,
502                             int event, int arg1, void *arg2)
503 {
504   CURLcode result = CURLE_OK;
505 
506   for(; cf; cf = cf->next) {
507     if(Curl_cf_def_cntrl == cf->cft->cntrl)
508       continue;
509     result = cf->cft->cntrl(cf, data, event, arg1, arg2);
510     if(!ignore_result && result)
511       break;
512   }
513   return result;
514 }
515 
Curl_conn_cf_get_socket(struct Curl_cfilter * cf,struct Curl_easy * data)516 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
517                                       struct Curl_easy *data)
518 {
519   curl_socket_t sock;
520   if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
521     return sock;
522   return CURL_SOCKET_BAD;
523 }
524 
Curl_conn_get_socket(struct Curl_easy * data,int sockindex)525 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
526 {
527   struct Curl_cfilter *cf;
528 
529   cf = data->conn? data->conn->cfilter[sockindex] : NULL;
530   /* if the top filter has not connected, ask it (and its sub-filters)
531    * for the socket. Otherwise conn->sock[sockindex] should have it.
532    */
533   if(cf && !cf->connected)
534     return Curl_conn_cf_get_socket(cf, data);
535   return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
536 }
537 
Curl_conn_forget_socket(struct Curl_easy * data,int sockindex)538 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
539 {
540   if(data->conn) {
541     struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
542     if(cf)
543       (void)Curl_conn_cf_cntrl(cf, data, TRUE,
544                                CF_CTRL_FORGET_SOCKET, 0, NULL);
545     fake_sclose(data->conn->sock[sockindex]);
546     data->conn->sock[sockindex] = CURL_SOCKET_BAD;
547   }
548 }
549 
cf_cntrl_all(struct connectdata * conn,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)550 static CURLcode cf_cntrl_all(struct connectdata *conn,
551                              struct Curl_easy *data,
552                              bool ignore_result,
553                              int event, int arg1, void *arg2)
554 {
555   CURLcode result = CURLE_OK;
556   size_t i;
557 
558   for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
559     result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
560                                 event, arg1, arg2);
561     if(!ignore_result && result)
562       break;
563   }
564   return result;
565 }
566 
Curl_conn_ev_data_attach(struct connectdata * conn,struct Curl_easy * data)567 void Curl_conn_ev_data_attach(struct connectdata *conn,
568                               struct Curl_easy *data)
569 {
570   cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
571 }
572 
Curl_conn_ev_data_detach(struct connectdata * conn,struct Curl_easy * data)573 void Curl_conn_ev_data_detach(struct connectdata *conn,
574                               struct Curl_easy *data)
575 {
576   cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
577 }
578 
Curl_conn_ev_data_setup(struct Curl_easy * data)579 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
580 {
581   return cf_cntrl_all(data->conn, data, FALSE,
582                       CF_CTRL_DATA_SETUP, 0, NULL);
583 }
584 
Curl_conn_ev_data_idle(struct Curl_easy * data)585 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
586 {
587   return cf_cntrl_all(data->conn, data, FALSE,
588                       CF_CTRL_DATA_IDLE, 0, NULL);
589 }
590 
591 /**
592  * Notify connection filters that the transfer represented by `data`
593  * is done with sending data (e.g. has uploaded everything).
594  */
Curl_conn_ev_data_done_send(struct Curl_easy * data)595 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
596 {
597   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
598 }
599 
600 /**
601  * Notify connection filters that the transfer represented by `data`
602  * is finished - eventually premature, e.g. before being complete.
603  */
Curl_conn_ev_data_done(struct Curl_easy * data,bool premature)604 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
605 {
606   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
607 }
608 
Curl_conn_ev_data_pause(struct Curl_easy * data,bool do_pause)609 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
610 {
611   return cf_cntrl_all(data->conn, data, FALSE,
612                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
613 }
614 
Curl_conn_ev_update_info(struct Curl_easy * data,struct connectdata * conn)615 void Curl_conn_ev_update_info(struct Curl_easy *data,
616                               struct connectdata *conn)
617 {
618   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
619 }
620 
621 /**
622  * Update connection statistics
623  */
conn_report_connect_stats(struct Curl_easy * data,struct connectdata * conn)624 static void conn_report_connect_stats(struct Curl_easy *data,
625                                       struct connectdata *conn)
626 {
627   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
628   if(cf) {
629     struct curltime connected;
630     struct curltime appconnected;
631 
632     memset(&connected, 0, sizeof(connected));
633     cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
634     if(connected.tv_sec || connected.tv_usec)
635       Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
636 
637     memset(&appconnected, 0, sizeof(appconnected));
638     cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
639     if(appconnected.tv_sec || appconnected.tv_usec)
640       Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
641   }
642 }
643 
Curl_conn_is_alive(struct Curl_easy * data,struct connectdata * conn,bool * input_pending)644 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
645                         bool *input_pending)
646 {
647   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
648   return cf && !cf->conn->bits.close &&
649          cf->cft->is_alive(cf, data, input_pending);
650 }
651 
Curl_conn_keep_alive(struct Curl_easy * data,struct connectdata * conn,int sockindex)652 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
653                               struct connectdata *conn,
654                               int sockindex)
655 {
656   struct Curl_cfilter *cf = conn->cfilter[sockindex];
657   return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
658 }
659 
Curl_conn_get_max_concurrent(struct Curl_easy * data,struct connectdata * conn,int sockindex)660 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
661                                      struct connectdata *conn,
662                                      int sockindex)
663 {
664   CURLcode result;
665   int n = 0;
666 
667   struct Curl_cfilter *cf = conn->cfilter[sockindex];
668   result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
669                               &n, NULL) : CURLE_UNKNOWN_OPTION;
670   return (result || n <= 0)? 1 : (size_t)n;
671 }
672 
Curl_conn_get_stream_error(struct Curl_easy * data,struct connectdata * conn,int sockindex)673 int Curl_conn_get_stream_error(struct Curl_easy *data,
674                                struct connectdata *conn,
675                                int sockindex)
676 {
677   CURLcode result;
678   int n = 0;
679 
680   struct Curl_cfilter *cf = conn->cfilter[sockindex];
681   result = cf? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
682                               &n, NULL) : CURLE_UNKNOWN_OPTION;
683   return (result || n < 0)? 0 : n;
684 }
685 
Curl_conn_sockindex(struct Curl_easy * data,curl_socket_t sockfd)686 int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
687 {
688   if(data && data->conn &&
689      sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
690     return SECONDARYSOCKET;
691   return FIRSTSOCKET;
692 }
693 
Curl_conn_recv(struct Curl_easy * data,int sockindex,char * buf,size_t blen,ssize_t * n)694 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
695                         char *buf, size_t blen, ssize_t *n)
696 {
697   CURLcode result = CURLE_OK;
698   ssize_t nread;
699 
700   DEBUGASSERT(data->conn);
701   nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
702   DEBUGASSERT(nread >= 0 || result);
703   DEBUGASSERT(nread < 0 || !result);
704   *n = (nread >= 0)? (size_t)nread : 0;
705   return result;
706 }
707 
Curl_conn_send(struct Curl_easy * data,int sockindex,const void * buf,size_t blen,size_t * pnwritten)708 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
709                         const void *buf, size_t blen,
710                         size_t *pnwritten)
711 {
712   ssize_t nwritten;
713   CURLcode result = CURLE_OK;
714   struct connectdata *conn;
715 
716   DEBUGASSERT(sockindex >= 0 && sockindex < 2);
717   DEBUGASSERT(pnwritten);
718   DEBUGASSERT(data);
719   DEBUGASSERT(data->conn);
720   conn = data->conn;
721 #ifdef CURLDEBUG
722   {
723     /* Allow debug builds to override this logic to force short sends
724     */
725     char *p = getenv("CURL_SMALLSENDS");
726     if(p) {
727       size_t altsize = (size_t)strtoul(p, NULL, 10);
728       if(altsize)
729         blen = CURLMIN(blen, altsize);
730     }
731   }
732 #endif
733   nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
734   DEBUGASSERT((nwritten >= 0) || result);
735   *pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
736   return result;
737 }
738 
Curl_pollset_reset(struct Curl_easy * data,struct easy_pollset * ps)739 void Curl_pollset_reset(struct Curl_easy *data,
740                         struct easy_pollset *ps)
741 {
742   size_t i;
743   (void)data;
744   memset(ps, 0, sizeof(*ps));
745   for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
746     ps->sockets[i] = CURL_SOCKET_BAD;
747 }
748 
749 /**
750  *
751  */
Curl_pollset_change(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,int add_flags,int remove_flags)752 void Curl_pollset_change(struct Curl_easy *data,
753                        struct easy_pollset *ps, curl_socket_t sock,
754                        int add_flags, int remove_flags)
755 {
756   unsigned int i;
757 
758   (void)data;
759   DEBUGASSERT(VALID_SOCK(sock));
760   if(!VALID_SOCK(sock))
761     return;
762 
763   DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
764   DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
765   DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
766   for(i = 0; i < ps->num; ++i) {
767     if(ps->sockets[i] == sock) {
768       ps->actions[i] &= (unsigned char)(~remove_flags);
769       ps->actions[i] |= (unsigned char)add_flags;
770       /* all gone? remove socket */
771       if(!ps->actions[i]) {
772         if((i + 1) < ps->num) {
773           memmove(&ps->sockets[i], &ps->sockets[i + 1],
774                   (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
775           memmove(&ps->actions[i], &ps->actions[i + 1],
776                   (ps->num - (i + 1)) * sizeof(ps->actions[0]));
777         }
778         --ps->num;
779       }
780       return;
781     }
782   }
783   /* not present */
784   if(add_flags) {
785     /* Having more SOCKETS per easy handle than what is defined
786      * is a programming error. This indicates that we need
787      * to raise this limit, making easy_pollset larger.
788      * Since we use this in tight loops, we do not want to make
789      * the pollset dynamic unnecessarily.
790      * The current maximum in practise is HTTP/3 eyeballing where
791      * we have up to 4 sockets involved in connection setup.
792      */
793     DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
794     if(i < MAX_SOCKSPEREASYHANDLE) {
795       ps->sockets[i] = sock;
796       ps->actions[i] = (unsigned char)add_flags;
797       ps->num = i + 1;
798     }
799   }
800 }
801 
Curl_pollset_set(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool do_in,bool do_out)802 void Curl_pollset_set(struct Curl_easy *data,
803                       struct easy_pollset *ps, curl_socket_t sock,
804                       bool do_in, bool do_out)
805 {
806   Curl_pollset_change(data, ps, sock,
807                       (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
808                       (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
809 }
810 
ps_add(struct Curl_easy * data,struct easy_pollset * ps,int bitmap,curl_socket_t * socks)811 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
812                    int bitmap, curl_socket_t *socks)
813 {
814   if(bitmap) {
815     int i;
816     for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
817       if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
818         break;
819       }
820       if(bitmap & GETSOCK_READSOCK(i)) {
821         if(bitmap & GETSOCK_WRITESOCK(i))
822           Curl_pollset_add_inout(data, ps, socks[i]);
823         else
824           /* is READ, since we checked MASK_RW above */
825           Curl_pollset_add_in(data, ps, socks[i]);
826       }
827       else
828         Curl_pollset_add_out(data, ps, socks[i]);
829     }
830   }
831 }
832 
Curl_pollset_add_socks(struct Curl_easy * data,struct easy_pollset * ps,int (* get_socks_cb)(struct Curl_easy * data,curl_socket_t * socks))833 void Curl_pollset_add_socks(struct Curl_easy *data,
834                             struct easy_pollset *ps,
835                             int (*get_socks_cb)(struct Curl_easy *data,
836                                                 curl_socket_t *socks))
837 {
838   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
839   int bitmap;
840 
841   bitmap = get_socks_cb(data, socks);
842   ps_add(data, ps, bitmap, socks);
843 }
844 
Curl_pollset_check(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool * pwant_read,bool * pwant_write)845 void Curl_pollset_check(struct Curl_easy *data,
846                         struct easy_pollset *ps, curl_socket_t sock,
847                         bool *pwant_read, bool *pwant_write)
848 {
849   unsigned int i;
850 
851   (void)data;
852   DEBUGASSERT(VALID_SOCK(sock));
853   for(i = 0; i < ps->num; ++i) {
854     if(ps->sockets[i] == sock) {
855       *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
856       *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
857       return;
858     }
859   }
860   *pwant_read = *pwant_write = FALSE;
861 }
862