• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "warnless.h"
37 
38 /* The last 3 #include files should be in this order */
39 #include "curl_printf.h"
40 #include "curl_memory.h"
41 #include "memdebug.h"
42 
43 #ifndef ARRAYSIZE
44 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
45 #endif
46 
47 
Curl_cf_def_destroy_this(struct Curl_cfilter * cf,struct Curl_easy * data)48 void Curl_cf_def_destroy_this(struct Curl_cfilter *cf, struct Curl_easy *data)
49 {
50   (void)cf;
51   (void)data;
52 }
53 
Curl_cf_def_close(struct Curl_cfilter * cf,struct Curl_easy * data)54 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
55 {
56   cf->connected = FALSE;
57   if(cf->next)
58     cf->next->cft->close(cf->next, data);
59 }
60 
Curl_cf_def_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)61 CURLcode Curl_cf_def_connect(struct Curl_cfilter *cf,
62                              struct Curl_easy *data,
63                              bool blocking, bool *done)
64 {
65   CURLcode result;
66 
67   if(cf->connected) {
68     *done = TRUE;
69     return CURLE_OK;
70   }
71   if(cf->next) {
72     result = cf->next->cft->connect(cf->next, data, blocking, done);
73     if(!result && *done) {
74       cf->connected = TRUE;
75     }
76     return result;
77   }
78   *done = FALSE;
79   return CURLE_FAILED_INIT;
80 }
81 
Curl_cf_def_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)82 void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
83                           const char **phost, const char **pdisplay_host,
84                           int *pport)
85 {
86   if(cf->next)
87     cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
88   else {
89     *phost = cf->conn->host.name;
90     *pdisplay_host = cf->conn->host.dispname;
91     *pport = cf->conn->port;
92   }
93 }
94 
Curl_cf_def_get_select_socks(struct Curl_cfilter * cf,struct Curl_easy * data,curl_socket_t * socks)95 int Curl_cf_def_get_select_socks(struct Curl_cfilter *cf,
96                                  struct Curl_easy *data,
97                                  curl_socket_t *socks)
98 {
99   return cf->next?
100     cf->next->cft->get_select_socks(cf->next, data, socks) : 0;
101 }
102 
Curl_cf_def_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)103 bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
104                               const struct Curl_easy *data)
105 {
106   return cf->next?
107     cf->next->cft->has_data_pending(cf->next, data) : FALSE;
108 }
109 
Curl_cf_def_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)110 ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
111                           const void *buf, size_t len, CURLcode *err)
112 {
113   return cf->next?
114     cf->next->cft->do_send(cf->next, data, buf, len, err) :
115     CURLE_RECV_ERROR;
116 }
117 
Curl_cf_def_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)118 ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
119                           char *buf, size_t len, CURLcode *err)
120 {
121   return cf->next?
122     cf->next->cft->do_recv(cf->next, data, buf, len, err) :
123     CURLE_SEND_ERROR;
124 }
125 
Curl_cf_def_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)126 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
127                                struct Curl_easy *data,
128                                bool *input_pending)
129 {
130   return cf->next?
131     cf->next->cft->is_alive(cf->next, data, input_pending) :
132     FALSE; /* pessimistic in absence of data */
133 }
134 
Curl_cf_def_conn_keep_alive(struct Curl_cfilter * cf,struct Curl_easy * data)135 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
136                                      struct Curl_easy *data)
137 {
138   return cf->next?
139     cf->next->cft->keep_alive(cf->next, data) :
140     CURLE_OK;
141 }
142 
Curl_cf_def_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)143 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
144                            struct Curl_easy *data,
145                            int query, int *pres1, void *pres2)
146 {
147   return cf->next?
148     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
149     CURLE_UNKNOWN_OPTION;
150 }
151 
Curl_conn_cf_discard_chain(struct Curl_cfilter ** pcf,struct Curl_easy * data)152 void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
153                                 struct Curl_easy *data)
154 {
155   struct Curl_cfilter *cfn, *cf = *pcf;
156 
157   if(cf) {
158     *pcf = NULL;
159     while(cf) {
160       cfn = cf->next;
161       /* prevent destroying filter to mess with its sub-chain, since
162        * we have the reference now and will call destroy on it.
163        */
164       cf->next = NULL;
165       cf->cft->destroy(cf, data);
166       free(cf);
167       cf = cfn;
168     }
169   }
170 }
171 
Curl_conn_cf_discard_all(struct Curl_easy * data,struct connectdata * conn,int index)172 void Curl_conn_cf_discard_all(struct Curl_easy *data,
173                               struct connectdata *conn, int index)
174 {
175   Curl_conn_cf_discard_chain(&conn->cfilter[index], data);
176 }
177 
Curl_conn_close(struct Curl_easy * data,int index)178 void Curl_conn_close(struct Curl_easy *data, int index)
179 {
180   struct Curl_cfilter *cf;
181 
182   DEBUGASSERT(data->conn);
183   /* it is valid to call that without filters being present */
184   cf = data->conn->cfilter[index];
185   if(cf) {
186     cf->cft->close(cf, data);
187   }
188 }
189 
Curl_conn_recv(struct Curl_easy * data,int num,char * buf,size_t len,CURLcode * code)190 ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
191                        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_recv(cf, data, buf, len, code);
203   }
204   failf(data, CMSGI(data->conn, num, "recv: no filter connected"));
205   *code = CURLE_FAILED_INIT;
206   return -1;
207 }
208 
Curl_conn_send(struct Curl_easy * data,int num,const void * mem,size_t len,CURLcode * code)209 ssize_t Curl_conn_send(struct Curl_easy *data, int num,
210                        const void *mem, size_t len, CURLcode *code)
211 {
212   struct Curl_cfilter *cf;
213 
214   DEBUGASSERT(data);
215   DEBUGASSERT(data->conn);
216   cf = data->conn->cfilter[num];
217   while(cf && !cf->connected) {
218     cf = cf->next;
219   }
220   if(cf) {
221     return cf->cft->do_send(cf, data, mem, len, code);
222   }
223   failf(data, CMSGI(data->conn, num, "send: no filter connected"));
224   DEBUGASSERT(0);
225   *code = CURLE_FAILED_INIT;
226   return -1;
227 }
228 
Curl_cf_create(struct Curl_cfilter ** pcf,const struct Curl_cftype * cft,void * ctx)229 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
230                         const struct Curl_cftype *cft,
231                         void *ctx)
232 {
233   struct Curl_cfilter *cf;
234   CURLcode result = CURLE_OUT_OF_MEMORY;
235 
236   DEBUGASSERT(cft);
237   cf = calloc(sizeof(*cf), 1);
238   if(!cf)
239     goto out;
240 
241   cf->cft = cft;
242   cf->ctx = ctx;
243   result = CURLE_OK;
244 out:
245   *pcf = cf;
246   return result;
247 }
248 
Curl_conn_cf_add(struct Curl_easy * data,struct connectdata * conn,int index,struct Curl_cfilter * cf)249 void Curl_conn_cf_add(struct Curl_easy *data,
250                       struct connectdata *conn,
251                       int index,
252                       struct Curl_cfilter *cf)
253 {
254   (void)data;
255   DEBUGASSERT(conn);
256   DEBUGASSERT(!cf->conn);
257   DEBUGASSERT(!cf->next);
258 
259   cf->next = conn->cfilter[index];
260   cf->conn = conn;
261   cf->sockindex = index;
262   conn->cfilter[index] = cf;
263   DEBUGF(LOG_CF(data, cf, "added"));
264 }
265 
Curl_conn_cf_insert_after(struct Curl_cfilter * cf_at,struct Curl_cfilter * cf_new)266 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
267                                struct Curl_cfilter *cf_new)
268 {
269   struct Curl_cfilter *tail, **pnext;
270 
271   DEBUGASSERT(cf_at);
272   DEBUGASSERT(cf_new);
273   DEBUGASSERT(!cf_new->conn);
274 
275   tail = cf_at->next;
276   cf_at->next = cf_new;
277   do {
278     cf_new->conn = cf_at->conn;
279     cf_new->sockindex = cf_at->sockindex;
280     pnext = &cf_new->next;
281     cf_new = cf_new->next;
282   } while(cf_new);
283   *pnext = tail;
284 }
285 
Curl_conn_cf_discard(struct Curl_cfilter * cf,struct Curl_easy * data)286 void Curl_conn_cf_discard(struct Curl_cfilter *cf, struct Curl_easy *data)
287 {
288   struct Curl_cfilter **pprev = &cf->conn->cfilter[cf->sockindex];
289 
290   /* remove from chain if still in there */
291   DEBUGASSERT(cf);
292   while (*pprev) {
293     if (*pprev == cf) {
294       *pprev = cf->next;
295       break;
296     }
297     pprev = &((*pprev)->next);
298   }
299   cf->cft->destroy(cf, data);
300   free(cf);
301 }
302 
Curl_conn_cf_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)303 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
304                               struct Curl_easy *data,
305                               bool blocking, bool *done)
306 {
307   if(cf)
308     return cf->cft->connect(cf, data, blocking, done);
309   return CURLE_FAILED_INIT;
310 }
311 
Curl_conn_cf_close(struct Curl_cfilter * cf,struct Curl_easy * data)312 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
313 {
314   if(cf)
315     cf->cft->close(cf, data);
316 }
317 
Curl_conn_cf_get_select_socks(struct Curl_cfilter * cf,struct Curl_easy * data,curl_socket_t * socks)318 int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
319                                   struct Curl_easy *data,
320                                   curl_socket_t *socks)
321 {
322   if(cf)
323     return cf->cft->get_select_socks(cf, data, socks);
324   return 0;
325 }
326 
Curl_conn_cf_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)327 bool Curl_conn_cf_data_pending(struct Curl_cfilter *cf,
328                                const struct Curl_easy *data)
329 {
330   if(cf)
331     return cf->cft->has_data_pending(cf, data);
332   return FALSE;
333 }
334 
Curl_conn_cf_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)335 ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
336                           const void *buf, size_t len, CURLcode *err)
337 {
338   if(cf)
339     return cf->cft->do_send(cf, data, buf, len, err);
340   *err = CURLE_SEND_ERROR;
341   return -1;
342 }
343 
Curl_conn_cf_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)344 ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
345                           char *buf, size_t len, CURLcode *err)
346 {
347   if(cf)
348     return cf->cft->do_recv(cf, data, buf, len, err);
349   *err = CURLE_RECV_ERROR;
350   return -1;
351 }
352 
Curl_conn_connect(struct Curl_easy * data,int sockindex,bool blocking,bool * done)353 CURLcode Curl_conn_connect(struct Curl_easy *data,
354                            int sockindex,
355                            bool blocking,
356                            bool *done)
357 {
358   struct Curl_cfilter *cf;
359   CURLcode result = CURLE_OK;
360 
361   DEBUGASSERT(data);
362   DEBUGASSERT(data->conn);
363 
364   cf = data->conn->cfilter[sockindex];
365   DEBUGASSERT(cf);
366   if(!cf)
367     return CURLE_FAILED_INIT;
368 
369   *done = cf->connected;
370   if(!*done) {
371     result = cf->cft->connect(cf, data, blocking, done);
372     if(!result && *done) {
373       Curl_conn_ev_update_info(data, data->conn);
374       Curl_conn_report_connect_stats(data, data->conn);
375       data->conn->keepalive = Curl_now();
376     }
377     else if(result) {
378       Curl_conn_report_connect_stats(data, data->conn);
379     }
380   }
381 
382   return result;
383 }
384 
Curl_conn_is_connected(struct connectdata * conn,int sockindex)385 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
386 {
387   struct Curl_cfilter *cf;
388 
389   cf = conn->cfilter[sockindex];
390   return cf && cf->connected;
391 }
392 
Curl_conn_is_ip_connected(struct Curl_easy * data,int sockindex)393 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
394 {
395   struct Curl_cfilter *cf;
396 
397   cf = data->conn->cfilter[sockindex];
398   while(cf) {
399     if(cf->connected)
400       return TRUE;
401     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
402       return FALSE;
403     cf = cf->next;
404   }
405   return FALSE;
406 }
407 
Curl_conn_is_ssl(struct connectdata * conn,int sockindex)408 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
409 {
410   struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
411 
412   for(; cf; cf = cf->next) {
413     if(cf->cft->flags & CF_TYPE_SSL)
414       return TRUE;
415     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
416       return FALSE;
417   }
418   return FALSE;
419 }
420 
Curl_conn_is_multiplex(struct connectdata * conn,int sockindex)421 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
422 {
423   struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
424 
425   for(; cf; cf = cf->next) {
426     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
427       return TRUE;
428     if(cf->cft->flags & CF_TYPE_IP_CONNECT
429        || cf->cft->flags & CF_TYPE_SSL)
430       return FALSE;
431   }
432   return FALSE;
433 }
434 
Curl_conn_data_pending(struct Curl_easy * data,int sockindex)435 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
436 {
437   struct Curl_cfilter *cf;
438 
439   (void)data;
440   DEBUGASSERT(data);
441   DEBUGASSERT(data->conn);
442 
443   cf = data->conn->cfilter[sockindex];
444   while(cf && !cf->connected) {
445     cf = cf->next;
446   }
447   if(cf) {
448     return cf->cft->has_data_pending(cf, data);
449   }
450   return FALSE;
451 }
452 
Curl_conn_get_select_socks(struct Curl_easy * data,int sockindex,curl_socket_t * socks)453 int Curl_conn_get_select_socks(struct Curl_easy *data, int sockindex,
454                                curl_socket_t *socks)
455 {
456   struct Curl_cfilter *cf;
457 
458   DEBUGASSERT(data);
459   DEBUGASSERT(data->conn);
460   cf = data->conn->cfilter[sockindex];
461 
462   /* if the next one is not yet connected, that's the one we want */
463   while(cf && cf->next && !cf->next->connected)
464     cf = cf->next;
465   if(cf) {
466     return cf->cft->get_select_socks(cf, data, socks);
467   }
468   return GETSOCK_BLANK;
469 }
470 
Curl_conn_get_host(struct Curl_easy * data,int sockindex,const char ** phost,const char ** pdisplay_host,int * pport)471 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
472                         const char **phost, const char **pdisplay_host,
473                         int *pport)
474 {
475   struct Curl_cfilter *cf;
476 
477   DEBUGASSERT(data->conn);
478   cf = data->conn->cfilter[sockindex];
479   if(cf) {
480     cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
481   }
482   else {
483     /* Some filter ask during shutdown for this, mainly for debugging
484      * purposes. We hand out the defaults, however this is not always
485      * accurate, as the connection might be tunneled, etc. But all that
486      * state is already gone here. */
487     *phost = data->conn->host.name;
488     *pdisplay_host = data->conn->host.dispname;
489     *pport = data->conn->remote_port;
490   }
491 }
492 
Curl_cf_def_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)493 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
494                                 struct Curl_easy *data,
495                                 int event, int arg1, void *arg2)
496 {
497   (void)cf;
498   (void)data;
499   (void)event;
500   (void)arg1;
501   (void)arg2;
502   return CURLE_OK;
503 }
504 
Curl_conn_cf_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)505 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
506                             struct Curl_easy *data,
507                             bool ignore_result,
508                             int event, int arg1, void *arg2)
509 {
510   CURLcode result = CURLE_OK;
511 
512   for(; cf; cf = cf->next) {
513     if(Curl_cf_def_cntrl == cf->cft->cntrl)
514       continue;
515     result = cf->cft->cntrl(cf, data, event, arg1, arg2);
516     if(!ignore_result && result)
517       break;
518   }
519   return result;
520 }
521 
Curl_conn_cf_get_socket(struct Curl_cfilter * cf,struct Curl_easy * data)522 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
523                                       struct Curl_easy *data)
524 {
525   curl_socket_t sock;
526   if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
527     return sock;
528   return CURL_SOCKET_BAD;
529 }
530 
Curl_conn_get_socket(struct Curl_easy * data,int sockindex)531 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
532 {
533   struct Curl_cfilter *cf;
534 
535   cf = data->conn? data->conn->cfilter[sockindex] : NULL;
536   /* if the top filter has not connected, ask it (and its sub-filters)
537    * for the socket. Otherwise conn->sock[sockindex] should have it.
538    */
539   if(cf && !cf->connected)
540     return Curl_conn_cf_get_socket(cf, data);
541   return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
542 }
543 
cf_cntrl_all(struct connectdata * conn,struct Curl_easy * data,bool ignore_result,int event,int arg1,void * arg2)544 static CURLcode cf_cntrl_all(struct connectdata *conn,
545                              struct Curl_easy *data,
546                              bool ignore_result,
547                              int event, int arg1, void *arg2)
548 {
549   CURLcode result = CURLE_OK;
550   size_t i;
551 
552   for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
553     result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
554                                 event, arg1, arg2);
555     if(!ignore_result && result)
556       break;
557   }
558   return result;
559 }
560 
Curl_conn_ev_data_attach(struct connectdata * conn,struct Curl_easy * data)561 void Curl_conn_ev_data_attach(struct connectdata *conn,
562                               struct Curl_easy *data)
563 {
564   cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
565 }
566 
Curl_conn_ev_data_detach(struct connectdata * conn,struct Curl_easy * data)567 void Curl_conn_ev_data_detach(struct connectdata *conn,
568                               struct Curl_easy *data)
569 {
570   cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
571 }
572 
Curl_conn_ev_data_setup(struct Curl_easy * data)573 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
574 {
575   return cf_cntrl_all(data->conn, data, FALSE,
576                       CF_CTRL_DATA_SETUP, 0, NULL);
577 }
578 
Curl_conn_ev_data_idle(struct Curl_easy * data)579 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
580 {
581   return cf_cntrl_all(data->conn, data, FALSE,
582                       CF_CTRL_DATA_IDLE, 0, NULL);
583 }
584 
585 /**
586  * Notify connection filters that the transfer represented by `data`
587  * is donw with sending data (e.g. has uploaded everything).
588  */
Curl_conn_ev_data_done_send(struct Curl_easy * data)589 void Curl_conn_ev_data_done_send(struct Curl_easy *data)
590 {
591   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
592 }
593 
594 /**
595  * Notify connection filters that the transfer represented by `data`
596  * is finished - eventually premature, e.g. before being complete.
597  */
Curl_conn_ev_data_done(struct Curl_easy * data,bool premature)598 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
599 {
600   cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
601 }
602 
Curl_conn_ev_data_pause(struct Curl_easy * data,bool do_pause)603 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
604 {
605   return cf_cntrl_all(data->conn, data, FALSE,
606                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
607 }
608 
Curl_conn_ev_update_info(struct Curl_easy * data,struct connectdata * conn)609 void Curl_conn_ev_update_info(struct Curl_easy *data,
610                               struct connectdata *conn)
611 {
612   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
613 }
614 
Curl_conn_report_connect_stats(struct Curl_easy * data,struct connectdata * conn)615 void Curl_conn_report_connect_stats(struct Curl_easy *data,
616                                     struct connectdata *conn)
617 {
618   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
619   if(cf) {
620     struct curltime connected;
621     struct curltime appconnected;
622 
623     memset(&connected, 0, sizeof(connected));
624     cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
625     if(connected.tv_sec || connected.tv_usec)
626       Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
627 
628     memset(&appconnected, 0, sizeof(appconnected));
629     cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
630     if(appconnected.tv_sec || appconnected.tv_usec)
631       Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
632   }
633 }
634 
Curl_conn_is_alive(struct Curl_easy * data,struct connectdata * conn,bool * input_pending)635 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
636                         bool *input_pending)
637 {
638   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
639   return cf && !cf->conn->bits.close &&
640          cf->cft->is_alive(cf, data, input_pending);
641 }
642 
Curl_conn_keep_alive(struct Curl_easy * data,struct connectdata * conn,int sockindex)643 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
644                               struct connectdata *conn,
645                               int sockindex)
646 {
647   struct Curl_cfilter *cf = conn->cfilter[sockindex];
648   return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
649 }
650 
Curl_conn_get_max_concurrent(struct Curl_easy * data,struct connectdata * conn,int sockindex)651 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
652                                      struct connectdata *conn,
653                                      int sockindex)
654 {
655   CURLcode result;
656   int n = 0;
657 
658   struct Curl_cfilter *cf = conn->cfilter[sockindex];
659   result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
660                               &n, NULL) : CURLE_UNKNOWN_OPTION;
661   return (result || n <= 0)? 1 : (size_t)n;
662 }
663 
664