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