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:
Stefan Eissing 2024-01-05 12:28:09 +01:00 committed by Daniel Stenberg
parent 8edcfedc1a
commit a0f94800d5
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
10 changed files with 125 additions and 107 deletions

View file

@ -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,