1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 #include "curl_setup.h"
26
27 #include "urldata.h"
28 #include "strerror.h"
29 #include "cfilters.h"
30 #include "connect.h"
31 #include "url.h" /* for Curl_safefree() */
32 #include "sendf.h"
33 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
34 #include "multiif.h"
35 #include "progress.h"
36 #include "select.h"
37 #include "warnless.h"
38
39 /* The last 3 #include files should be in this order */
40 #include "curl_printf.h"
41 #include "curl_memory.h"
42 #include "memdebug.h"
43
44 #ifndef ARRAYSIZE
45 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
46 #endif
47
48 #ifdef DEBUGBUILD
49 /* used by unit2600.c */
Curl_cf_def_close(struct Curl_cfilter * cf,struct Curl_easy * data)50 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
51 {
52 cf->connected = FALSE;
53 if(cf->next)
54 cf->next->cft->do_close(cf->next, data);
55 }
56 #endif
57
58 static void conn_report_connect_stats(struct Curl_easy *data,
59 struct connectdata *conn);
60
Curl_cf_def_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)61 void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
62 const char **phost, const char **pdisplay_host,
63 int *pport)
64 {
65 if(cf->next)
66 cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
67 else {
68 *phost = cf->conn->host.name;
69 *pdisplay_host = cf->conn->host.dispname;
70 *pport = cf->conn->port;
71 }
72 }
73
Curl_cf_def_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)74 void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
75 struct Curl_easy *data,
76 struct easy_pollset *ps)
77 {
78 /* NOP */
79 (void)cf;
80 (void)data;
81 (void)ps;
82 }
83
Curl_cf_def_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)84 bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
85 const struct Curl_easy *data)
86 {
87 return cf->next?
88 cf->next->cft->has_data_pending(cf->next, data) : FALSE;
89 }
90
Curl_cf_def_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)91 ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
92 const void *buf, size_t len, CURLcode *err)
93 {
94 return cf->next?
95 cf->next->cft->do_send(cf->next, data, buf, len, err) :
96 CURLE_RECV_ERROR;
97 }
98
Curl_cf_def_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)99 ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
100 char *buf, size_t len, CURLcode *err)
101 {
102 return cf->next?
103 cf->next->cft->do_recv(cf->next, data, buf, len, err) :
104 CURLE_SEND_ERROR;
105 }
106
Curl_cf_def_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)107 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
108 struct Curl_easy *data,
109 bool *input_pending)
110 {
111 return cf->next?
112 cf->next->cft->is_alive(cf->next, data, input_pending) :
113 FALSE; /* pessimistic in absence of data */
114 }
115
Curl_cf_def_conn_keep_alive(struct Curl_cfilter * cf,struct Curl_easy * data)116 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
117 struct Curl_easy *data)
118 {
119 return cf->next?
120 cf->next->cft->keep_alive(cf->next, data) :
121 CURLE_OK;
122 }
123
Curl_cf_def_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)124 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
125 struct Curl_easy *data,
126 int query, int *pres1, void *pres2)
127 {
128 return cf->next?
129 cf->next->cft->query(cf->next, data, query, pres1, pres2) :
130 CURLE_UNKNOWN_OPTION;
131 }
132
Curl_conn_cf_discard_chain(struct Curl_cfilter ** pcf,struct Curl_easy * data)133 void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
134 struct Curl_easy *data)
135 {
136 struct Curl_cfilter *cfn, *cf = *pcf;
137
138 if(cf) {
139 *pcf = NULL;
140 while(cf) {
141 cfn = cf->next;
142 /* prevent destroying filter to mess with its sub-chain, since
143 * we have the reference now and will call destroy on it.
144 */
145 cf->next = NULL;
146 cf->cft->destroy(cf, data);
147 free(cf);
148 cf = cfn;
149 }
150 }
151 }
152
Curl_conn_cf_discard_all(struct Curl_easy * data,struct connectdata * conn,int index)153 void Curl_conn_cf_discard_all(struct Curl_easy *data,
154 struct connectdata *conn, int index)
155 {
156 Curl_conn_cf_discard_chain(&conn->cfilter[index], data);
157 }
158
Curl_conn_close(struct Curl_easy * data,int index)159 void Curl_conn_close(struct Curl_easy *data, int index)
160 {
161 struct Curl_cfilter *cf;
162
163 DEBUGASSERT(data->conn);
164 /* it is valid to call that without filters being present */
165 cf = data->conn->cfilter[index];
166 if(cf) {
167 cf->cft->do_close(cf, data);
168 }
169 }
170
Curl_conn_recv(struct Curl_easy * data,int num,char * buf,size_t len,CURLcode * code)171 ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
172 size_t len, CURLcode *code)
173 {
174 struct Curl_cfilter *cf;
175
176 DEBUGASSERT(data);
177 DEBUGASSERT(data->conn);
178 cf = data->conn->cfilter[num];
179 while(cf && !cf->connected) {
180 cf = cf->next;
181 }
182 if(cf) {
183 return cf->cft->do_recv(cf, data, buf, len, code);
184 }
185 failf(data, "recv: no filter connected");
186 *code = CURLE_FAILED_INIT;
187 return -1;
188 }
189
Curl_conn_send(struct Curl_easy * data,int num,const void * mem,size_t len,CURLcode * code)190 ssize_t Curl_conn_send(struct Curl_easy *data, int num,
191 const void *mem, size_t len, CURLcode *code)
192 {
193 struct Curl_cfilter *cf;
194
195 DEBUGASSERT(data);
196 DEBUGASSERT(data->conn);
197 cf = data->conn->cfilter[num];
198 while(cf && !cf->connected) {
199 cf = cf->next;
200 }
201 if(cf) {
202 return cf->cft->do_send(cf, data, mem, len, code);
203 }
204 failf(data, "send: no filter connected");
205 DEBUGASSERT(0);
206 *code = CURLE_FAILED_INIT;
207 return -1;
208 }
209
Curl_cf_create(struct Curl_cfilter ** pcf,const struct Curl_cftype * cft,void * ctx)210 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
211 const struct Curl_cftype *cft,
212 void *ctx)
213 {
214 struct Curl_cfilter *cf;
215 CURLcode result = CURLE_OUT_OF_MEMORY;
216
217 DEBUGASSERT(cft);
218 cf = calloc(1, sizeof(*cf));
219 if(!cf)
220 goto out;
221
222 cf->cft = cft;
223 cf->ctx = ctx;
224 result = CURLE_OK;
225 out:
226 *pcf = cf;
227 return result;
228 }
229
Curl_conn_cf_add(struct Curl_easy * data,struct connectdata * conn,int index,struct Curl_cfilter * cf)230 void Curl_conn_cf_add(struct Curl_easy *data,
231 struct connectdata *conn,
232 int index,
233 struct Curl_cfilter *cf)
234 {
235 (void)data;
236 DEBUGASSERT(conn);
237 DEBUGASSERT(!cf->conn);
238 DEBUGASSERT(!cf->next);
239
240 cf->next = conn->cfilter[index];
241 cf->conn = conn;
242 cf->sockindex = index;
243 conn->cfilter[index] = cf;
244 CURL_TRC_CF(data, cf, "added");
245 }
246
Curl_conn_cf_insert_after(struct Curl_cfilter * cf_at,struct Curl_cfilter * cf_new)247 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
248 struct Curl_cfilter *cf_new)
249 {
250 struct Curl_cfilter *tail, **pnext;
251
252 DEBUGASSERT(cf_at);
253 DEBUGASSERT(cf_new);
254 DEBUGASSERT(!cf_new->conn);
255
256 tail = cf_at->next;
257 cf_at->next = cf_new;
258 do {
259 cf_new->conn = cf_at->conn;
260 cf_new->sockindex = cf_at->sockindex;
261 pnext = &cf_new->next;
262 cf_new = cf_new->next;
263 } while(cf_new);
264 *pnext = tail;
265 }
266
Curl_conn_cf_discard_sub(struct Curl_cfilter * cf,struct Curl_cfilter * discard,struct Curl_easy * data,bool destroy_always)267 bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
268 struct Curl_cfilter *discard,
269 struct Curl_easy *data,
270 bool destroy_always)
271 {
272 struct Curl_cfilter **pprev = &cf->next;
273 bool found = FALSE;
274
275 /* remove from sub-chain and destroy */
276 DEBUGASSERT(cf);
277 while(*pprev) {
278 if(*pprev == cf) {
279 *pprev = discard->next;
280 discard->next = NULL;
281 found = TRUE;
282 break;
283 }
284 pprev = &((*pprev)->next);
285 }
286 if(found || destroy_always) {
287 discard->next = NULL;
288 discard->cft->destroy(discard, data);
289 free(discard);
290 }
291 return found;
292 }
293
Curl_conn_cf_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)294 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
295 struct Curl_easy *data,
296 bool blocking, bool *done)
297 {
298 if(cf)
299 return cf->cft->do_connect(cf, data, blocking, done);
300 return CURLE_FAILED_INIT;
301 }
302
Curl_conn_cf_close(struct Curl_cfilter * cf,struct Curl_easy * data)303 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
304 {
305 if(cf)
306 cf->cft->do_close(cf, data);
307 }
308
Curl_conn_cf_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)309 ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
310 const void *buf, size_t len, CURLcode *err)
311 {
312 if(cf)
313 return cf->cft->do_send(cf, data, buf, len, err);
314 *err = CURLE_SEND_ERROR;
315 return -1;
316 }
317
Curl_conn_cf_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)318 ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
319 char *buf, size_t len, CURLcode *err)
320 {
321 if(cf)
322 return cf->cft->do_recv(cf, data, buf, len, err);
323 *err = CURLE_RECV_ERROR;
324 return -1;
325 }
326
Curl_conn_connect(struct Curl_easy * data,int sockindex,bool blocking,bool * done)327 CURLcode Curl_conn_connect(struct Curl_easy *data,
328 int sockindex,
329 bool blocking,
330 bool *done)
331 {
332 struct Curl_cfilter *cf;
333 CURLcode result = CURLE_OK;
334
335 DEBUGASSERT(data);
336 DEBUGASSERT(data->conn);
337
338 cf = data->conn->cfilter[sockindex];
339 DEBUGASSERT(cf);
340 if(!cf)
341 return CURLE_FAILED_INIT;
342
343 *done = cf->connected;
344 if(!*done) {
345 result = cf->cft->do_connect(cf, data, blocking, done);
346 if(!result && *done) {
347 Curl_conn_ev_update_info(data, data->conn);
348 conn_report_connect_stats(data, data->conn);
349 data->conn->keepalive = Curl_now();
350 }
351 else if(result) {
352 conn_report_connect_stats(data, data->conn);
353 }
354 }
355
356 return result;
357 }
358
Curl_conn_is_connected(struct connectdata * conn,int sockindex)359 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
360 {
361 struct Curl_cfilter *cf;
362
363 cf = conn->cfilter[sockindex];
364 return cf && cf->connected;
365 }
366
Curl_conn_is_ip_connected(struct Curl_easy * data,int sockindex)367 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
368 {
369 struct Curl_cfilter *cf;
370
371 cf = data->conn->cfilter[sockindex];
372 while(cf) {
373 if(cf->connected)
374 return TRUE;
375 if(cf->cft->flags & CF_TYPE_IP_CONNECT)
376 return FALSE;
377 cf = cf->next;
378 }
379 return FALSE;
380 }
381
Curl_conn_cf_is_ssl(struct Curl_cfilter * cf)382 bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf)
383 {
384 for(; cf; cf = cf->next) {
385 if(cf->cft->flags & CF_TYPE_SSL)
386 return TRUE;
387 if(cf->cft->flags & CF_TYPE_IP_CONNECT)
388 return FALSE;
389 }
390 return FALSE;
391 }
392
Curl_conn_is_ssl(struct connectdata * conn,int sockindex)393 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
394 {
395 return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
396 }
397
Curl_conn_is_multiplex(struct connectdata * conn,int sockindex)398 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
399 {
400 struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
401
402 for(; cf; cf = cf->next) {
403 if(cf->cft->flags & CF_TYPE_MULTIPLEX)
404 return TRUE;
405 if(cf->cft->flags & CF_TYPE_IP_CONNECT
406 || cf->cft->flags & CF_TYPE_SSL)
407 return FALSE;
408 }
409 return FALSE;
410 }
411
Curl_conn_data_pending(struct Curl_easy * data,int sockindex)412 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
413 {
414 struct Curl_cfilter *cf;
415
416 (void)data;
417 DEBUGASSERT(data);
418 DEBUGASSERT(data->conn);
419
420 cf = data->conn->cfilter[sockindex];
421 while(cf && !cf->connected) {
422 cf = cf->next;
423 }
424 if(cf) {
425 return cf->cft->has_data_pending(cf, data);
426 }
427 return FALSE;
428 }
429
Curl_conn_cf_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)430 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
431 struct Curl_easy *data,
432 struct easy_pollset *ps)
433 {
434 /* Get the lowest not-connected filter, if there are any */
435 while(cf && !cf->connected && cf->next && !cf->next->connected)
436 cf = cf->next;
437 /* From there on, give all filters a chance to adjust the pollset.
438 * Lower filters are called later, so they may override */
439 while(cf) {
440 cf->cft->adjust_pollset(cf, data, ps);
441 cf = cf->next;
442 }
443 }
444
Curl_conn_adjust_pollset(struct Curl_easy * data,struct easy_pollset * ps)445 void Curl_conn_adjust_pollset(struct Curl_easy *data,
446 struct easy_pollset *ps)
447 {
448 int i;
449
450 DEBUGASSERT(data);
451 DEBUGASSERT(data->conn);
452 for(i = 0; i < 2; ++i) {
453 Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
454 }
455 }
456
Curl_conn_get_host(struct Curl_easy * data,int sockindex,const char ** phost,const char ** pdisplay_host,int * pport)457 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
458 const char **phost, const char **pdisplay_host,
459 int *pport)
460 {
461 struct Curl_cfilter *cf;
462
463 DEBUGASSERT(data->conn);
464 cf = data->conn->cfilter[sockindex];
465 if(cf) {
466 cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
467 }
468 else {
469 /* Some filter ask during shutdown for this, mainly for debugging
470 * purposes. We hand out the defaults, however this is not always
471 * accurate, as the connection might be tunneled, etc. But all that
472 * state is already gone here. */
473 *phost = data->conn->host.name;
474 *pdisplay_host = data->conn->host.dispname;
475 *pport = data->conn->remote_port;
476 }
477 }
478
Curl_cf_def_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)479 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
480 struct Curl_easy *data,
481 int event, int arg1, void *arg2)
482 {
483 (void)cf;
484 (void)data;
485 (void)event;
486 (void)arg1;
487 (void)arg2;
488 return CURLE_OK;
489 }
490
Curl_conn_cf_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)491 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
492 struct Curl_easy *data,
493 bool ignore_result,
494 int event, int arg1, void *arg2)
495 {
496 CURLcode result = CURLE_OK;
497
498 for(; cf; cf = cf->next) {
499 if(Curl_cf_def_cntrl == cf->cft->cntrl)
500 continue;
501 result = cf->cft->cntrl(cf, data, event, arg1, arg2);
502 if(!ignore_result && result)
503 break;
504 }
505 return result;
506 }
507
Curl_conn_cf_get_socket(struct Curl_cfilter * cf,struct Curl_easy * data)508 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
509 struct Curl_easy *data)
510 {
511 curl_socket_t sock;
512 if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
513 return sock;
514 return CURL_SOCKET_BAD;
515 }
516
Curl_conn_get_socket(struct Curl_easy * data,int sockindex)517 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
518 {
519 struct Curl_cfilter *cf;
520
521 cf = data->conn? data->conn->cfilter[sockindex] : NULL;
522 /* if the top filter has not connected, ask it (and its sub-filters)
523 * for the socket. Otherwise conn->sock[sockindex] should have it.
524 */
525 if(cf && !cf->connected)
526 return Curl_conn_cf_get_socket(cf, data);
527 return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
528 }
529
Curl_conn_forget_socket(struct Curl_easy * data,int sockindex)530 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
531 {
532 if(data->conn) {
533 struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
534 if(cf)
535 (void)Curl_conn_cf_cntrl(cf, data, TRUE,
536 CF_CTRL_FORGET_SOCKET, 0, NULL);
537 fake_sclose(data->conn->sock[sockindex]);
538 data->conn->sock[sockindex] = CURL_SOCKET_BAD;
539 }
540 }
541
cf_cntrl_all(struct connectdata * conn,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)542 static CURLcode cf_cntrl_all(struct connectdata *conn,
543 struct Curl_easy *data,
544 bool ignore_result,
545 int event, int arg1, void *arg2)
546 {
547 CURLcode result = CURLE_OK;
548 size_t i;
549
550 for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
551 result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
552 event, arg1, arg2);
553 if(!ignore_result && result)
554 break;
555 }
556 return result;
557 }
558
Curl_conn_ev_data_attach(struct connectdata * conn,struct Curl_easy * data)559 void Curl_conn_ev_data_attach(struct connectdata *conn,
560 struct Curl_easy *data)
561 {
562 cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
563 }
564
Curl_conn_ev_data_detach(struct connectdata * conn,struct Curl_easy * data)565 void Curl_conn_ev_data_detach(struct connectdata *conn,
566 struct Curl_easy *data)
567 {
568 cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
569 }
570
Curl_conn_ev_data_setup(struct Curl_easy * data)571 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
572 {
573 return cf_cntrl_all(data->conn, data, FALSE,
574 CF_CTRL_DATA_SETUP, 0, NULL);
575 }
576
Curl_conn_ev_data_idle(struct Curl_easy * data)577 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
578 {
579 return cf_cntrl_all(data->conn, data, FALSE,
580 CF_CTRL_DATA_IDLE, 0, NULL);
581 }
582
583 /**
584 * Notify connection filters that the transfer represented by `data`
585 * is donw with sending data (e.g. has uploaded everything).
586 */
Curl_conn_ev_data_done_send(struct Curl_easy * data)587 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
588 {
589 cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
590 }
591
592 /**
593 * Notify connection filters that the transfer represented by `data`
594 * is finished - eventually premature, e.g. before being complete.
595 */
Curl_conn_ev_data_done(struct Curl_easy * data,bool premature)596 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
597 {
598 cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
599 }
600
Curl_conn_ev_data_pause(struct Curl_easy * data,bool do_pause)601 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
602 {
603 return cf_cntrl_all(data->conn, data, FALSE,
604 CF_CTRL_DATA_PAUSE, do_pause, NULL);
605 }
606
Curl_conn_ev_update_info(struct Curl_easy * data,struct connectdata * conn)607 void Curl_conn_ev_update_info(struct Curl_easy *data,
608 struct connectdata *conn)
609 {
610 cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
611 }
612
613 /**
614 * Update connection statistics
615 */
conn_report_connect_stats(struct Curl_easy * data,struct connectdata * conn)616 static void conn_report_connect_stats(struct Curl_easy *data,
617 struct connectdata *conn)
618 {
619 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
620 if(cf) {
621 struct curltime connected;
622 struct curltime appconnected;
623
624 memset(&connected, 0, sizeof(connected));
625 cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
626 if(connected.tv_sec || connected.tv_usec)
627 Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
628
629 memset(&appconnected, 0, sizeof(appconnected));
630 cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
631 if(appconnected.tv_sec || appconnected.tv_usec)
632 Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
633 }
634 }
635
Curl_conn_is_alive(struct Curl_easy * data,struct connectdata * conn,bool * input_pending)636 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
637 bool *input_pending)
638 {
639 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
640 return cf && !cf->conn->bits.close &&
641 cf->cft->is_alive(cf, data, input_pending);
642 }
643
Curl_conn_keep_alive(struct Curl_easy * data,struct connectdata * conn,int sockindex)644 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
645 struct connectdata *conn,
646 int sockindex)
647 {
648 struct Curl_cfilter *cf = conn->cfilter[sockindex];
649 return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
650 }
651
Curl_conn_get_max_concurrent(struct Curl_easy * data,struct connectdata * conn,int sockindex)652 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
653 struct connectdata *conn,
654 int sockindex)
655 {
656 CURLcode result;
657 int n = 0;
658
659 struct Curl_cfilter *cf = conn->cfilter[sockindex];
660 result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
661 &n, NULL) : CURLE_UNKNOWN_OPTION;
662 return (result || n <= 0)? 1 : (size_t)n;
663 }
664
665
Curl_pollset_reset(struct Curl_easy * data,struct easy_pollset * ps)666 void Curl_pollset_reset(struct Curl_easy *data,
667 struct easy_pollset *ps)
668 {
669 size_t i;
670 (void)data;
671 memset(ps, 0, sizeof(*ps));
672 for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
673 ps->sockets[i] = CURL_SOCKET_BAD;
674 }
675
676 /**
677 *
678 */
Curl_pollset_change(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,int add_flags,int remove_flags)679 void Curl_pollset_change(struct Curl_easy *data,
680 struct easy_pollset *ps, curl_socket_t sock,
681 int add_flags, int remove_flags)
682 {
683 unsigned int i;
684
685 (void)data;
686 DEBUGASSERT(VALID_SOCK(sock));
687 if(!VALID_SOCK(sock))
688 return;
689
690 DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
691 DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
692 DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
693 for(i = 0; i < ps->num; ++i) {
694 if(ps->sockets[i] == sock) {
695 ps->actions[i] &= (unsigned char)(~remove_flags);
696 ps->actions[i] |= (unsigned char)add_flags;
697 /* all gone? remove socket */
698 if(!ps->actions[i]) {
699 if((i + 1) < ps->num) {
700 memmove(&ps->sockets[i], &ps->sockets[i + 1],
701 (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
702 memmove(&ps->actions[i], &ps->actions[i + 1],
703 (ps->num - (i + 1)) * sizeof(ps->actions[0]));
704 }
705 --ps->num;
706 }
707 return;
708 }
709 }
710 /* not present */
711 if(add_flags) {
712 /* Having more SOCKETS per easy handle than what is defined
713 * is a programming error. This indicates that we need
714 * to raise this limit, making easy_pollset larger.
715 * Since we use this in tight loops, we do not want to make
716 * the pollset dynamic unnecessarily.
717 * The current maximum in practise is HTTP/3 eyeballing where
718 * we have up to 4 sockets involved in connection setup.
719 */
720 DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
721 if(i < MAX_SOCKSPEREASYHANDLE) {
722 ps->sockets[i] = sock;
723 ps->actions[i] = (unsigned char)add_flags;
724 ps->num = i + 1;
725 }
726 }
727 }
728
Curl_pollset_set(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool do_in,bool do_out)729 void Curl_pollset_set(struct Curl_easy *data,
730 struct easy_pollset *ps, curl_socket_t sock,
731 bool do_in, bool do_out)
732 {
733 Curl_pollset_change(data, ps, sock,
734 (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
735 (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
736 }
737
ps_add(struct Curl_easy * data,struct easy_pollset * ps,int bitmap,curl_socket_t * socks)738 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
739 int bitmap, curl_socket_t *socks)
740 {
741 if(bitmap) {
742 int i;
743 for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
744 if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
745 break;
746 }
747 if(bitmap & GETSOCK_READSOCK(i)) {
748 if(bitmap & GETSOCK_WRITESOCK(i))
749 Curl_pollset_add_inout(data, ps, socks[i]);
750 else
751 /* is READ, since we checked MASK_RW above */
752 Curl_pollset_add_in(data, ps, socks[i]);
753 }
754 else
755 Curl_pollset_add_out(data, ps, socks[i]);
756 }
757 }
758 }
759
Curl_pollset_add_socks(struct Curl_easy * data,struct easy_pollset * ps,int (* get_socks_cb)(struct Curl_easy * data,curl_socket_t * socks))760 void Curl_pollset_add_socks(struct Curl_easy *data,
761 struct easy_pollset *ps,
762 int (*get_socks_cb)(struct Curl_easy *data,
763 curl_socket_t *socks))
764 {
765 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
766 int bitmap;
767
768 bitmap = get_socks_cb(data, socks);
769 ps_add(data, ps, bitmap, socks);
770 }
771
Curl_pollset_check(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool * pwant_read,bool * pwant_write)772 void Curl_pollset_check(struct Curl_easy *data,
773 struct easy_pollset *ps, curl_socket_t sock,
774 bool *pwant_read, bool *pwant_write)
775 {
776 unsigned int i;
777
778 (void)data;
779 DEBUGASSERT(VALID_SOCK(sock));
780 for(i = 0; i < ps->num; ++i) {
781 if(ps->sockets[i] == sock) {
782 *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
783 *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
784 return;
785 }
786 }
787 *pwant_read = *pwant_write = FALSE;
788 }
789