VirtualBox

source: vbox/trunk/src/libs/curl-8.11.1/lib/cfilters.c

Last change on this file was 108048, checked in by vboxsync, 3 months ago

curl-8.11.1: Applied and adjusted our curl changes to 8.7.1. jiraref:VBP-1535

  • Property svn:eol-style set to native
File size: 28.1 KB
Line 
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
48static void cf_cntrl_update_info(struct Curl_easy *data,
49 struct connectdata *conn);
50
51#ifdef UNITTESTS
52/* used by unit2600.c */
53void 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
61CURLcode 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
70static void conn_report_connect_stats(struct Curl_easy *data,
71 struct connectdata *conn);
72
73void 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
86void 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
96bool 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
103ssize_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
112ssize_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
120bool 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
129CURLcode 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
137CURLcode 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
146void 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
166void 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
172void 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
185CURLcode 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
240ssize_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
263ssize_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
288CURLcode 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;
303out:
304 *pcf = cf;
305 return result;
306}
307
308void 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
325void 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
345bool 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
372CURLcode 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
381void 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
387ssize_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
397ssize_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
406CURLcode 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
451bool 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
459bool 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
474bool 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
485bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
486{
487 return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
488}
489
490bool 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
504bool 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
522bool 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
532bool 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
537void 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
555void 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
567int 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
603void 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
625CURLcode 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
637CURLcode 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
654curl_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
663CURLcode 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
672curl_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
685void 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
697static 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
714void 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
720void 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
726CURLcode 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
732CURLcode 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
739CURLcode 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 */
749void 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 */
758void 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
763CURLcode 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
769static 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 */
778static 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
798bool 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
806CURLcode 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
814size_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
827int 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
840int 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
848CURLcode 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
862CURLcode 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
897void 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 */
910void 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
960void 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
971static 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
993void 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
1005void 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}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette