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