multi: add xfer_buf to multi handle

- can be borrowed by transfer during recv-write operation
- needs to be released before borrowing again
- adjustis size to `data->set.buffer_size`
- used in transfer.c readwrite_data()

Closes #12805
This commit is contained in:
Stefan Eissing 2024-01-26 12:05:08 +01:00 committed by Daniel Stenberg
parent c54d0ff6b3
commit 476adfeac0
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
10 changed files with 113 additions and 25 deletions

View file

@ -94,6 +94,7 @@ static CURLMcode add_next_timeout(struct curltime now,
static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
static void multi_xfer_buf_free(struct Curl_multi *multi);
#ifdef DEBUGBUILD
static const char * const multi_statename[]={
@ -189,6 +190,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
/* changing to COMPLETED means there's one less easy handle 'alive' */
DEBUGASSERT(data->multi->num_alive > 0);
data->multi->num_alive--;
if(!data->multi->num_alive) {
/* free the transfer buffer when we have no more active transfers */
multi_xfer_buf_free(data->multi);
}
}
/* if this state has an init-function, run it */
@ -784,7 +789,6 @@ static CURLcode multi_done(struct Curl_easy *data,
data->state.lastconnect_id = -1;
}
Curl_safefree(data->state.buffer);
return result;
}
@ -1891,12 +1895,9 @@ static CURLcode readrewind(struct Curl_easy *data)
*/
CURLcode Curl_preconnect(struct Curl_easy *data)
{
if(!data->state.buffer) {
data->state.buffer = malloc(data->set.buffer_size + 1);
if(!data->state.buffer)
return CURLE_OUT_OF_MEMORY;
}
/* this used to do data->state.buffer allocation,
maybe remove completely now? */
(void)data;
return CURLE_OK;
}
@ -2450,7 +2451,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
{
char *newurl = NULL;
bool retry = FALSE;
DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
if(data->set.max_send_speed)
@ -2883,6 +2883,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
#endif
multi_xfer_buf_free(multi);
free(multi);
return CURLM_OK;
@ -3819,3 +3820,64 @@ struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi)
}
return a;
}
CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
char **pbuf, size_t *pbuflen)
{
DEBUGASSERT(data);
DEBUGASSERT(data->multi);
*pbuf = NULL;
*pbuflen = 0;
if(!data->multi) {
failf(data, "transfer has no multi handle");
return CURLE_FAILED_INIT;
}
if(!data->set.buffer_size) {
failf(data, "transfer buffer size is 0");
return CURLE_FAILED_INIT;
}
if(data->multi->xfer_buf_borrowed) {
failf(data, "attempt to borrow xfer_buf when already borrowed");
return CURLE_AGAIN;
}
if(data->multi->xfer_buf &&
data->set.buffer_size > data->multi->xfer_buf_len) {
/* not large enough, get a new one */
free(data->multi->xfer_buf);
data->multi->xfer_buf = NULL;
data->multi->xfer_buf_len = 0;
}
if(!data->multi->xfer_buf) {
data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
if(!data->multi->xfer_buf) {
failf(data, "could not allocate xfer_buf of %zu bytes",
(size_t)data->set.buffer_size);
return CURLE_OUT_OF_MEMORY;
}
data->multi->xfer_buf_len = data->set.buffer_size;
}
data->multi->xfer_buf_borrowed = TRUE;
*pbuf = data->multi->xfer_buf;
*pbuflen = data->multi->xfer_buf_len;
return CURLE_OK;
}
void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
{
(void)buf;
DEBUGASSERT(data);
DEBUGASSERT(data->multi);
DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
data->multi->xfer_buf_borrowed = FALSE;
}
static void multi_xfer_buf_free(struct Curl_multi *multi)
{
DEBUGASSERT(multi);
Curl_safefree(multi->xfer_buf);
multi->xfer_buf_len = 0;
multi->xfer_buf_borrowed = FALSE;
}