diff options
author | Maxim Yurchuk <maxim-yurchuk@ydb.tech> | 2024-10-18 20:31:38 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-18 20:31:38 +0300 |
commit | 2a74bac2d2d3bccb4e10120f1ead805640ec9dd0 (patch) | |
tree | 047e4818ced5aaf73f58517629e5260b5291f9f0 /contrib/libs/curl/lib/easy.c | |
parent | 2d9656823e9521d8c29ea4c9a1d0eab78391abfc (diff) | |
parent | 3d834a1923bbf9403cd4a448e7f32b670aa4124f (diff) | |
download | ydb-2a74bac2d2d3bccb4e10120f1ead805640ec9dd0.tar.gz |
Merge pull request #10502 from ydb-platform/mergelibs-241016-1210
Library import 241016-1210
Diffstat (limited to 'contrib/libs/curl/lib/easy.c')
-rw-r--r-- | contrib/libs/curl/lib/easy.c | 346 |
1 files changed, 171 insertions, 175 deletions
diff --git a/contrib/libs/curl/lib/easy.c b/contrib/libs/curl/lib/easy.c index 261445aeef..322d1a41b8 100644 --- a/contrib/libs/curl/lib/easy.c +++ b/contrib/libs/curl/lib/easy.c @@ -113,7 +113,6 @@ static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT; #endif #if defined(_MSC_VER) && defined(_DLL) -# pragma warning(push) # pragma warning(disable:4232) /* MSVC extension, dllimport identity */ #endif @@ -131,7 +130,7 @@ curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup; #endif #if defined(_MSC_VER) && defined(_DLL) -# pragma warning(pop) +# pragma warning(default:4232) /* MSVC extension, dllimport identity */ #endif #ifdef DEBUGBUILD @@ -243,7 +242,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, global_init_lock(); if(initialized) { - /* Already initialized, do not do it again, but bump the variable anyway to + /* Already initialized, don't do it again, but bump the variable anyway to work like curl_global_init() and require the same amount of cleanup calls. */ initialized++; @@ -269,8 +268,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, /** * curl_global_cleanup() globally cleanups curl, uses the value of - * "easy_init_flags" to determine what needs to be cleaned up and what does - * not. + * "easy_init_flags" to determine what needs to be cleaned up and what doesn't. */ void curl_global_cleanup(void) { @@ -376,7 +374,7 @@ struct Curl_easy *curl_easy_init(void) return data; } -#ifdef DEBUGBUILD +#ifdef CURLDEBUG struct socketmonitor { struct socketmonitor *next; /* the next node in the list or NULL */ @@ -391,22 +389,25 @@ struct events { int running_handles; /* store the returned number */ }; -#define DEBUG_EV_POLL 0 - /* events_timer * * Callback that gets called with a new value when the timeout should be * updated. */ + static int events_timer(struct Curl_multi *multi, /* multi handle */ long timeout_ms, /* see above */ void *userp) /* private callback pointer */ { struct events *ev = userp; (void)multi; -#if DEBUG_EV_POLL - fprintf(stderr, "events_timer: set timeout %ldms\n", timeout_ms); -#endif + if(timeout_ms == -1) + /* timeout removed */ + timeout_ms = 0; + else if(timeout_ms == 0) + /* timeout is already reached! */ + timeout_ms = 1; /* trigger asap */ + ev->ms = timeout_ms; ev->msbump = TRUE; return 0; @@ -460,7 +461,6 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ struct events *ev = userp; struct socketmonitor *m; struct socketmonitor *prev = NULL; - bool found = FALSE; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) easy; @@ -470,7 +470,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ m = ev->list; while(m) { if(m->socket.fd == s) { - found = TRUE; + if(what == CURL_POLL_REMOVE) { struct socketmonitor *nxt = m->next; /* remove this node from the list of monitored sockets */ @@ -479,14 +479,14 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ else ev->list = nxt; free(m); - infof(easy, "socket cb: socket %" FMT_SOCKET_T " REMOVED", s); + m = nxt; + infof(easy, "socket cb: socket %d REMOVED", s); } else { /* The socket 's' is already being monitored, update the activity mask. Convert from libcurl bitmask to the poll one. */ m->socket.events = socketcb2poll(what); - infof(easy, "socket cb: socket %" FMT_SOCKET_T - " UPDATED as %s%s", s, + infof(easy, "socket cb: socket %d UPDATED as %s%s", s, (what&CURL_POLL_IN)?"IN":"", (what&CURL_POLL_OUT)?"OUT":""); } @@ -495,13 +495,12 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ prev = m; m = m->next; /* move to next node */ } - - if(!found) { + if(!m) { if(what == CURL_POLL_REMOVE) { - /* should not happen if our logic is correct, but is no drama. */ - DEBUGF(infof(easy, "socket cb: asked to REMOVE socket %" - FMT_SOCKET_T "but not present!", s)); - DEBUGASSERT(0); + /* this happens a bit too often, libcurl fix perhaps? */ + /* fprintf(stderr, + "%s: socket %d asked to be REMOVED but not present!\n", + __func__, s); */ } else { m = malloc(sizeof(struct socketmonitor)); @@ -511,7 +510,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ m->socket.events = socketcb2poll(what); m->socket.revents = 0; ev->list = m; - infof(easy, "socket cb: socket %" FMT_SOCKET_T " ADDED as %s%s", s, + infof(easy, "socket cb: socket %d ADDED as %s%s", s, (what&CURL_POLL_IN)?"IN":"", (what&CURL_POLL_OUT)?"OUT":""); } @@ -561,15 +560,14 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) int pollrc; int i; struct curltime before; + struct curltime after; /* populate the fds[] array */ for(m = ev->list, f = &fds[0]; m; m = m->next) { f->fd = m->socket.fd; f->events = m->socket.events; f->revents = 0; -#if DEBUG_EV_POLL - fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); -#endif + /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */ f++; numfds++; } @@ -577,27 +575,12 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) /* get the time stamp to use to figure out how long poll takes */ before = Curl_now(); - if(numfds) { - /* wait for activity or timeout */ -#if DEBUG_EV_POLL - fprintf(stderr, "poll(numfds=%d, timeout=%ldms)\n", numfds, ev->ms); -#endif - pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms); -#if DEBUG_EV_POLL - fprintf(stderr, "poll(numfds=%d, timeout=%ldms) -> %d\n", - numfds, ev->ms, pollrc); -#endif - if(pollrc < 0) - return CURLE_UNRECOVERABLE_POLL; - } - else { -#if DEBUG_EV_POLL - fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms); -#endif - pollrc = 0; - if(ev->ms > 0) - Curl_wait_ms(ev->ms); - } + /* wait for activity or timeout */ + pollrc = Curl_poll(fds, numfds, ev->ms); + if(pollrc < 0) + return CURLE_UNRECOVERABLE_POLL; + + after = Curl_now(); ev->msbump = FALSE; /* reset here */ @@ -610,37 +593,25 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) } else { /* here pollrc is > 0 */ - struct Curl_llist_node *e = Curl_llist_head(&multi->process); - struct Curl_easy *data; - DEBUGASSERT(e); - data = Curl_node_elem(e); - DEBUGASSERT(data); /* loop over the monitored sockets to see which ones had activity */ for(i = 0; i< numfds; i++) { if(fds[i].revents) { /* socket activity, tell libcurl */ int act = poll2cselect(fds[i].revents); /* convert */ - - /* sending infof "randomly" to the first easy handle */ - infof(data, "call curl_multi_socket_action(socket " - "%" FMT_SOCKET_T ")", (curl_socket_t)fds[i].fd); + infof(multi->easyp, "call curl_multi_socket_action(socket %d)", + fds[i].fd); mcode = curl_multi_socket_action(multi, fds[i].fd, act, &ev->running_handles); } } - - if(!ev->msbump && ev->ms >= 0) { + if(!ev->msbump) { /* If nothing updated the timeout, we decrease it by the spent time. * If it was updated, it has the new timeout time stored already. */ - timediff_t timediff = Curl_timediff(Curl_now(), before); + timediff_t timediff = Curl_timediff(after, before); if(timediff > 0) { -#if DEBUG_EV_POLL - fprintf(stderr, "poll timeout %ldms not updated, decrease by " - "time spent %ldms\n", ev->ms, (long)timediff); -#endif if(timediff > ev->ms) ev->ms = 0; else @@ -652,7 +623,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(mcode) return CURLE_URL_MALFORMAT; - /* we do not really care about the "msgs_in_queue" value returned in the + /* we don't really care about the "msgs_in_queue" value returned in the second argument */ msg = curl_multi_info_read(multi, &pollrc); if(msg) { @@ -673,15 +644,15 @@ static CURLcode easy_events(struct Curl_multi *multi) { /* this struct is made static to allow it to be used after this function returns and curl_multi_remove_handle() is called */ - static struct events evs = {-1, FALSE, 0, NULL, 0}; + static struct events evs = {2, FALSE, 0, NULL, 0}; /* if running event-based, do some further multi inits */ events_setup(multi, &evs); return wait_or_timeout(multi, &evs); } -#else /* DEBUGBUILD */ -/* when not built with debug, this function does not exist */ +#else /* CURLDEBUG */ +/* when not built with debug, this function doesn't exist */ #define easy_events(x) CURLE_NOT_BUILT_IN #endif @@ -713,9 +684,9 @@ static CURLcode easy_transfer(struct Curl_multi *multi) /* Make sure to return some kind of error if there was a multi problem */ if(mcode) { result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : - /* The other multi errors should never happen, so return - something suitably generic */ - CURLE_BAD_FUNCTION_ARGUMENT; + /* The other multi errors should never happen, so return + something suitably generic */ + CURLE_BAD_FUNCTION_ARGUMENT; } return result; @@ -731,7 +702,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi) * easy handle, destroys the multi handle and returns the easy handle's return * code. * - * REALITY: it cannot just create and destroy the multi handle that easily. It + * REALITY: it can't just create and destroy the multi handle that easily. It * needs to keep it around since if this easy handle is used again by this * function, the same multi handle must be reused so that the same pools and * caches can be used. @@ -753,8 +724,6 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) /* clear this as early as possible */ data->set.errorbuffer[0] = 0; - data->state.os_errno = 0; - if(data->multi) { failf(data, "easy handle already used in multi handle"); return CURLE_FAILED_INIT; @@ -768,6 +737,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) multi = Curl_multi_handle(1, 3, 7); if(!multi) return CURLE_OUT_OF_MEMORY; + data->multi_easy = multi; } if(multi->in_callback) @@ -776,25 +746,21 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) /* Copy the MAXCONNECTS option to the multi handle */ curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects); - data->multi_easy = NULL; /* pretend it does not exist */ mcode = curl_multi_add_handle(multi, data); if(mcode) { curl_multi_cleanup(multi); + data->multi_easy = NULL; if(mcode == CURLM_OUT_OF_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_FAILED_INIT; } - /* assign this after curl_multi_add_handle() */ - data->multi_easy = multi; - - sigpipe_init(&pipe_st); - sigpipe_apply(data, &pipe_st); + sigpipe_ignore(data, &pipe_st); /* run the transfer */ result = events ? easy_events(multi) : easy_transfer(multi); - /* ignoring the return code is not nice, but atm we cannot really handle + /* ignoring the return code isn't nice, but atm we can't really handle a failure here, room for future improvement! */ (void)curl_multi_remove_handle(multi, data); @@ -814,7 +780,7 @@ CURLcode curl_easy_perform(struct Curl_easy *data) return easy_perform(data, FALSE); } -#ifdef DEBUGBUILD +#ifdef CURLDEBUG /* * curl_easy_perform_ev() is the external interface that performs a blocking * transfer using the event-based API internally. @@ -938,7 +904,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER); - /* the connection pool is setup on demand */ + /* the connection cache is setup on demand */ + outcurl->state.conn_cache = NULL; outcurl->state.lastconnect_id = -1; outcurl->state.recent_conn_id = -1; outcurl->id = -1; @@ -1006,38 +973,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) } #endif -#ifdef CURLRES_ASYNCH - /* Clone the resolver handle, if present, for the new handle */ - if(Curl_resolver_duphandle(outcurl, - &outcurl->state.async.resolver, - data->state.async.resolver)) - goto fail; -#endif - -#ifdef USE_ARES - { - CURLcode rc; - - rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]); - if(rc && rc != CURLE_NOT_BUILT_IN) - goto fail; - - rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]); - if(rc && rc != CURLE_NOT_BUILT_IN) - goto fail; - - rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]); - if(rc && rc != CURLE_NOT_BUILT_IN) - goto fail; - - rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]); - if(rc && rc != CURLE_NOT_BUILT_IN) - goto fail; - } -#endif /* USE_ARES */ -#ifndef CURL_DISABLE_HTTP - Curl_llist_init(&outcurl->state.httphdrs, NULL); -#endif Curl_initinfo(outcurl); outcurl->magic = CURLEASY_MAGIC_NUMBER; @@ -1052,6 +987,7 @@ fail: #ifndef CURL_DISABLE_COOKIES free(outcurl->cookies); #endif + free(outcurl->state.buffer); Curl_dyn_free(&outcurl->state.headerb); Curl_altsvc_cleanup(&outcurl->asi); Curl_hsts_cleanup(&outcurl->hsts); @@ -1068,7 +1004,7 @@ fail: */ void curl_easy_reset(struct Curl_easy *data) { - Curl_req_hard_reset(&data->req, data); + Curl_free_request_state(data); /* zero out UserDefined data: */ Curl_freeset(data); @@ -1114,10 +1050,9 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) int oldstate; int newstate; bool recursive = FALSE; - bool keep_changed, unpause_read, not_all_paused; if(!GOOD_EASY_HANDLE(data) || !data->conn) - /* crazy input, do not continue */ + /* crazy input, don't continue */ return CURLE_BAD_FUNCTION_ARGUMENT; if(Curl_is_in_callback(data)) @@ -1130,52 +1065,60 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); - keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate); - not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != - (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE); - unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) && - (data->mstate == MSTATE_PERFORMING || - data->mstate == MSTATE_RATELIMITING)); - /* Unpausing writes is detected on the next run in - * transfer.c:Curl_sendrecv(). This is because this may result - * in a transfer error if the application's callbacks fail */ - - /* Set the new keepon state, so it takes effect no matter what error - * may happen afterwards. */ - k->keepon = newstate; + if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) { + /* Not changing any pause state, return */ + DEBUGF(infof(data, "pause: no change, early return")); + return CURLE_OK; + } - /* If not completely pausing both directions now, run again in any case. */ - if(not_all_paused) { - Curl_expire(data, 0, EXPIRE_RUN_NOW); - /* reset the too-slow time keeper */ - data->state.keeps_speed.tv_sec = 0; - /* Simulate socket events on next run for unpaused directions */ - if(!(newstate & KEEP_SEND_PAUSE)) - data->state.select_bits |= CURL_CSELECT_OUT; - if(!(newstate & KEEP_RECV_PAUSE)) - data->state.select_bits |= CURL_CSELECT_IN; - /* On changes, tell application to update its timers. */ - if(keep_changed && data->multi) { - if(Curl_update_timer(data->multi)) { - result = CURLE_ABORTED_BY_CALLBACK; - goto out; - } - } + /* Unpause parts in active mime tree. */ + if((k->keepon & ~newstate & KEEP_SEND_PAUSE) && + (data->mstate == MSTATE_PERFORMING || + data->mstate == MSTATE_RATELIMITING) && + data->state.fread_func == (curl_read_callback) Curl_mime_read) { + Curl_mime_unpause(data->state.in); } - if(unpause_read) { - result = Curl_creader_unpause(data); + /* put it back in the keepon */ + k->keepon = newstate; + + if(!(newstate & KEEP_RECV_PAUSE)) { + Curl_conn_ev_data_pause(data, FALSE); + result = Curl_client_unpause(data); if(result) - goto out; + return result; } - if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) { - Curl_conn_ev_data_pause(data, FALSE); - result = Curl_cwriter_unpause(data); +#ifdef USE_HYPER + if(!(newstate & KEEP_SEND_PAUSE)) { + /* need to wake the send body waker */ + if(data->hyp.send_body_waker) { + hyper_waker_wake(data->hyp.send_body_waker); + data->hyp.send_body_waker = NULL; + } + } +#endif + + /* if there's no error and we're not pausing both directions, we want + to have this handle checked soon */ + if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != + (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) { + Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ + + /* reset the too-slow time keeper */ + data->state.keeps_speed.tv_sec = 0; + + if(!data->state.tempcount) + /* if not pausing again, force a recv/send check of this connection as + the data might've been read off the socket already */ + data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; + if(data->multi) { + if(Curl_update_timer(data->multi)) + return CURLE_ABORTED_BY_CALLBACK; + } } -out: - if(!result && !data->state.done && keep_changed) + if(!data->state.done) /* This transfer may have been moved in or out of the bundle, update the corresponding socket callback, if used */ result = Curl_updatesocket(data); @@ -1189,11 +1132,9 @@ out: } -static CURLcode easy_connection(struct Curl_easy *data, +static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, struct connectdata **connp) { - curl_socket_t sfd; - if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -1203,9 +1144,9 @@ static CURLcode easy_connection(struct Curl_easy *data, return CURLE_UNSUPPORTED_PROTOCOL; } - sfd = Curl_getconnectinfo(data, connp); + *sfd = Curl_getconnectinfo(data, connp); - if(sfd == CURL_SOCKET_BAD) { + if(*sfd == CURL_SOCKET_BAD) { failf(data, "Failed to get recent socket"); return CURLE_UNSUPPORTED_PROTOCOL; } @@ -1221,6 +1162,7 @@ static CURLcode easy_connection(struct Curl_easy *data, CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, size_t *n) { + curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c; @@ -1228,7 +1170,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, if(Curl_is_in_callback(data)) return CURLE_RECURSIVE_API_CALL; - result = easy_connection(data, &c); + result = easy_connection(data, &sfd, &c); if(result) return result; @@ -1238,7 +1180,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, Curl_attach_connection(data, c); *n = 0; - result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1); + result = Curl_read(data, sfd, buffer, buflen, &n1); if(result) return result; @@ -1250,10 +1192,11 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, #ifdef USE_WEBSOCKETS CURLcode Curl_connect_only_attach(struct Curl_easy *data) { + curl_socket_t sfd; CURLcode result; struct connectdata *c = NULL; - result = easy_connection(data, &c); + result = easy_connection(data, &sfd, &c); if(result) return result; @@ -1272,14 +1215,15 @@ CURLcode Curl_connect_only_attach(struct Curl_easy *data) * This is the private internal version of curl_easy_send() */ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, - size_t buflen, size_t *n) + size_t buflen, ssize_t *n) { + curl_socket_t sfd; CURLcode result; + ssize_t n1; struct connectdata *c = NULL; SIGPIPE_VARIABLE(pipe_st); - *n = 0; - result = easy_connection(data, &c); + result = easy_connection(data, &sfd, &c); if(result) return result; @@ -1288,12 +1232,20 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, needs to be reattached */ Curl_attach_connection(data, c); + *n = 0; sigpipe_ignore(data, &pipe_st); - result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n); + result = Curl_write(data, sfd, buffer, buflen, &n1); sigpipe_restore(&pipe_st); - if(result && result != CURLE_AGAIN) + if(n1 == -1) return CURLE_SEND_ERROR; + + /* detect EAGAIN */ + if(!result && !n1) + return CURLE_AGAIN; + + *n = n1; + return result; } @@ -1304,17 +1256,58 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, size_t buflen, size_t *n) { - size_t written = 0; + ssize_t written = 0; CURLcode result; if(Curl_is_in_callback(data)) return CURLE_RECURSIVE_API_CALL; result = Curl_senddata(data, buffer, buflen, &written); - *n = written; + *n = (size_t)written; return result; } /* + * Wrapper to call functions in Curl_conncache_foreach() + * + * Returns always 0. + */ +static int conn_upkeep(struct Curl_easy *data, + struct connectdata *conn, + void *param) +{ + struct curltime *now = param; + + if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms) + return 0; + + /* briefly attach for action */ + Curl_attach_connection(data, conn); + if(conn->handler->connection_check) { + /* Do a protocol-specific keepalive check on the connection. */ + conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE); + } + else { + /* Do the generic action on the FIRSTSOCKE filter chain */ + Curl_conn_keep_alive(data, conn, FIRSTSOCKET); + } + Curl_detach_connection(data); + + conn->keepalive = *now; + return 0; /* continue iteration */ +} + +static CURLcode upkeep(struct conncache *conn_cache, void *data) +{ + struct curltime now = Curl_now(); + /* Loop over every connection and make connection alive. */ + Curl_conncache_foreach(data, + conn_cache, + &now, + conn_upkeep); + return CURLE_OK; +} + +/* * Performs connection upkeep for the given session handle. */ CURLcode curl_easy_upkeep(struct Curl_easy *data) @@ -1323,9 +1316,12 @@ CURLcode curl_easy_upkeep(struct Curl_easy *data) if(!GOOD_EASY_HANDLE(data)) return CURLE_BAD_FUNCTION_ARGUMENT; - if(Curl_is_in_callback(data)) - return CURLE_RECURSIVE_API_CALL; - - /* Use the common function to keep connections alive. */ - return Curl_cpool_upkeep(data); + if(data->multi_easy) { + /* Use the common function to keep connections alive. */ + return upkeep(&data->multi_easy->conn_cache, data); + } + else { + /* No connections, so just return success */ + return CURLE_OK; + } } |