Skip to content

Commit

Permalink
Use single curl multi handle to re-use connections
Browse files Browse the repository at this point in the history
  • Loading branch information
jeroen committed Apr 24, 2024
1 parent cd94cda commit e16127d
Show file tree
Hide file tree
Showing 9 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/gnuwin32/embeddedR.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ void Rf_endEmbeddedR(int fatal)
{
R_RunExitFinalizers();
CleanEd();
CurlCleanup();
R_CleanTempDir();
if(!fatal){
Rf_KillAllDevices();
Expand Down
1 change: 1 addition & 0 deletions src/gnuwin32/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ static void Rstd_CleanUp(SA_TYPE saveact, int status, int runLast)
CleanEd();
KillAllDevices(); /* Unix does not do this under SA_SUICIDE */
AllDevicesKilled = TRUE; /* used in devWindows.c to inhibit callbacks */
CurlCleanup();
R_CleanTempDir(); /* changes directory */
if (R_Interactive && CharacterMode == RTerm)
SetConsoleTitle(oldtitle);
Expand Down
1 change: 1 addition & 0 deletions src/include/Defn.h
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,7 @@ SEXP fixup_NaRm(SEXP args); /* summary.c */
void invalidate_cached_recodings(void); /* from sysutils.c */
void resetICUcollator(Rboolean disable); /* from util.c */
void dt_invalidate_locale(void); /* from Rstrptime.h */
extern void CurlCleanup(void); /* from connections.c */
extern int R_OutputCon; /* from connections.c */
extern int R_InitReadItemDepth, R_ReadItemDepth; /* from serialize.c */
void get_current_mem(size_t *,size_t *,size_t *); /* from memory.c */
Expand Down
2 changes: 2 additions & 0 deletions src/include/Rmodules/Rinternet.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef int (*R_HTTPDCreateRoutine)(const char *ip, int port);
typedef void (*R_HTTPDStopRoutine)(void);

typedef SEXP (*R_CurlRoutine)(SEXP call, SEXP op, SEXP args, SEXP rho);
typedef void (*R_CurlCleanupRoutine)(void);

typedef struct {
R_DownloadRoutine download;
Expand All @@ -67,6 +68,7 @@ typedef struct {
R_CurlRoutine curlVersion;
R_CurlRoutine curlGetHeaders;
R_CurlRoutine curlDownload;
R_CurlCleanupRoutine curlCleanup;
R_NewUrlRoutine newcurlurl;
} R_InternetRoutines;

Expand Down
9 changes: 9 additions & 0 deletions src/main/internet.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,15 @@ attribute_hidden SEXP do_curlDownload(SEXP call, SEXP op, SEXP args, SEXP rho)
}
}

void CurlCleanup(void)
{
if(!initialized) internet_Init();
if(initialized > 0)
(*ptr->curlCleanup)();
else
error(_("internet routines cannot be loaded"));
}

Rconnection attribute_hidden
R_newCurlUrl(const char *description, const char * const mode, SEXP headers, int type)
{
Expand Down
2 changes: 2 additions & 0 deletions src/modules/internet/internet.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef int_fast64_t DLsize_t; // used for download lengths and sizes
SEXP in_do_curlVersion(SEXP call, SEXP op, SEXP args, SEXP rho);
SEXP in_do_curlGetHeaders(SEXP call, SEXP op, SEXP args, SEXP rho);
SEXP in_do_curlDownload(SEXP call, SEXP op, SEXP args, SEXP rho);
void in_curlCleanup(void);
Rconnection
in_newCurlUrl(const char *description, const char * const mode, SEXP headers, int type);

Expand Down Expand Up @@ -729,6 +730,7 @@ R_init_internet(DllInfo *info)
tmp->curlVersion = in_do_curlVersion;
tmp->curlGetHeaders = in_do_curlGetHeaders;
tmp->curlDownload = in_do_curlDownload;
tmp->curlCleanup = in_curlCleanup;
tmp->newcurlurl = in_newCurlUrl;

R_setInternetRoutines(tmp);
Expand Down
23 changes: 19 additions & 4 deletions src/modules/internet/libcurl.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,29 @@ extern void Rsleep(double timeint);

static int current_timeout = 0;

// The multi-handle is shared between downloads for reusing connections
static CURLM *shared_mhnd = NULL;

static CURLM attribute_hidden *get_mhnd(void)
{
if(!shared_mhnd)
shared_mhnd = curl_multi_init();
return shared_mhnd;
}

void attribute_hidden in_curlCleanup(void)
{
if(shared_mhnd)
curl_multi_cleanup(shared_mhnd);
shared_mhnd = NULL;
}

# if LIBCURL_VERSION_MAJOR < 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR < 28)

// curl/curl.h includes <sys/select.h> and headers it requires.

#define curl_multi_wait R_curl_multi_wait


static CURLMcode
R_curl_multi_wait(CURLM *multi_handle,
/* IGNORED */ void *unused,
Expand Down Expand Up @@ -565,8 +581,6 @@ static void download_cleanup(void *data)
if (c->hnd && c->hnd[i])
curl_easy_cleanup(c->hnd[i]);
}
if (c->mhnd)
curl_multi_cleanup(c->mhnd);
if (c->headers)
curl_slist_free_all(c->headers);

Expand Down Expand Up @@ -668,7 +682,8 @@ in_do_curlDownload(SEXP call, SEXP op, SEXP args, SEXP rho)
c.headers = headers = tmp;
}

CURLM *mhnd = curl_multi_init();
CURLM *mhnd = get_mhnd();

if (!mhnd)
error(_("could not create curl handle"));
c.mhnd = mhnd;
Expand Down
1 change: 1 addition & 0 deletions src/unix/Rembedded.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ void Rf_endEmbeddedR(int fatal)
R_RunExitFinalizers();
CleanEd();
if(!fatal) KillAllDevices();
CurlCleanup();
R_CleanTempDir();
if(!fatal && R_CollectWarnings)
PrintWarnings(); /* from device close and .Last */
Expand Down
1 change: 1 addition & 0 deletions src/unix/sys-std.c
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,7 @@ void Rstd_CleanUp(SA_TYPE saveact, int status, int runLast)
R_RunExitFinalizers();
CleanEd();
if(saveact != SA_SUICIDE) KillAllDevices();
CurlCleanup();
R_CleanTempDir();
if(saveact != SA_SUICIDE && R_CollectWarnings)
PrintWarnings(); /* from device close and (if run) .Last */
Expand Down

0 comments on commit e16127d

Please sign in to comment.