3535#include "../../trace_api.h"
3636#include "../../resolve.h"
3737#include "../../timer.h"
38+ #include "../../lock_ops.h"
3839
3940#include "../tls_mgm/api.h"
4041
@@ -89,6 +90,10 @@ extern trace_proto_t tprot;
8990extern char * rest_id_s ;
9091
9192static CURLSH * curl_share = NULL ;
93+ static gen_lock_t curl_share_locks [CURL_LOCK_DATA_LAST ];
94+
95+ static enum curl_status status ;
96+ static long timer ;
9297
9398/**
9499 * We cannot use the "parallel transfers" feature of libcurl's multi interface
@@ -179,9 +184,18 @@ int rcl_init_internals(void)
179184
180185#define w_curl_multi_setopt (mh , opt , value ) \
181186 do { \
182- rc = curl_multi_setopt(mh, opt, value); \
183- if (rc != CURLE_OK) { \
184- LM_ERR("curl_multi_setopt(%d): (%s)\n", opt, curl_easy_strerror(rc)); \
187+ mrc = curl_multi_setopt(mh, opt, value); \
188+ if (mrc != CURLE_OK) { \
189+ LM_ERR("curl_multi_setopt(%d): (%s)\n", opt, curl_multi_strerror(mrc)); \
190+ goto cleanup; \
191+ } \
192+ } while (0)
193+
194+ #define w_curl_share_setopt (cs , opt , value ) \
195+ do { \
196+ src = curl_share_setopt(cs, opt, value); \
197+ if (src != CURLE_OK) { \
198+ LM_ERR("curl_share_setopt: %s\n", curl_share_strerror(src)); \
185199 goto cleanup; \
186200 } \
187201 } while (0)
@@ -426,21 +440,40 @@ static inline int get_easy_status(CURL *handle, CURLM *multi, CURLcode *code)
426440 return -1 ;
427441}
428442
443+ static void libcurl_share_lock (CURL * handle , curl_lock_data data , curl_lock_access access , void * clientp ) {
444+ LM_DBG ("Locking libcurl share %d\n" , data );
445+ lock_get (& curl_share_locks [data ]);
446+ }
447+
448+ static void libcurl_share_unlock (CURL * handle , curl_lock_data data , void * clientp ) {
449+ LM_DBG ("Unlocking libcurl share %d\n" , data );
450+ lock_release (& curl_share_locks [data ]);
451+ }
452+
429453static CURLSH * get_curl_share (void ) {
430454 CURLSHcode src ;
431455
432456 if (!curl_share ) {
433- curl_share = curl_share_init ();
457+ for (int i = 0 ; i < CURL_LOCK_DATA_LAST ; ++ i ) {
458+ lock_init (& curl_share_locks [i ]);
459+ }
434460
435- src = curl_share_setopt ( curl_share , CURLSHOPT_SHARE , CURL_LOCK_DATA_CONNECT );
461+ curl_share = curl_share_init ( );
436462
437- if (src != CURLSHE_OK ) {
438- LM_WARN ("curl_share_setopt: %s\n" , curl_share_strerror (src ));
439- return NULL ;
440- }
463+ w_curl_share_setopt (curl_share , CURLSHOPT_SHARE , CURL_LOCK_DATA_CONNECT );
464+ w_curl_share_setopt (curl_share , CURLSHOPT_LOCKFUNC , libcurl_share_lock );
465+ w_curl_share_setopt (curl_share , CURLSHOPT_UNLOCKFUNC , libcurl_share_unlock );
441466 }
442467
443468 return curl_share ;
469+ cleanup :
470+ for (int i = 0 ; i < CURL_LOCK_DATA_LAST ; ++ i ) {
471+ lock_destroy (& curl_share_locks [i ]);
472+ }
473+
474+ curl_share_cleanup (curl_share );
475+ curl_share = NULL ;
476+ return NULL ;
444477}
445478
446479static int init_transfer (CURL * handle , char * url , unsigned long timeout_s )
@@ -466,8 +499,7 @@ static int init_transfer(CURL *handle, char *url, unsigned long timeout_s)
466499 w_curl_easy_setopt (handle , CURLOPT_VERBOSE , 1 );
467500 w_curl_easy_setopt (handle , CURLOPT_FAILONERROR , 0 );
468501
469- if (is_printable (L_DBG ))
470- w_curl_easy_setopt (handle , CURLOPT_STDERR , stderr );
502+ w_curl_easy_setopt (handle , CURLOPT_STDERR , stdout );
471503
472504 if (ssl_capath )
473505 w_curl_easy_setopt (handle , CURLOPT_CAPATH , ssl_capath );
@@ -487,12 +519,15 @@ static int init_transfer(CURL *handle, char *url, unsigned long timeout_s)
487519static int init_socket_keepalive (CURL * handle ) {
488520 CURLcode rc ;
489521
490- curl_share = get_curl_share ();
491- w_curl_easy_setopt (handle , CURLOPT_SHARE , curl_share );
522+ if (share_connections ) {
523+ // If the share cannot be created then log warn but keep going
524+ curl_share = get_curl_share ();
525+ w_curl_easy_setopt (handle , CURLOPT_SHARE , curl_share );
526+ }
492527
493528 w_curl_easy_setopt (handle , CURLOPT_TCP_KEEPALIVE , 1L );
494- w_curl_easy_setopt (handle , CURLOPT_TCP_KEEPIDLE , 5L );
495- w_curl_easy_setopt (handle , CURLOPT_TCP_KEEPINTVL , 5L );
529+ w_curl_easy_setopt (handle , CURLOPT_TCP_KEEPIDLE , 180L );
530+ w_curl_easy_setopt (handle , CURLOPT_TCP_KEEPINTVL , 180L );
496531 w_curl_easy_setopt (handle , CURLOPT_MAXAGE_CONN , socket_keep_alive );
497532
498533 return 0 ;
@@ -1290,6 +1325,9 @@ static enum async_ret_code _resume_async_http_req_v2(int fd, struct sip_msg *msg
12901325 goto cleanup ;
12911326 }
12921327
1328+ w_curl_multi_setopt (multi_handle , CURLMOPT_TIMERFUNCTION , timer_cb );
1329+ w_curl_multi_setopt (multi_handle , CURLMOPT_TIMERDATA , & timer );
1330+
12931331 retr = 0 ;
12941332 do {
12951333 /* When @enable_expect_100 is on, both the client body upload and the
@@ -1686,8 +1724,7 @@ int start_async_http_req_v2(struct sip_msg *msg, enum rest_client_method method,
16861724 CURLMcode mrc ;
16871725 OSS_CURLM * multi_list ;
16881726 CURLM * multi_handle ;
1689- long busy_wait , timeout , connect_timeout , retry_time , timer ;
1690- enum curl_status status = CURL_NONE ;
1727+ long busy_wait , timeout , connect_timeout , retry_time ;
16911728
16921729 handle = curl_easy_init ();
16931730
@@ -1722,10 +1759,7 @@ int start_async_http_req_v2(struct sip_msg *msg, enum rest_client_method method,
17221759 w_curl_easy_setopt (handle , CURLOPT_WRITEFUNCTION , write_func );
17231760 w_curl_easy_setopt (handle , CURLOPT_WRITEDATA , body );
17241761
1725- if (share_connections ) {
1726- // If the share cannot be created then log warn but keep going
1727- init_socket_keepalive (handle );
1728- }
1762+ init_socket_keepalive (handle );
17291763
17301764 if (ctype ) {
17311765 w_curl_easy_setopt (handle , CURLOPT_HEADERFUNCTION , header_func );
@@ -1761,6 +1795,7 @@ int start_async_http_req_v2(struct sip_msg *msg, enum rest_client_method method,
17611795
17621796 w_curl_multi_setopt (multi_handle , CURLMOPT_MAXCONNECTS , (long ) max_connections );
17631797
1798+ status = CURL_NONE ;
17641799 w_curl_easy_setopt (handle , CURLOPT_PREREQFUNCTION , prereq_callback );
17651800 w_curl_easy_setopt (handle , CURLOPT_PREREQDATA , & status );
17661801
@@ -1779,6 +1814,10 @@ int start_async_http_req_v2(struct sip_msg *msg, enum rest_client_method method,
17791814 do {
17801815 running_handles = run_multi_socket (multi_handle );
17811816
1817+ if (running_handles < 0 ) {
1818+ goto error ;
1819+ }
1820+
17821821 if (status == CURL_REQUEST_SENT ) {
17831822 goto success ;
17841823 }
@@ -1797,9 +1836,14 @@ int start_async_http_req_v2(struct sip_msg *msg, enum rest_client_method method,
17971836success :
17981837 async_parm -> header_list = header_list ;
17991838 async_parm -> handle = handle ;
1800- async_parm -> multi_list = multi_list ;
18011839 header_list = NULL ;
18021840 * out_fd = get_max_fd (ASYNC_SYNC ); // Running only one socket at a time so it's always the max
1841+
1842+ if (* out_fd >= 0 ) {
1843+ async_parm -> multi_list = multi_list ;
1844+ } else {
1845+ put_multi (multi_list );
1846+ }
18031847 return RCL_OK ;
18041848
18051849error :
@@ -1875,4 +1919,4 @@ enum async_ret_code resume_async_http_req_v2(int fd, struct sip_msg *msg, void *
18751919
18761920enum async_ret_code time_out_async_http_req_v2 (int fd , struct sip_msg * msg , void * _param ) {
18771921 return _resume_async_http_req_v2 (fd , msg , (rest_async_param * )_param , 1 );
1878- }
1922+ }
0 commit comments