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