• 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 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|CF_TYPE_SSL))
498       return FALSE;
499   }
500   return FALSE;
501 }
502 
Curl_conn_http_version(struct Curl_easy * data)503 unsigned char Curl_conn_http_version(struct Curl_easy *data)
504 {
505   struct Curl_cfilter *cf;
506   CURLcode result = CURLE_UNKNOWN_OPTION;
507   unsigned char v = 0;
508 
509   cf = data->conn ? data->conn->cfilter[FIRSTSOCKET] : NULL;
510   for(; cf; cf = cf->next) {
511     if(cf->cft->flags & CF_TYPE_HTTP) {
512       int value = 0;
513       result = cf->cft->query(cf, data, CF_QUERY_HTTP_VERSION, &value, NULL);
514       if(!result && ((value < 0) || (value > 255)))
515         result = CURLE_FAILED_INIT;
516       else
517         v = (unsigned char)value;
518       break;
519     }
520     if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
521       break;
522   }
523   return (unsigned char)(result ? 0 : v);
524 }
525 
Curl_conn_data_pending(struct Curl_easy * data,int sockindex)526 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
527 {
528   struct Curl_cfilter *cf;
529 
530   (void)data;
531   DEBUGASSERT(data);
532   DEBUGASSERT(data->conn);
533 
534   cf = data->conn->cfilter[sockindex];
535   while(cf && !cf->connected) {
536     cf = cf->next;
537   }
538   if(cf) {
539     return cf->cft->has_data_pending(cf, data);
540   }
541   return FALSE;
542 }
543 
Curl_conn_cf_needs_flush(struct Curl_cfilter * cf,struct Curl_easy * data)544 bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
545                               struct Curl_easy *data)
546 {
547   CURLcode result;
548   int pending = 0;
549   result = cf ? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH,
550                                &pending, NULL) : CURLE_UNKNOWN_OPTION;
551   return (result || !pending) ? FALSE : TRUE;
552 }
553 
Curl_conn_needs_flush(struct Curl_easy * data,int sockindex)554 bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
555 {
556   return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data);
557 }
558 
Curl_conn_cf_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)559 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
560                                  struct Curl_easy *data,
561                                  struct easy_pollset *ps)
562 {
563   /* Get the lowest not-connected filter, if there are any */
564   while(cf && !cf->connected && cf->next && !cf->next->connected)
565     cf = cf->next;
566   /* Skip all filters that have already shut down */
567   while(cf && cf->shutdown)
568     cf = cf->next;
569   /* From there on, give all filters a chance to adjust the pollset.
570    * Lower filters are called later, so they may override */
571   while(cf) {
572     cf->cft->adjust_pollset(cf, data, ps);
573     cf = cf->next;
574   }
575 }
576 
Curl_conn_adjust_pollset(struct Curl_easy * data,struct easy_pollset * ps)577 void Curl_conn_adjust_pollset(struct Curl_easy *data,
578                                struct easy_pollset *ps)
579 {
580   int i;
581 
582   DEBUGASSERT(data);
583   DEBUGASSERT(data->conn);
584   for(i = 0; i < 2; ++i) {
585     Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
586   }
587 }
588 
Curl_conn_cf_poll(struct Curl_cfilter * cf,struct Curl_easy * data,timediff_t timeout_ms)589 int Curl_conn_cf_poll(struct Curl_cfilter *cf,
590                       struct Curl_easy *data,
591                       timediff_t timeout_ms)
592 {
593   struct easy_pollset ps;
594   struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
595   unsigned int i, npfds = 0;
596 
597   DEBUGASSERT(cf);
598   DEBUGASSERT(data);
599   DEBUGASSERT(data->conn);
600   memset(&ps, 0, sizeof(ps));
601   memset(pfds, 0, sizeof(pfds));
602 
603   Curl_conn_cf_adjust_pollset(cf, data, &ps);
604   DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
605   for(i = 0; i < ps.num; ++i) {
606     short events = 0;
607     if(ps.actions[i] & CURL_POLL_IN) {
608       events |= POLLIN;
609     }
610     if(ps.actions[i] & CURL_POLL_OUT) {
611       events |= POLLOUT;
612     }
613     if(events) {
614       pfds[npfds].fd = ps.sockets[i];
615       pfds[npfds].events = events;
616       ++npfds;
617     }
618   }
619 
620   if(!npfds)
621     DEBUGF(infof(data, "no sockets to poll!"));
622   return Curl_poll(pfds, npfds, timeout_ms);
623 }
624 
Curl_conn_get_host(struct Curl_easy * data,int sockindex,const char ** phost,const char ** pdisplay_host,int * pport)625 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
626                         const char **phost, const char **pdisplay_host,
627                         int *pport)
628 {
629   struct Curl_cfilter *cf;
630 
631   DEBUGASSERT(data->conn);
632   cf = data->conn->cfilter[sockindex];
633   if(cf) {
634     cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
635   }
636   else {
637     /* Some filter ask during shutdown for this, mainly for debugging
638      * purposes. We hand out the defaults, however this is not always
639      * accurate, as the connection might be tunneled, etc. But all that
640      * state is already gone here. */
641     *phost = data->conn->host.name;
642     *pdisplay_host = data->conn->host.dispname;
643     *pport = data->conn->remote_port;
644   }
645 }
646 
Curl_cf_def_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)647 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
648                                 struct Curl_easy *data,
649                                 int event, int arg1, void *arg2)
650 {
651   (void)cf;
652   (void)data;
653   (void)event;
654   (void)arg1;
655   (void)arg2;
656   return CURLE_OK;
657 }
658 
Curl_conn_cf_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)659 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
660                             struct Curl_easy *data,
661                             bool ignore_result,
662                             int event, int arg1, void *arg2)
663 {
664   CURLcode result = CURLE_OK;
665 
666   for(; cf; cf = cf->next) {
667     if(Curl_cf_def_cntrl == cf->cft->cntrl)
668       continue;
669     result = cf->cft->cntrl(cf, data, event, arg1, arg2);
670     if(!ignore_result && result)
671       break;
672   }
673   return result;
674 }
675 
Curl_conn_cf_get_socket(struct Curl_cfilter * cf,struct Curl_easy * data)676 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
677                                       struct Curl_easy *data)
678 {
679   curl_socket_t sock;
680   if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
681     return sock;
682   return CURL_SOCKET_BAD;
683 }
684 
Curl_conn_cf_get_ip_info(struct Curl_cfilter * cf,struct Curl_easy * data,int * is_ipv6,struct ip_quadruple * ipquad)685 CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
686                                   struct Curl_easy *data,
687                                   int *is_ipv6, struct ip_quadruple *ipquad)
688 {
689   if(cf)
690     return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad);
691   return CURLE_UNKNOWN_OPTION;
692 }
693 
Curl_conn_get_socket(struct Curl_easy * data,int sockindex)694 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
695 {
696   struct Curl_cfilter *cf;
697 
698   cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
699   /* if the top filter has not connected, ask it (and its sub-filters)
700    * for the socket. Otherwise conn->sock[sockindex] should have it.
701    */
702   if(cf && !cf->connected)
703     return Curl_conn_cf_get_socket(cf, data);
704   return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
705 }
706 
Curl_conn_forget_socket(struct Curl_easy * data,int sockindex)707 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
708 {
709   if(data->conn) {
710     struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
711     if(cf)
712       (void)Curl_conn_cf_cntrl(cf, data, TRUE,
713                                CF_CTRL_FORGET_SOCKET, 0, NULL);
714     fake_sclose(data->conn->sock[sockindex]);
715     data->conn->sock[sockindex] = CURL_SOCKET_BAD;
716   }
717 }
718 
cf_cntrl_all(struct connectdata * conn,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)719 static CURLcode cf_cntrl_all(struct connectdata *conn,
720                              struct Curl_easy *data,
721                              bool ignore_result,
722                              int event, int arg1, void *arg2)
723 {
724   CURLcode result = CURLE_OK;
725   size_t i;
726 
727   for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
728     result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
729                                 event, arg1, arg2);
730     if(!ignore_result && result)
731       break;
732   }
733   return result;
734 }
735 
Curl_conn_ev_data_setup(struct Curl_easy * data)736 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
737 {
738   return cf_cntrl_all(data->conn, data, FALSE,
739                       CF_CTRL_DATA_SETUP, 0, NULL);
740 }
741 
Curl_conn_ev_data_idle(struct Curl_easy * data)742 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
743 {
744   return cf_cntrl_all(data->conn, data, FALSE,
745                       CF_CTRL_DATA_IDLE, 0, NULL);
746 }
747 
748 
Curl_conn_flush(struct Curl_easy * data,int sockindex)749 CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex)
750 {
751   return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE,
752                             CF_CTRL_FLUSH, 0, NULL);
753 }
754 
755 /**
756  * Notify connection filters that the transfer represented by `data`
757  * is done with sending data (e.g. has uploaded everything).
758  */
Curl_conn_ev_data_done_send(struct Curl_easy * data)759 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
760 {
761   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
762 }
763 
764 /**
765  * Notify connection filters that the transfer represented by `data`
766  * is finished - eventually premature, e.g. before being complete.
767  */
Curl_conn_ev_data_done(struct Curl_easy * data,bool premature)768 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
769 {
770   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
771 }
772 
Curl_conn_ev_data_pause(struct Curl_easy * data,bool do_pause)773 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
774 {
775   return cf_cntrl_all(data->conn, data, FALSE,
776                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
777 }
778 
cf_cntrl_update_info(struct Curl_easy * data,struct connectdata * conn)779 static void cf_cntrl_update_info(struct Curl_easy *data,
780                                  struct connectdata *conn)
781 {
782   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
783 }
784 
785 /**
786  * Update connection statistics
787  */
conn_report_connect_stats(struct Curl_easy * data,struct connectdata * conn)788 static void conn_report_connect_stats(struct Curl_easy *data,
789                                       struct connectdata *conn)
790 {
791   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
792   if(cf) {
793     struct curltime connected;
794     struct curltime appconnected;
795 
796     memset(&connected, 0, sizeof(connected));
797     cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
798     if(connected.tv_sec || connected.tv_usec)
799       Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
800 
801     memset(&appconnected, 0, sizeof(appconnected));
802     cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
803     if(appconnected.tv_sec || appconnected.tv_usec)
804       Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
805   }
806 }
807 
Curl_conn_is_alive(struct Curl_easy * data,struct connectdata * conn,bool * input_pending)808 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
809                         bool *input_pending)
810 {
811   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
812   return cf && !cf->conn->bits.close &&
813          cf->cft->is_alive(cf, data, input_pending);
814 }
815 
Curl_conn_keep_alive(struct Curl_easy * data,struct connectdata * conn,int sockindex)816 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
817                               struct connectdata *conn,
818                               int sockindex)
819 {
820   struct Curl_cfilter *cf = conn->cfilter[sockindex];
821   return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK;
822 }
823 
Curl_conn_get_max_concurrent(struct Curl_easy * data,struct connectdata * conn,int sockindex)824 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
825                                      struct connectdata *conn,
826                                      int sockindex)
827 {
828   CURLcode result;
829   int n = 0;
830 
831   struct Curl_cfilter *cf = conn->cfilter[sockindex];
832   result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
833                                &n, NULL) : CURLE_UNKNOWN_OPTION;
834   return (result || n <= 0) ? 1 : (size_t)n;
835 }
836 
Curl_conn_get_stream_error(struct Curl_easy * data,struct connectdata * conn,int sockindex)837 int Curl_conn_get_stream_error(struct Curl_easy *data,
838                                struct connectdata *conn,
839                                int sockindex)
840 {
841   CURLcode result;
842   int n = 0;
843 
844   struct Curl_cfilter *cf = conn->cfilter[sockindex];
845   result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
846                                &n, NULL) : CURLE_UNKNOWN_OPTION;
847   return (result || n < 0) ? 0 : n;
848 }
849 
Curl_conn_sockindex(struct Curl_easy * data,curl_socket_t sockfd)850 int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
851 {
852   if(data && data->conn &&
853      sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
854     return SECONDARYSOCKET;
855   return FIRSTSOCKET;
856 }
857 
Curl_conn_recv(struct Curl_easy * data,int sockindex,char * buf,size_t blen,ssize_t * n)858 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
859                         char *buf, size_t blen, ssize_t *n)
860 {
861   CURLcode result = CURLE_OK;
862   ssize_t nread;
863 
864   DEBUGASSERT(data->conn);
865   nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
866   DEBUGASSERT(nread >= 0 || result);
867   DEBUGASSERT(nread < 0 || !result);
868   *n = (nread >= 0) ? (size_t)nread : 0;
869   return result;
870 }
871 
Curl_conn_send(struct Curl_easy * data,int sockindex,const void * buf,size_t blen,bool eos,size_t * pnwritten)872 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
873                         const void *buf, size_t blen, bool eos,
874                         size_t *pnwritten)
875 {
876   size_t write_len = blen;
877   ssize_t nwritten;
878   CURLcode result = CURLE_OK;
879   struct connectdata *conn;
880 
881   DEBUGASSERT(sockindex >= 0 && sockindex < 2);
882   DEBUGASSERT(pnwritten);
883   DEBUGASSERT(data);
884   DEBUGASSERT(data->conn);
885   conn = data->conn;
886 #ifdef DEBUGBUILD
887   {
888     /* Allow debug builds to override this logic to force short sends
889     */
890     char *p = getenv("CURL_SMALLSENDS");
891     if(p) {
892       size_t altsize = (size_t)strtoul(p, NULL, 10);
893       if(altsize)
894         write_len = CURLMIN(write_len, altsize);
895     }
896   }
897 #endif
898   if(write_len != blen)
899     eos = FALSE;
900   nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
901                                    &result);
902   DEBUGASSERT((nwritten >= 0) || result);
903   *pnwritten = (nwritten < 0) ? 0 : (size_t)nwritten;
904   return result;
905 }
906 
Curl_pollset_reset(struct Curl_easy * data,struct easy_pollset * ps)907 void Curl_pollset_reset(struct Curl_easy *data,
908                         struct easy_pollset *ps)
909 {
910   size_t i;
911   (void)data;
912   memset(ps, 0, sizeof(*ps));
913   for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++)
914     ps->sockets[i] = CURL_SOCKET_BAD;
915 }
916 
917 /**
918  *
919  */
Curl_pollset_change(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,int add_flags,int remove_flags)920 void Curl_pollset_change(struct Curl_easy *data,
921                        struct easy_pollset *ps, curl_socket_t sock,
922                        int add_flags, int remove_flags)
923 {
924   unsigned int i;
925 
926   (void)data;
927   DEBUGASSERT(VALID_SOCK(sock));
928   if(!VALID_SOCK(sock))
929     return;
930 
931   DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
932   DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
933   DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
934   for(i = 0; i < ps->num; ++i) {
935     if(ps->sockets[i] == sock) {
936       ps->actions[i] &= (unsigned char)(~remove_flags);
937       ps->actions[i] |= (unsigned char)add_flags;
938       /* all gone? remove socket */
939       if(!ps->actions[i]) {
940         if((i + 1) < ps->num) {
941           memmove(&ps->sockets[i], &ps->sockets[i + 1],
942                   (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
943           memmove(&ps->actions[i], &ps->actions[i + 1],
944                   (ps->num - (i + 1)) * sizeof(ps->actions[0]));
945         }
946         --ps->num;
947       }
948       return;
949     }
950   }
951   /* not present */
952   if(add_flags) {
953     /* Having more SOCKETS per easy handle than what is defined
954      * is a programming error. This indicates that we need
955      * to raise this limit, making easy_pollset larger.
956      * Since we use this in tight loops, we do not want to make
957      * the pollset dynamic unnecessarily.
958      * The current maximum in practise is HTTP/3 eyeballing where
959      * we have up to 4 sockets involved in connection setup.
960      */
961     DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
962     if(i < MAX_SOCKSPEREASYHANDLE) {
963       ps->sockets[i] = sock;
964       ps->actions[i] = (unsigned char)add_flags;
965       ps->num = i + 1;
966     }
967   }
968 }
969 
Curl_pollset_set(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool do_in,bool do_out)970 void Curl_pollset_set(struct Curl_easy *data,
971                       struct easy_pollset *ps, curl_socket_t sock,
972                       bool do_in, bool do_out)
973 {
974   Curl_pollset_change(data, ps, sock,
975                       (do_in ? CURL_POLL_IN : 0)|
976                       (do_out ? CURL_POLL_OUT : 0),
977                       (!do_in ? CURL_POLL_IN : 0)|
978                       (!do_out ? CURL_POLL_OUT : 0));
979 }
980 
ps_add(struct Curl_easy * data,struct easy_pollset * ps,int bitmap,curl_socket_t * socks)981 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
982                    int bitmap, curl_socket_t *socks)
983 {
984   if(bitmap) {
985     int i;
986     for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
987       if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
988         break;
989       }
990       if(bitmap & GETSOCK_READSOCK(i)) {
991         if(bitmap & GETSOCK_WRITESOCK(i))
992           Curl_pollset_add_inout(data, ps, socks[i]);
993         else
994           /* is READ, since we checked MASK_RW above */
995           Curl_pollset_add_in(data, ps, socks[i]);
996       }
997       else
998         Curl_pollset_add_out(data, ps, socks[i]);
999     }
1000   }
1001 }
1002 
Curl_pollset_add_socks(struct Curl_easy * data,struct easy_pollset * ps,int (* get_socks_cb)(struct Curl_easy * data,curl_socket_t * socks))1003 void Curl_pollset_add_socks(struct Curl_easy *data,
1004                             struct easy_pollset *ps,
1005                             int (*get_socks_cb)(struct Curl_easy *data,
1006                                                 curl_socket_t *socks))
1007 {
1008   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
1009   int bitmap;
1010 
1011   bitmap = get_socks_cb(data, socks);
1012   ps_add(data, ps, bitmap, socks);
1013 }
1014 
Curl_pollset_check(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool * pwant_read,bool * pwant_write)1015 void Curl_pollset_check(struct Curl_easy *data,
1016                         struct easy_pollset *ps, curl_socket_t sock,
1017                         bool *pwant_read, bool *pwant_write)
1018 {
1019   unsigned int i;
1020 
1021   (void)data;
1022   DEBUGASSERT(VALID_SOCK(sock));
1023   for(i = 0; i < ps->num; ++i) {
1024     if(ps->sockets[i] == sock) {
1025       *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
1026       *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
1027       return;
1028     }
1029   }
1030   *pwant_read = *pwant_write = FALSE;
1031 }
1032