multi: multi_getsock(), check correct socket
- in phase CONNECTING/TUNNELING/PROTOCONNECT, retrieve the socket from the connection filters and do not rely on `conn->sockfd` being already set by the transfer. - this applies to the default behaviour, a protocol handler may override this via its callbacks. - add a warning message in multi_getsock() when the transfer is expected to have something in its pollset, but instead it is empty. Reported-by: saurabhsingh-dev on github Fixes #13998 Closes #14011
This commit is contained in:
parent
8e3e3921e6
commit
def99d8507
45
lib/multi.c
45
lib/multi.c
@ -1024,12 +1024,14 @@ void Curl_attach_connection(struct Curl_easy *data,
|
|||||||
static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
(void)socks;
|
curl_socket_t sockfd;
|
||||||
/* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes
|
|
||||||
* that *after* the connect. */
|
if(!conn)
|
||||||
if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
|
return GETSOCK_BLANK;
|
||||||
|
sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
|
||||||
|
if(sockfd != CURL_SOCKET_BAD) {
|
||||||
/* Default is to wait to something from the server */
|
/* Default is to wait to something from the server */
|
||||||
socks[0] = conn->sock[FIRSTSOCKET];
|
socks[0] = sockfd;
|
||||||
return GETSOCK_READSOCK(0);
|
return GETSOCK_READSOCK(0);
|
||||||
}
|
}
|
||||||
return GETSOCK_BLANK;
|
return GETSOCK_BLANK;
|
||||||
@ -1038,11 +1040,16 @@ static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
|||||||
static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
if(conn && conn->handler->proto_getsock)
|
curl_socket_t sockfd;
|
||||||
|
|
||||||
|
if(!conn)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
if(conn->handler->proto_getsock)
|
||||||
return conn->handler->proto_getsock(data, conn, socks);
|
return conn->handler->proto_getsock(data, conn, socks);
|
||||||
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
|
||||||
|
if(sockfd != CURL_SOCKET_BAD) {
|
||||||
/* Default is to wait to something from the server */
|
/* Default is to wait to something from the server */
|
||||||
socks[0] = conn->sockfd;
|
socks[0] = sockfd;
|
||||||
return GETSOCK_READSOCK(0);
|
return GETSOCK_READSOCK(0);
|
||||||
}
|
}
|
||||||
return GETSOCK_BLANK;
|
return GETSOCK_BLANK;
|
||||||
@ -1051,9 +1058,11 @@ static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
|||||||
static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
if(conn && conn->handler->domore_getsock)
|
if(!conn)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
if(conn->handler->domore_getsock)
|
||||||
return conn->handler->domore_getsock(data, conn, socks);
|
return conn->handler->domore_getsock(data, conn, socks);
|
||||||
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
else if(conn->sockfd != CURL_SOCKET_BAD) {
|
||||||
/* Default is that we want to send something to the server */
|
/* Default is that we want to send something to the server */
|
||||||
socks[0] = conn->sockfd;
|
socks[0] = conn->sockfd;
|
||||||
return GETSOCK_WRITESOCK(0);
|
return GETSOCK_WRITESOCK(0);
|
||||||
@ -1064,9 +1073,11 @@ static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
|||||||
static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
if(conn && conn->handler->doing_getsock)
|
if(!conn)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
if(conn->handler->doing_getsock)
|
||||||
return conn->handler->doing_getsock(data, conn, socks);
|
return conn->handler->doing_getsock(data, conn, socks);
|
||||||
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
|
else if(conn->sockfd != CURL_SOCKET_BAD) {
|
||||||
/* Default is that we want to send something to the server */
|
/* Default is that we want to send something to the server */
|
||||||
socks[0] = conn->sockfd;
|
socks[0] = conn->sockfd;
|
||||||
return GETSOCK_WRITESOCK(0);
|
return GETSOCK_WRITESOCK(0);
|
||||||
@ -1077,7 +1088,6 @@ static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
|||||||
static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
|
static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
|
|
||||||
if(!conn)
|
if(!conn)
|
||||||
return GETSOCK_BLANK;
|
return GETSOCK_BLANK;
|
||||||
else if(conn->handler->perform_getsock)
|
else if(conn->handler->perform_getsock)
|
||||||
@ -1114,6 +1124,7 @@ static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
|
|||||||
static void multi_getsock(struct Curl_easy *data,
|
static void multi_getsock(struct Curl_easy *data,
|
||||||
struct easy_pollset *ps)
|
struct easy_pollset *ps)
|
||||||
{
|
{
|
||||||
|
bool expect_sockets = TRUE;
|
||||||
/* The no connection case can happen when this is called from
|
/* The no connection case can happen when this is called from
|
||||||
curl_multi_remove_handle() => singlesocket() => multi_getsock().
|
curl_multi_remove_handle() => singlesocket() => multi_getsock().
|
||||||
*/
|
*/
|
||||||
@ -1127,6 +1138,7 @@ static void multi_getsock(struct Curl_easy *data,
|
|||||||
case MSTATE_SETUP:
|
case MSTATE_SETUP:
|
||||||
case MSTATE_CONNECT:
|
case MSTATE_CONNECT:
|
||||||
/* nothing to poll for yet */
|
/* nothing to poll for yet */
|
||||||
|
expect_sockets = FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSTATE_RESOLVING:
|
case MSTATE_RESOLVING:
|
||||||
@ -1165,19 +1177,26 @@ static void multi_getsock(struct Curl_easy *data,
|
|||||||
|
|
||||||
case MSTATE_RATELIMITING:
|
case MSTATE_RATELIMITING:
|
||||||
/* we need to let time pass, ignore socket(s) */
|
/* we need to let time pass, ignore socket(s) */
|
||||||
|
expect_sockets = FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSTATE_DONE:
|
case MSTATE_DONE:
|
||||||
case MSTATE_COMPLETED:
|
case MSTATE_COMPLETED:
|
||||||
case MSTATE_MSGSENT:
|
case MSTATE_MSGSENT:
|
||||||
/* nothing more to poll for */
|
/* nothing more to poll for */
|
||||||
|
expect_sockets = FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
|
failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
|
||||||
DEBUGASSERT(0);
|
DEBUGASSERT(0);
|
||||||
|
expect_sockets = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(expect_sockets && !ps->num && !Curl_xfer_is_blocked(data)) {
|
||||||
|
infof(data, "WARNING: no socket in pollset, transfer may stall!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
|
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user