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