transfer: adjust_pollset improvements
- let `multi_getsock()` initialize the pollset in what the transfer state requires in regards to SEND/RECV - change connection filters `adjust_pollset()` implementation to react on the presence of POLLIN/-OUT in the pollset and no longer check CURL_WANT_SEND/CURL_WANT_RECV - cf-socket will no longer add POLLIN on its own - http2 and http/3 filters will only do adjustments if the passed pollset wants to POLLIN/OUT for the transfer on the socket. This is similar to the HTTP/2 proxy filter and works in stacked filters. Closes #12640
This commit is contained in:
Родитель
8edcfedc1a
Коммит
a0f94800d5
|
@ -1243,7 +1243,7 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
|
|||
if(ctx->sock != CURL_SOCKET_BAD) {
|
||||
if(!cf->connected)
|
||||
Curl_pollset_set_out_only(data, ps, ctx->sock);
|
||||
else if(CURL_WANT_RECV(data))
|
||||
else if(!ctx->active)
|
||||
Curl_pollset_add_in(data, ps, ctx->sock);
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
|
||||
}
|
||||
|
|
|
@ -760,25 +760,11 @@ static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
|
|||
void Curl_pollset_add_socks(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
int (*get_socks_cb)(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
curl_socket_t *socks))
|
||||
{
|
||||
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
|
||||
int bitmap;
|
||||
|
||||
DEBUGASSERT(data->conn);
|
||||
bitmap = get_socks_cb(data, data->conn, socks);
|
||||
ps_add(data, ps, bitmap, socks);
|
||||
}
|
||||
|
||||
void Curl_pollset_add_socks2(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
int (*get_socks_cb)(struct Curl_easy *data,
|
||||
curl_socket_t *socks))
|
||||
{
|
||||
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
|
||||
int bitmap;
|
||||
|
||||
bitmap = get_socks_cb(data, socks);
|
||||
ps_add(data, ps, bitmap, socks);
|
||||
}
|
||||
|
|
|
@ -530,12 +530,7 @@ void Curl_pollset_set(struct Curl_easy *data,
|
|||
void Curl_pollset_add_socks(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
int (*get_socks_cb)(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
curl_socket_t *socks));
|
||||
void Curl_pollset_add_socks2(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
int (*get_socks_cb)(struct Curl_easy *data,
|
||||
curl_socket_t *socks));
|
||||
|
||||
/**
|
||||
* Check if the pollset, as is, wants to read and/or write regarding
|
||||
|
|
12
lib/http2.c
12
lib/http2.c
|
@ -2331,12 +2331,16 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
|
|||
struct easy_pollset *ps)
|
||||
{
|
||||
struct cf_h2_ctx *ctx = cf->ctx;
|
||||
bool want_recv = CURL_WANT_RECV(data);
|
||||
bool want_send = CURL_WANT_SEND(data);
|
||||
curl_socket_t sock;
|
||||
bool want_recv, want_send;
|
||||
|
||||
if(ctx->h2 && (want_recv || want_send)) {
|
||||
if(!ctx->h2)
|
||||
return;
|
||||
|
||||
sock = Curl_conn_cf_get_socket(cf, data);
|
||||
Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
|
||||
if(want_recv || want_send) {
|
||||
struct stream_ctx *stream = H2_STREAM_CTX(data);
|
||||
curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
|
||||
struct cf_call_data save;
|
||||
bool c_exhaust, s_exhaust;
|
||||
|
||||
|
|
131
lib/multi.c
131
lib/multi.c
|
@ -994,31 +994,90 @@ void Curl_attach_connection(struct Curl_easy *data,
|
|||
Curl_conn_ev_data_attach(conn, data);
|
||||
}
|
||||
|
||||
static int domore_getsock(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
curl_socket_t *socks)
|
||||
static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
(void)socks;
|
||||
if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
||||
/* Default is to wait to something from the server */
|
||||
socks[0] = conn->sockfd;
|
||||
return GETSOCK_READSOCK(0);
|
||||
}
|
||||
return GETSOCK_BLANK;
|
||||
}
|
||||
|
||||
static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
if(conn && conn->handler->proto_getsock)
|
||||
return conn->handler->proto_getsock(data, conn, socks);
|
||||
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
||||
/* Default is to wait to something from the server */
|
||||
socks[0] = conn->sockfd;
|
||||
return GETSOCK_READSOCK(0);
|
||||
}
|
||||
return GETSOCK_BLANK;
|
||||
}
|
||||
|
||||
static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
if(conn && conn->handler->domore_getsock)
|
||||
return conn->handler->domore_getsock(data, conn, socks);
|
||||
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
||||
/* Default is that we want to send something to the server */
|
||||
socks[0] = conn->sockfd;
|
||||
return GETSOCK_WRITESOCK(0);
|
||||
}
|
||||
return GETSOCK_BLANK;
|
||||
}
|
||||
|
||||
static int doing_getsock(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
curl_socket_t *socks)
|
||||
static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
if(conn && conn->handler->doing_getsock)
|
||||
return conn->handler->doing_getsock(data, conn, socks);
|
||||
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
||||
/* Default is that we want to send something to the server */
|
||||
socks[0] = conn->sockfd;
|
||||
return GETSOCK_WRITESOCK(0);
|
||||
}
|
||||
return GETSOCK_BLANK;
|
||||
}
|
||||
|
||||
static int protocol_getsock(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
curl_socket_t *socks)
|
||||
static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
|
||||
{
|
||||
if(conn->handler->proto_getsock)
|
||||
return conn->handler->proto_getsock(data, conn, socks);
|
||||
return GETSOCK_BLANK;
|
||||
struct connectdata *conn = data->conn;
|
||||
|
||||
if(!conn)
|
||||
return GETSOCK_BLANK;
|
||||
else if(conn->handler->perform_getsock)
|
||||
return conn->handler->perform_getsock(data, conn, sock);
|
||||
else {
|
||||
/* Default is to obey the data->req.keepon flags for send/recv */
|
||||
int bitmap = GETSOCK_BLANK;
|
||||
unsigned sockindex = 0;
|
||||
if(CURL_WANT_RECV(data)) {
|
||||
DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
|
||||
bitmap |= GETSOCK_READSOCK(sockindex);
|
||||
sock[sockindex] = conn->sockfd;
|
||||
}
|
||||
|
||||
if(CURL_WANT_SEND(data)) {
|
||||
if((conn->sockfd != conn->writesockfd) ||
|
||||
bitmap == GETSOCK_BLANK) {
|
||||
/* only if they are not the same socket and we have a readable
|
||||
one, we increase index */
|
||||
if(bitmap != GETSOCK_BLANK)
|
||||
sockindex++; /* increase index if we need two entries */
|
||||
|
||||
DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
|
||||
sock[sockindex] = conn->writesockfd;
|
||||
}
|
||||
bitmap |= GETSOCK_WRITESOCK(sockindex);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initializes `poll_set` with the current socket poll actions needed
|
||||
|
@ -1034,45 +1093,61 @@ static void multi_getsock(struct Curl_easy *data,
|
|||
return;
|
||||
|
||||
switch(data->mstate) {
|
||||
default:
|
||||
case MSTATE_INIT:
|
||||
case MSTATE_PENDING:
|
||||
case MSTATE_CONNECT:
|
||||
/* nothing to poll for yet */
|
||||
break;
|
||||
|
||||
case MSTATE_RESOLVING:
|
||||
Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock);
|
||||
Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
|
||||
/* connection filters are not involved in this phase */
|
||||
return;
|
||||
break;
|
||||
|
||||
case MSTATE_CONNECTING:
|
||||
case MSTATE_TUNNELING:
|
||||
Curl_pollset_add_socks(data, ps, connecting_getsock);
|
||||
Curl_conn_adjust_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_PROTOCONNECTING:
|
||||
case MSTATE_PROTOCONNECT:
|
||||
case MSTATE_PROTOCONNECTING:
|
||||
Curl_pollset_add_socks(data, ps, protocol_getsock);
|
||||
Curl_conn_adjust_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_DO:
|
||||
case MSTATE_DOING:
|
||||
Curl_pollset_add_socks(data, ps, doing_getsock);
|
||||
break;
|
||||
|
||||
case MSTATE_TUNNELING:
|
||||
case MSTATE_CONNECTING:
|
||||
Curl_conn_adjust_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_DOING_MORE:
|
||||
Curl_pollset_add_socks(data, ps, domore_getsock);
|
||||
Curl_conn_adjust_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_DID: /* since is set after DO is completed, we switch to
|
||||
waiting for the same as the PERFORMING state */
|
||||
case MSTATE_DID: /* same as PERFORMING in regard to polling */
|
||||
case MSTATE_PERFORMING:
|
||||
Curl_pollset_add_socks(data, ps, Curl_single_getsock);
|
||||
Curl_pollset_add_socks(data, ps, perform_getsock);
|
||||
Curl_conn_adjust_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_RATELIMITING:
|
||||
/* nothing to wait for */
|
||||
return;
|
||||
}
|
||||
/* we need to let time pass, ignore socket(s) */
|
||||
break;
|
||||
|
||||
/* Let connection filters add/remove as needed */
|
||||
Curl_conn_adjust_pollset(data, ps);
|
||||
case MSTATE_DONE:
|
||||
case MSTATE_COMPLETED:
|
||||
case MSTATE_MSGSENT:
|
||||
/* nothing more to poll for */
|
||||
break;
|
||||
|
||||
default:
|
||||
failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
|
||||
DEBUGASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
|
||||
|
|
|
@ -1220,52 +1220,6 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_single_getsock() gets called by the multi interface code when the app
|
||||
* has requested to get the sockets for the current connection. This function
|
||||
* will then be called once for every connection that the multi interface
|
||||
* keeps track of. This function will only be called for connections that are
|
||||
* in the proper state to have this information available.
|
||||
*/
|
||||
int Curl_single_getsock(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
curl_socket_t *sock)
|
||||
{
|
||||
int bitmap = GETSOCK_BLANK;
|
||||
unsigned sockindex = 0;
|
||||
|
||||
if(conn->handler->perform_getsock)
|
||||
return conn->handler->perform_getsock(data, conn, sock);
|
||||
|
||||
/* don't include HOLD and PAUSE connections */
|
||||
if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
|
||||
|
||||
DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
|
||||
|
||||
bitmap |= GETSOCK_READSOCK(sockindex);
|
||||
sock[sockindex] = conn->sockfd;
|
||||
}
|
||||
|
||||
/* don't include HOLD and PAUSE connections */
|
||||
if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
|
||||
if((conn->sockfd != conn->writesockfd) ||
|
||||
bitmap == GETSOCK_BLANK) {
|
||||
/* only if they are not the same socket and we have a readable
|
||||
one, we increase index */
|
||||
if(bitmap != GETSOCK_BLANK)
|
||||
sockindex++; /* increase index if we need two entries */
|
||||
|
||||
DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
|
||||
|
||||
sock[sockindex] = conn->writesockfd;
|
||||
}
|
||||
|
||||
bitmap |= GETSOCK_WRITESOCK(sockindex);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
|
||||
which means this gets called once for each subsequent redirect etc */
|
||||
void Curl_init_CONNECT(struct Curl_easy *data)
|
||||
|
|
|
@ -47,8 +47,6 @@ CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
|
|||
followtype type);
|
||||
CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
struct Curl_easy *data, bool *done);
|
||||
int Curl_single_getsock(struct Curl_easy *data,
|
||||
struct connectdata *conn, curl_socket_t *socks);
|
||||
CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
|
||||
size_t *nreadp);
|
||||
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
|
||||
|
|
|
@ -583,7 +583,7 @@ struct hostname {
|
|||
(((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND)
|
||||
/* transfer receive is not on PAUSE or HOLD */
|
||||
#define CURL_WANT_RECV(data) \
|
||||
(!((data)->req.keepon & (KEEP_RECV_PAUSE|KEEP_RECV_HOLD)))
|
||||
(((data)->req.keepon & KEEP_RECVBITS) == KEEP_RECV)
|
||||
|
||||
#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
|
||||
#define USE_CURL_ASYNC
|
||||
|
|
|
@ -1157,10 +1157,13 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
|
|||
struct easy_pollset *ps)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
bool want_recv = CURL_WANT_RECV(data);
|
||||
bool want_send = CURL_WANT_SEND(data);
|
||||
bool want_recv, want_send;
|
||||
|
||||
if(ctx->qconn && (want_recv || want_send)) {
|
||||
if(!ctx->qconn)
|
||||
return;
|
||||
|
||||
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
|
||||
if(want_recv || want_send) {
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct cf_call_data save;
|
||||
bool c_exhaust, s_exhaust;
|
||||
|
|
|
@ -1180,10 +1180,13 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
|
|||
struct easy_pollset *ps)
|
||||
{
|
||||
struct cf_quiche_ctx *ctx = cf->ctx;
|
||||
bool want_recv = CURL_WANT_RECV(data);
|
||||
bool want_send = CURL_WANT_SEND(data);
|
||||
bool want_recv, want_send;
|
||||
|
||||
if(ctx->qconn && (want_recv || want_send)) {
|
||||
if(!ctx->qconn)
|
||||
return;
|
||||
|
||||
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
|
||||
if(want_recv || want_send) {
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
bool c_exhaust, s_exhaust;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче