@@ -131,6 +131,11 @@ static int closesocket_callback(void __attribute__((unused)) *clientp, curl_sock
131131 DLOG ("curl closed socket: %d" , sock );
132132 client -> connections -- ;
133133
134+ if (client -> connections <= 0 && ev_is_active (& client -> reset_timer )) {
135+ ILOG ("Client reset timer cancelled, since all connection closed" );
136+ ev_timer_stop (client -> loop , & client -> reset_timer );
137+ }
138+
134139 if (client -> stat ) {
135140 stat_connection_closed (client -> stat );
136141 }
@@ -353,6 +358,12 @@ static int https_fetch_ctx_process_response(https_client_t *client,
353358 case CURLE_WRITE_ERROR :
354359 WLOG_REQ ("curl request failed with write error (probably response content was too large)" );
355360 break ;
361+ case CURLE_OPERATION_TIMEDOUT :
362+ if (!ev_is_active (& client -> reset_timer )) {
363+ ILOG_REQ ("Client reset timer started" );
364+ ev_timer_start (client -> loop , & client -> reset_timer );
365+ }
366+ __attribute__((fallthrough ));
356367 default :
357368 WLOG_REQ ("curl request failed with %d: %s" , curl_result_code , curl_easy_strerror (curl_result_code ));
358369 if (ctx -> curl_errbuf [0 ] != 0 ) {
@@ -465,7 +476,7 @@ static int https_fetch_ctx_process_response(https_client_t *client,
465476 res = curl_easy_getinfo (ctx -> curl , CURLINFO_SCHEME , & str_resp );
466477 if (res != CURLE_OK ) {
467478 ELOG_REQ ("CURLINFO_SCHEME: %s" , curl_easy_strerror (res ));
468- } else if (strcasecmp (str_resp , "https" ) != 0 ) {
479+ } else if (str_resp != NULL && strcasecmp (str_resp , "https" ) != 0 ) {
469480 DLOG_REQ ("CURLINFO_SCHEME: %s" , str_resp );
470481 }
471482
@@ -648,15 +659,31 @@ static int multi_timer_cb(CURLM __attribute__((unused)) *multi,
648659 return 0 ;
649660}
650661
662+ static void https_client_multi_init (https_client_t * c , struct curl_slist * header_list ) {
663+ c -> curlm = curl_multi_init (); // if fails, first setopt will fail
664+ c -> header_list = header_list ;
665+
666+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_PIPELINING , CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX );
667+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_MAX_TOTAL_CONNECTIONS , HTTPS_CONNECTION_LIMIT );
668+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_MAX_HOST_CONNECTIONS , HTTPS_CONNECTION_LIMIT );
669+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_SOCKETDATA , c );
670+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_SOCKETFUNCTION , multi_sock_cb );
671+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_TIMERDATA , c );
672+ ASSERT_CURL_MULTI_SETOPT (c -> curlm , CURLMOPT_TIMERFUNCTION , multi_timer_cb );
673+ }
674+
675+ static void reset_timer_cb (struct ev_loop __attribute__((unused )) * loop ,
676+ ev_timer * w , int __attribute__((unused )) revents ) {
677+ GET_PTR (https_client_t , c , w -> data );
678+ ILOG ("Client reset timer timeouted" );
679+ https_client_reset (c );
680+ }
681+
651682void https_client_init (https_client_t * c , options_t * opt ,
652683 stat_t * stat , struct ev_loop * loop ) {
653684 // NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
654685 memset (c , 0 , sizeof (* c ));
655686 c -> loop = loop ;
656- c -> curlm = curl_multi_init (); // if fails, first setopt will fail
657- c -> header_list = curl_slist_append (curl_slist_append (NULL ,
658- "Accept: " DOH_CONTENT_TYPE ),
659- "Content-Type: " DOH_CONTENT_TYPE );
660687 c -> fetches = NULL ;
661688 c -> timer .data = c ;
662689 for (int i = 0 ; i < HTTPS_SOCKET_LIMIT ; i ++ ) {
@@ -665,13 +692,13 @@ void https_client_init(https_client_t *c, options_t *opt,
665692 c -> opt = opt ;
666693 c -> stat = stat ;
667694
668- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_PIPELINING , CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX );
669- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_MAX_TOTAL_CONNECTIONS , HTTPS_CONNECTION_LIMIT ) ;
670- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_MAX_HOST_CONNECTIONS , HTTPS_CONNECTION_LIMIT );
671- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_SOCKETDATA , c );
672- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_SOCKETFUNCTION , multi_sock_cb );
673- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_TIMERDATA , c );
674- ASSERT_CURL_MULTI_SETOPT ( c -> curlm , CURLMOPT_TIMERFUNCTION , multi_timer_cb );
695+ ev_timer_init ( & c -> reset_timer , reset_timer_cb , ( double ) opt -> conn_loss_time , 0 );
696+ c -> reset_timer . data = c ;
697+
698+ struct curl_slist * header_list = curl_slist_append ( curl_slist_append ( NULL ,
699+ "Accept: " DOH_CONTENT_TYPE ),
700+ "Content-Type: " DOH_CONTENT_TYPE );
701+ https_client_multi_init ( c , header_list );
675702}
676703
677704void https_client_fetch (https_client_t * c , const char * url ,
@@ -687,11 +714,10 @@ void https_client_fetch(https_client_t *c, const char *url,
687714}
688715
689716void https_client_reset (https_client_t * c ) {
690- options_t * opt = c -> opt ;
691- stat_t * stat = c -> stat ;
692- struct ev_loop * loop = c -> loop ;
717+ struct curl_slist * header_list = c -> header_list ;
718+ c -> header_list = NULL ;
693719 https_client_cleanup (c );
694- https_client_init (c , opt , stat , loop );
720+ https_client_multi_init (c , header_list );
695721}
696722
697723void https_client_cleanup (https_client_t * c ) {
@@ -700,4 +726,5 @@ void https_client_cleanup(https_client_t *c) {
700726 }
701727 curl_slist_free_all (c -> header_list );
702728 curl_multi_cleanup (c -> curlm );
729+ ev_timer_stop (c -> loop , & c -> reset_timer );
703730}
0 commit comments