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->primary.remote_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_cf_recv(struct Curl_easy * data,int num,char * buf,size_t len,CURLcode * code)171 ssize_t Curl_cf_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 *code = CURLE_OK;
179 cf = data->conn->cfilter[num];
180 while(cf && !cf->connected) {
181 cf = cf->next;
182 }
183 if(cf) {
184 ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
185 DEBUGASSERT(nread >= 0 || *code);
186 DEBUGASSERT(nread < 0 || !*code);
187 return nread;
188 }
189 failf(data, "recv: no filter connected");
190 *code = CURLE_FAILED_INIT;
191 return -1;
192 }
193
Curl_cf_send(struct Curl_easy * data,int num,const void * mem,size_t len,CURLcode * code)194 ssize_t Curl_cf_send(struct Curl_easy *data, int num,
195 const void *mem, size_t len, CURLcode *code)
196 {
197 struct Curl_cfilter *cf;
198
199 DEBUGASSERT(data);
200 DEBUGASSERT(data->conn);
201 *code = CURLE_OK;
202 cf = data->conn->cfilter[num];
203 while(cf && !cf->connected) {
204 cf = cf->next;
205 }
206 if(cf) {
207 ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
208 DEBUGASSERT(nwritten >= 0 || *code);
209 DEBUGASSERT(nwritten < 0 || !*code || !len);
210 return nwritten;
211 }
212 failf(data, "send: no filter connected");
213 DEBUGASSERT(0);
214 *code = CURLE_FAILED_INIT;
215 return -1;
216 }
217
Curl_cf_create(struct Curl_cfilter ** pcf,const struct Curl_cftype * cft,void * ctx)218 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
219 const struct Curl_cftype *cft,
220 void *ctx)
221 {
222 struct Curl_cfilter *cf;
223 CURLcode result = CURLE_OUT_OF_MEMORY;
224
225 DEBUGASSERT(cft);
226 cf = calloc(1, sizeof(*cf));
227 if(!cf)
228 goto out;
229
230 cf->cft = cft;
231 cf->ctx = ctx;
232 result = CURLE_OK;
233 out:
234 *pcf = cf;
235 return result;
236 }
237
Curl_conn_cf_add(struct Curl_easy * data,struct connectdata * conn,int index,struct Curl_cfilter * cf)238 void Curl_conn_cf_add(struct Curl_easy *data,
239 struct connectdata *conn,
240 int index,
241 struct Curl_cfilter *cf)
242 {
243 (void)data;
244 DEBUGASSERT(conn);
245 DEBUGASSERT(!cf->conn);
246 DEBUGASSERT(!cf->next);
247
248 cf->next = conn->cfilter[index];
249 cf->conn = conn;
250 cf->sockindex = index;
251 conn->cfilter[index] = cf;
252 CURL_TRC_CF(data, cf, "added");
253 }
254
Curl_conn_cf_insert_after(struct Curl_cfilter * cf_at,struct Curl_cfilter * cf_new)255 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
256 struct Curl_cfilter *cf_new)
257 {
258 struct Curl_cfilter *tail, **pnext;
259
260 DEBUGASSERT(cf_at);
261 DEBUGASSERT(cf_new);
262 DEBUGASSERT(!cf_new->conn);
263
264 tail = cf_at->next;
265 cf_at->next = cf_new;
266 do {
267 cf_new->conn = cf_at->conn;
268 cf_new->sockindex = cf_at->sockindex;
269 pnext = &cf_new->next;
270 cf_new = cf_new->next;
271 } while(cf_new);
272 *pnext = tail;
273 }
274
Curl_conn_cf_discard_sub(struct Curl_cfilter * cf,struct Curl_cfilter * discard,struct Curl_easy * data,bool destroy_always)275 bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
276 struct Curl_cfilter *discard,
277 struct Curl_easy *data,
278 bool destroy_always)
279 {
280 struct Curl_cfilter **pprev = &cf->next;
281 bool found = FALSE;
282
283 /* remove from sub-chain and destroy */
284 DEBUGASSERT(cf);
285 while(*pprev) {
286 if(*pprev == cf) {
287 *pprev = discard->next;
288 discard->next = NULL;
289 found = TRUE;
290 break;
291 }
292 pprev = &((*pprev)->next);
293 }
294 if(found || destroy_always) {
295 discard->next = NULL;
296 discard->cft->destroy(discard, data);
297 free(discard);
298 }
299 return found;
300 }
301
Curl_conn_cf_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)302 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
303 struct Curl_easy *data,
304 bool blocking, bool *done)
305 {
306 if(cf)
307 return cf->cft->do_connect(cf, data, blocking, done);
308 return CURLE_FAILED_INIT;
309 }
310
Curl_conn_cf_close(struct Curl_cfilter * cf,struct Curl_easy * data)311 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
312 {
313 if(cf)
314 cf->cft->do_close(cf, data);
315 }
316
Curl_conn_cf_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)317 ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
318 const void *buf, size_t len, CURLcode *err)
319 {
320 if(cf)
321 return cf->cft->do_send(cf, data, buf, len, err);
322 *err = CURLE_SEND_ERROR;
323 return -1;
324 }
325
Curl_conn_cf_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)326 ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
327 char *buf, size_t len, CURLcode *err)
328 {
329 if(cf)
330 return cf->cft->do_recv(cf, data, buf, len, err);
331 *err = CURLE_RECV_ERROR;
332 return -1;
333 }
334
Curl_conn_connect(struct Curl_easy * data,int sockindex,bool blocking,bool * done)335 CURLcode Curl_conn_connect(struct Curl_easy *data,
336 int sockindex,
337 bool blocking,
338 bool *done)
339 {
340 struct Curl_cfilter *cf;
341 CURLcode result = CURLE_OK;
342
343 DEBUGASSERT(data);
344 DEBUGASSERT(data->conn);
345
346 cf = data->conn->cfilter[sockindex];
347 DEBUGASSERT(cf);
348 if(!cf)
349 return CURLE_FAILED_INIT;
350
351 *done = cf->connected;
352 if(!*done) {
353 result = cf->cft->do_connect(cf, data, blocking, done);
354 if(!result && *done) {
355 Curl_conn_ev_update_info(data, data->conn);
356 conn_report_connect_stats(data, data->conn);
357 data->conn->keepalive = Curl_now();
358 }
359 else if(result) {
360 conn_report_connect_stats(data, data->conn);
361 }
362 }
363
364 return result;
365 }
366
Curl_conn_is_connected(struct connectdata * conn,int sockindex)367 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
368 {
369 struct Curl_cfilter *cf;
370
371 cf = conn->cfilter[sockindex];
372 return cf && cf->connected;
373 }
374
Curl_conn_is_ip_connected(struct Curl_easy * data,int sockindex)375 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
376 {
377 struct Curl_cfilter *cf;
378
379 cf = data->conn->cfilter[sockindex];
380 while(cf) {
381 if(cf->connected)
382 return TRUE;
383 if(cf->cft->flags & CF_TYPE_IP_CONNECT)
384 return FALSE;
385 cf = cf->next;
386 }
387 return FALSE;
388 }
389
Curl_conn_cf_is_ssl(struct Curl_cfilter * cf)390 bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf)
391 {
392 for(; cf; cf = cf->next) {
393 if(cf->cft->flags & CF_TYPE_SSL)
394 return TRUE;
395 if(cf->cft->flags & CF_TYPE_IP_CONNECT)
396 return FALSE;
397 }
398 return FALSE;
399 }
400
Curl_conn_is_ssl(struct connectdata * conn,int sockindex)401 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
402 {
403 return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
404 }
405
Curl_conn_is_multiplex(struct connectdata * conn,int sockindex)406 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
407 {
408 struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
409
410 for(; cf; cf = cf->next) {
411 if(cf->cft->flags & CF_TYPE_MULTIPLEX)
412 return TRUE;
413 if(cf->cft->flags & CF_TYPE_IP_CONNECT
414 || cf->cft->flags & CF_TYPE_SSL)
415 return FALSE;
416 }
417 return FALSE;
418 }
419
Curl_conn_data_pending(struct Curl_easy * data,int sockindex)420 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
421 {
422 struct Curl_cfilter *cf;
423
424 (void)data;
425 DEBUGASSERT(data);
426 DEBUGASSERT(data->conn);
427
428 cf = data->conn->cfilter[sockindex];
429 while(cf && !cf->connected) {
430 cf = cf->next;
431 }
432 if(cf) {
433 return cf->cft->has_data_pending(cf, data);
434 }
435 return FALSE;
436 }
437
Curl_conn_cf_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)438 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
439 struct Curl_easy *data,
440 struct easy_pollset *ps)
441 {
442 /* Get the lowest not-connected filter, if there are any */
443 while(cf && !cf->connected && cf->next && !cf->next->connected)
444 cf = cf->next;
445 /* From there on, give all filters a chance to adjust the pollset.
446 * Lower filters are called later, so they may override */
447 while(cf) {
448 cf->cft->adjust_pollset(cf, data, ps);
449 cf = cf->next;
450 }
451 }
452
Curl_conn_adjust_pollset(struct Curl_easy * data,struct easy_pollset * ps)453 void Curl_conn_adjust_pollset(struct Curl_easy *data,
454 struct easy_pollset *ps)
455 {
456 int i;
457
458 DEBUGASSERT(data);
459 DEBUGASSERT(data->conn);
460 for(i = 0; i < 2; ++i) {
461 Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
462 }
463 }
464
Curl_conn_get_host(struct Curl_easy * data,int sockindex,const char ** phost,const char ** pdisplay_host,int * pport)465 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
466 const char **phost, const char **pdisplay_host,
467 int *pport)
468 {
469 struct Curl_cfilter *cf;
470
471 DEBUGASSERT(data->conn);
472 cf = data->conn->cfilter[sockindex];
473 if(cf) {
474 cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
475 }
476 else {
477 /* Some filter ask during shutdown for this, mainly for debugging
478 * purposes. We hand out the defaults, however this is not always
479 * accurate, as the connection might be tunneled, etc. But all that
480 * state is already gone here. */
481 *phost = data->conn->host.name;
482 *pdisplay_host = data->conn->host.dispname;
483 *pport = data->conn->remote_port;
484 }
485 }
486
Curl_cf_def_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)487 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
488 struct Curl_easy *data,
489 int event, int arg1, void *arg2)
490 {
491 (void)cf;
492 (void)data;
493 (void)event;
494 (void)arg1;
495 (void)arg2;
496 return CURLE_OK;
497 }
498
Curl_conn_cf_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)499 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
500 struct Curl_easy *data,
501 bool ignore_result,
502 int event, int arg1, void *arg2)
503 {
504 CURLcode result = CURLE_OK;
505
506 for(; cf; cf = cf->next) {
507 if(Curl_cf_def_cntrl == cf->cft->cntrl)
508 continue;
509 result = cf->cft->cntrl(cf, data, event, arg1, arg2);
510 if(!ignore_result && result)
511 break;
512 }
513 return result;
514 }
515
Curl_conn_cf_get_socket(struct Curl_cfilter * cf,struct Curl_easy * data)516 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
517 struct Curl_easy *data)
518 {
519 curl_socket_t sock;
520 if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
521 return sock;
522 return CURL_SOCKET_BAD;
523 }
524
Curl_conn_get_socket(struct Curl_easy * data,int sockindex)525 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
526 {
527 struct Curl_cfilter *cf;
528
529 cf = data->conn? data->conn->cfilter[sockindex] : NULL;
530 /* if the top filter has not connected, ask it (and its sub-filters)
531 * for the socket. Otherwise conn->sock[sockindex] should have it.
532 */
533 if(cf && !cf->connected)
534 return Curl_conn_cf_get_socket(cf, data);
535 return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
536 }
537
Curl_conn_forget_socket(struct Curl_easy * data,int sockindex)538 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
539 {
540 if(data->conn) {
541 struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
542 if(cf)
543 (void)Curl_conn_cf_cntrl(cf, data, TRUE,
544 CF_CTRL_FORGET_SOCKET, 0, NULL);
545 fake_sclose(data->conn->sock[sockindex]);
546 data->conn->sock[sockindex] = CURL_SOCKET_BAD;
547 }
548 }
549
cf_cntrl_all(struct connectdata * conn,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)550 static CURLcode cf_cntrl_all(struct connectdata *conn,
551 struct Curl_easy *data,
552 bool ignore_result,
553 int event, int arg1, void *arg2)
554 {
555 CURLcode result = CURLE_OK;
556 size_t i;
557
558 for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
559 result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
560 event, arg1, arg2);
561 if(!ignore_result && result)
562 break;
563 }
564 return result;
565 }
566
Curl_conn_ev_data_attach(struct connectdata * conn,struct Curl_easy * data)567 void Curl_conn_ev_data_attach(struct connectdata *conn,
568 struct Curl_easy *data)
569 {
570 cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
571 }
572
Curl_conn_ev_data_detach(struct connectdata * conn,struct Curl_easy * data)573 void Curl_conn_ev_data_detach(struct connectdata *conn,
574 struct Curl_easy *data)
575 {
576 cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
577 }
578
Curl_conn_ev_data_setup(struct Curl_easy * data)579 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
580 {
581 return cf_cntrl_all(data->conn, data, FALSE,
582 CF_CTRL_DATA_SETUP, 0, NULL);
583 }
584
Curl_conn_ev_data_idle(struct Curl_easy * data)585 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
586 {
587 return cf_cntrl_all(data->conn, data, FALSE,
588 CF_CTRL_DATA_IDLE, 0, NULL);
589 }
590
591 /**
592 * Notify connection filters that the transfer represented by `data`
593 * is done with sending data (e.g. has uploaded everything).
594 */
Curl_conn_ev_data_done_send(struct Curl_easy * data)595 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
596 {
597 cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
598 }
599
600 /**
601 * Notify connection filters that the transfer represented by `data`
602 * is finished - eventually premature, e.g. before being complete.
603 */
Curl_conn_ev_data_done(struct Curl_easy * data,bool premature)604 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
605 {
606 cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
607 }
608
Curl_conn_ev_data_pause(struct Curl_easy * data,bool do_pause)609 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
610 {
611 return cf_cntrl_all(data->conn, data, FALSE,
612 CF_CTRL_DATA_PAUSE, do_pause, NULL);
613 }
614
Curl_conn_ev_update_info(struct Curl_easy * data,struct connectdata * conn)615 void Curl_conn_ev_update_info(struct Curl_easy *data,
616 struct connectdata *conn)
617 {
618 cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
619 }
620
621 /**
622 * Update connection statistics
623 */
conn_report_connect_stats(struct Curl_easy * data,struct connectdata * conn)624 static void conn_report_connect_stats(struct Curl_easy *data,
625 struct connectdata *conn)
626 {
627 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
628 if(cf) {
629 struct curltime connected;
630 struct curltime appconnected;
631
632 memset(&connected, 0, sizeof(connected));
633 cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
634 if(connected.tv_sec || connected.tv_usec)
635 Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
636
637 memset(&appconnected, 0, sizeof(appconnected));
638 cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
639 if(appconnected.tv_sec || appconnected.tv_usec)
640 Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
641 }
642 }
643
Curl_conn_is_alive(struct Curl_easy * data,struct connectdata * conn,bool * input_pending)644 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
645 bool *input_pending)
646 {
647 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
648 return cf && !cf->conn->bits.close &&
649 cf->cft->is_alive(cf, data, input_pending);
650 }
651
Curl_conn_keep_alive(struct Curl_easy * data,struct connectdata * conn,int sockindex)652 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
653 struct connectdata *conn,
654 int sockindex)
655 {
656 struct Curl_cfilter *cf = conn->cfilter[sockindex];
657 return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
658 }
659
Curl_conn_get_max_concurrent(struct Curl_easy * data,struct connectdata * conn,int sockindex)660 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
661 struct connectdata *conn,
662 int sockindex)
663 {
664 CURLcode result;
665 int n = 0;
666
667 struct Curl_cfilter *cf = conn->cfilter[sockindex];
668 result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
669 &n, NULL) : CURLE_UNKNOWN_OPTION;
670 return (result || n <= 0)? 1 : (size_t)n;
671 }
672
Curl_conn_get_stream_error(struct Curl_easy * data,struct connectdata * conn,int sockindex)673 int Curl_conn_get_stream_error(struct Curl_easy *data,
674 struct connectdata *conn,
675 int sockindex)
676 {
677 CURLcode result;
678 int n = 0;
679
680 struct Curl_cfilter *cf = conn->cfilter[sockindex];
681 result = cf? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
682 &n, NULL) : CURLE_UNKNOWN_OPTION;
683 return (result || n < 0)? 0 : n;
684 }
685
Curl_conn_sockindex(struct Curl_easy * data,curl_socket_t sockfd)686 int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
687 {
688 if(data && data->conn &&
689 sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
690 return SECONDARYSOCKET;
691 return FIRSTSOCKET;
692 }
693
Curl_conn_recv(struct Curl_easy * data,int sockindex,char * buf,size_t blen,ssize_t * n)694 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
695 char *buf, size_t blen, ssize_t *n)
696 {
697 CURLcode result = CURLE_OK;
698 ssize_t nread;
699
700 DEBUGASSERT(data->conn);
701 nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
702 DEBUGASSERT(nread >= 0 || result);
703 DEBUGASSERT(nread < 0 || !result);
704 *n = (nread >= 0)? (size_t)nread : 0;
705 return result;
706 }
707
Curl_conn_send(struct Curl_easy * data,int sockindex,const void * buf,size_t blen,size_t * pnwritten)708 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
709 const void *buf, size_t blen,
710 size_t *pnwritten)
711 {
712 ssize_t nwritten;
713 CURLcode result = CURLE_OK;
714 struct connectdata *conn;
715
716 DEBUGASSERT(sockindex >= 0 && sockindex < 2);
717 DEBUGASSERT(pnwritten);
718 DEBUGASSERT(data);
719 DEBUGASSERT(data->conn);
720 conn = data->conn;
721 #ifdef CURLDEBUG
722 {
723 /* Allow debug builds to override this logic to force short sends
724 */
725 char *p = getenv("CURL_SMALLSENDS");
726 if(p) {
727 size_t altsize = (size_t)strtoul(p, NULL, 10);
728 if(altsize)
729 blen = CURLMIN(blen, altsize);
730 }
731 }
732 #endif
733 nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
734 DEBUGASSERT((nwritten >= 0) || result);
735 *pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
736 return result;
737 }
738
Curl_pollset_reset(struct Curl_easy * data,struct easy_pollset * ps)739 void Curl_pollset_reset(struct Curl_easy *data,
740 struct easy_pollset *ps)
741 {
742 size_t i;
743 (void)data;
744 memset(ps, 0, sizeof(*ps));
745 for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
746 ps->sockets[i] = CURL_SOCKET_BAD;
747 }
748
749 /**
750 *
751 */
Curl_pollset_change(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,int add_flags,int remove_flags)752 void Curl_pollset_change(struct Curl_easy *data,
753 struct easy_pollset *ps, curl_socket_t sock,
754 int add_flags, int remove_flags)
755 {
756 unsigned int i;
757
758 (void)data;
759 DEBUGASSERT(VALID_SOCK(sock));
760 if(!VALID_SOCK(sock))
761 return;
762
763 DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
764 DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
765 DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
766 for(i = 0; i < ps->num; ++i) {
767 if(ps->sockets[i] == sock) {
768 ps->actions[i] &= (unsigned char)(~remove_flags);
769 ps->actions[i] |= (unsigned char)add_flags;
770 /* all gone? remove socket */
771 if(!ps->actions[i]) {
772 if((i + 1) < ps->num) {
773 memmove(&ps->sockets[i], &ps->sockets[i + 1],
774 (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
775 memmove(&ps->actions[i], &ps->actions[i + 1],
776 (ps->num - (i + 1)) * sizeof(ps->actions[0]));
777 }
778 --ps->num;
779 }
780 return;
781 }
782 }
783 /* not present */
784 if(add_flags) {
785 /* Having more SOCKETS per easy handle than what is defined
786 * is a programming error. This indicates that we need
787 * to raise this limit, making easy_pollset larger.
788 * Since we use this in tight loops, we do not want to make
789 * the pollset dynamic unnecessarily.
790 * The current maximum in practise is HTTP/3 eyeballing where
791 * we have up to 4 sockets involved in connection setup.
792 */
793 DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
794 if(i < MAX_SOCKSPEREASYHANDLE) {
795 ps->sockets[i] = sock;
796 ps->actions[i] = (unsigned char)add_flags;
797 ps->num = i + 1;
798 }
799 }
800 }
801
Curl_pollset_set(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool do_in,bool do_out)802 void Curl_pollset_set(struct Curl_easy *data,
803 struct easy_pollset *ps, curl_socket_t sock,
804 bool do_in, bool do_out)
805 {
806 Curl_pollset_change(data, ps, sock,
807 (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
808 (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
809 }
810
ps_add(struct Curl_easy * data,struct easy_pollset * ps,int bitmap,curl_socket_t * socks)811 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
812 int bitmap, curl_socket_t *socks)
813 {
814 if(bitmap) {
815 int i;
816 for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
817 if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
818 break;
819 }
820 if(bitmap & GETSOCK_READSOCK(i)) {
821 if(bitmap & GETSOCK_WRITESOCK(i))
822 Curl_pollset_add_inout(data, ps, socks[i]);
823 else
824 /* is READ, since we checked MASK_RW above */
825 Curl_pollset_add_in(data, ps, socks[i]);
826 }
827 else
828 Curl_pollset_add_out(data, ps, socks[i]);
829 }
830 }
831 }
832
Curl_pollset_add_socks(struct Curl_easy * data,struct easy_pollset * ps,int (* get_socks_cb)(struct Curl_easy * data,curl_socket_t * socks))833 void Curl_pollset_add_socks(struct Curl_easy *data,
834 struct easy_pollset *ps,
835 int (*get_socks_cb)(struct Curl_easy *data,
836 curl_socket_t *socks))
837 {
838 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
839 int bitmap;
840
841 bitmap = get_socks_cb(data, socks);
842 ps_add(data, ps, bitmap, socks);
843 }
844
Curl_pollset_check(struct Curl_easy * data,struct easy_pollset * ps,curl_socket_t sock,bool * pwant_read,bool * pwant_write)845 void Curl_pollset_check(struct Curl_easy *data,
846 struct easy_pollset *ps, curl_socket_t sock,
847 bool *pwant_read, bool *pwant_write)
848 {
849 unsigned int i;
850
851 (void)data;
852 DEBUGASSERT(VALID_SOCK(sock));
853 for(i = 0; i < ps->num; ++i) {
854 if(ps->sockets[i] == sock) {
855 *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
856 *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
857 return;
858 }
859 }
860 *pwant_read = *pwant_write = FALSE;
861 }
862