mirror of
https://github.com/curl/curl.git
synced 2026-07-08 03:37:16 +03:00
socket: introduce SOCK_EAGAIN() and use it
To contain the logic of checking for both `EWOULDBLOCK` and/or `EAGAIN` depending on platform/availability. Also to avoid checking for both if they mapp to the same value, and to avoid PP guards around use. This also ensures `EAGAIN` is consistently not checked on Windows, where headers defined it, but `SOCKERRNO` never returns it, because curl maps it to `WSAGetLastError()`. If they map to the same value, checking them both in an `if` expression trips GCC warning `-Wlogical-op` (the same way it triggers duplicate case value error in `switch`). Also: - replace two `switch()` statements with the new macro. - tests/server/sws: make two outliers use the new macro that were only checking for `EWOULDBLOCK` before this patch, in `connect_to()`. - move variables to the left-side of expressions, where missing. - rustls: use a variant of this macro that uses raw `EWOULDBLOCK`. Tried tracing it back to the origins, but I couldn't figure out if this is working as expected on all supported Windows versions in Rust. It seems to be using `GetLastError()`, according to https://docs.rs/system_error/0.2.0/system_error/, which would be probably incorrect. Notes: - it's probably a good idea to assign `SOCKERRNO` to a variable before passing it to this macro. Cherry-picked from #21893 Closes #21992
This commit is contained in:
parent
7c51a33877
commit
879a1514c3
7 changed files with 63 additions and 95 deletions
|
|
@ -939,32 +939,19 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
|
|||
static CURLcode socket_connect_result(struct Curl_easy *data,
|
||||
const char *ipaddress, int error)
|
||||
{
|
||||
switch(error) {
|
||||
case SOCKEINPROGRESS:
|
||||
case SOCKEWOULDBLOCK:
|
||||
#ifdef EAGAIN
|
||||
#if (EAGAIN) != (SOCKEWOULDBLOCK)
|
||||
/* On some platforms EAGAIN and EWOULDBLOCK are the
|
||||
* same value, and on others they are different, hence
|
||||
* the odd #if
|
||||
*/
|
||||
case EAGAIN:
|
||||
#endif
|
||||
#endif
|
||||
if(error == SOCKEINPROGRESS || SOCK_EAGAIN(error))
|
||||
return CURLE_OK;
|
||||
|
||||
default:
|
||||
/* unknown error, fallthrough and try another address! */
|
||||
{
|
||||
VERBOSE(char buffer[STRERROR_LEN]);
|
||||
infof(data, "Immediate connect fail for %s: %s", ipaddress,
|
||||
curlx_strerror(error, buffer, sizeof(buffer)));
|
||||
NOVERBOSE((void)ipaddress);
|
||||
}
|
||||
data->state.os_errno = error;
|
||||
/* connect failed */
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
/* unknown error, fallthrough and try another address! */
|
||||
{
|
||||
VERBOSE(char buffer[STRERROR_LEN]);
|
||||
infof(data, "Immediate connect fail for %s: %s", ipaddress,
|
||||
curlx_strerror(error, buffer, sizeof(buffer)));
|
||||
NOVERBOSE((void)ipaddress);
|
||||
}
|
||||
data->state.os_errno = error;
|
||||
/* connect failed */
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
|
||||
struct cf_socket_ctx {
|
||||
|
|
@ -1560,22 +1547,12 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
|
||||
if(!curlx_sztouz(rv, pnwritten)) {
|
||||
int sockerr = SOCKERRNO;
|
||||
|
||||
if(
|
||||
#ifdef USE_WINSOCK
|
||||
/* This is how Windows does it */
|
||||
(SOCKEWOULDBLOCK == sockerr)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
|
||||
due to its inability to send off data without blocking. We therefore
|
||||
treat both error codes the same here */
|
||||
(SOCKEWOULDBLOCK == sockerr) ||
|
||||
(EAGAIN == sockerr) || (SOCKEINTR == sockerr) ||
|
||||
(SOCKEINPROGRESS == sockerr)
|
||||
if(SOCK_EAGAIN(sockerr)
|
||||
#ifndef USE_WINSOCK
|
||||
|| (sockerr == SOCKEINTR) || (sockerr == SOCKEINPROGRESS)
|
||||
#endif
|
||||
) {
|
||||
/* EWOULDBLOCK */
|
||||
result = CURLE_AGAIN;
|
||||
result = CURLE_AGAIN; /* EWOULDBLOCK */
|
||||
}
|
||||
else {
|
||||
char buffer[STRERROR_LEN];
|
||||
|
|
@ -1626,21 +1603,12 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
|
||||
if(!curlx_sztouz(rv, pnread)) {
|
||||
int sockerr = SOCKERRNO;
|
||||
|
||||
if(
|
||||
#ifdef USE_WINSOCK
|
||||
/* This is how Windows does it */
|
||||
(SOCKEWOULDBLOCK == sockerr)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
|
||||
due to its inability to send off data without blocking. We therefore
|
||||
treat both error codes the same here */
|
||||
(SOCKEWOULDBLOCK == sockerr) ||
|
||||
(EAGAIN == sockerr) || (SOCKEINTR == sockerr)
|
||||
if(SOCK_EAGAIN(sockerr)
|
||||
#ifndef USE_WINSOCK
|
||||
|| (sockerr == SOCKEINTR)
|
||||
#endif
|
||||
) {
|
||||
/* EWOULDBLOCK */
|
||||
result = CURLE_AGAIN;
|
||||
result = CURLE_AGAIN; /* EWOULDBLOCK */
|
||||
}
|
||||
else {
|
||||
char buffer[STRERROR_LEN];
|
||||
|
|
|
|||
|
|
@ -1137,6 +1137,15 @@ typedef unsigned int curl_bit;
|
|||
#define SOCKEWOULDBLOCK EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
/* The socket error may be EWOULDBLOCK or on some systems EAGAIN when
|
||||
it returned due to its inability to send/read data without blocking.
|
||||
We treat both error codes the same here. */
|
||||
#if !defined(USE_WINSOCK) && EAGAIN != SOCKEWOULDBLOCK
|
||||
#define SOCK_EAGAIN(e) ((e) == SOCKEWOULDBLOCK || (e) == EAGAIN)
|
||||
#else
|
||||
#define SOCK_EAGAIN(e) ((e) == SOCKEWOULDBLOCK)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macro argv_item_t hides platform details to code using it.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -232,16 +232,9 @@ static int wakeup_inet(curl_socket_t socks[2], bool nonblocking)
|
|||
/* Do not block forever */
|
||||
if(curlx_timediff_ms(curlx_now(), start) > (60 * 1000))
|
||||
goto error;
|
||||
if(
|
||||
#ifdef USE_WINSOCK
|
||||
/* This is how Windows does it */
|
||||
(SOCKEWOULDBLOCK == sockerr)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it
|
||||
returned due to its inability to send off data without
|
||||
blocking. We therefore treat both error codes the same here */
|
||||
(SOCKEWOULDBLOCK == sockerr) || (EAGAIN == sockerr) ||
|
||||
(SOCKEINTR == sockerr) || (SOCKEINPROGRESS == sockerr)
|
||||
if(SOCK_EAGAIN(sockerr)
|
||||
#ifndef USE_WINSOCK
|
||||
|| (sockerr == SOCKEINTR) || (sockerr == SOCKEINPROGRESS)
|
||||
#endif
|
||||
) {
|
||||
continue;
|
||||
|
|
@ -320,15 +313,12 @@ int Curl_wakeup_signal(curl_socket_t socks[2])
|
|||
err = 0;
|
||||
if(wakeup_write(socks[1], buf, sizeof(buf)) < 0) {
|
||||
err = SOCKERRNO;
|
||||
#ifdef USE_WINSOCK
|
||||
if(err == SOCKEWOULDBLOCK)
|
||||
err = 0; /* wakeup is already ongoing */
|
||||
#else
|
||||
if(SOCKEINTR == err)
|
||||
#ifndef USE_WINSOCK
|
||||
if(err == SOCKEINTR)
|
||||
continue;
|
||||
if((err == SOCKEWOULDBLOCK) || (err == EAGAIN))
|
||||
err = 0; /* wakeup is already ongoing */
|
||||
#endif
|
||||
if(SOCK_EAGAIN(err))
|
||||
err = 0; /* wakeup is already ongoing */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -346,15 +336,13 @@ CURLcode Curl_wakeup_consume(curl_socket_t socks[2], bool all)
|
|||
if(!rc)
|
||||
break;
|
||||
else if(rc < 0) {
|
||||
#ifdef USE_WINSOCK
|
||||
if(SOCKERRNO == SOCKEWOULDBLOCK)
|
||||
break;
|
||||
#else
|
||||
if(SOCKEINTR == SOCKERRNO)
|
||||
int sockerr = SOCKERRNO;
|
||||
#ifndef USE_WINSOCK
|
||||
if(sockerr == SOCKEINTR)
|
||||
continue;
|
||||
if((SOCKERRNO == SOCKEWOULDBLOCK) || (SOCKERRNO == EAGAIN))
|
||||
break;
|
||||
#endif
|
||||
if(SOCK_EAGAIN(sockerr))
|
||||
break;
|
||||
result = CURLE_READ_ERROR;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,12 +165,10 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
|
|||
;
|
||||
|
||||
if(!curlx_sztouz(rv, psent)) {
|
||||
switch(SOCKERRNO) {
|
||||
case EAGAIN:
|
||||
#if EAGAIN != SOCKEWOULDBLOCK
|
||||
case SOCKEWOULDBLOCK:
|
||||
#endif
|
||||
int sockerr = SOCKERRNO;
|
||||
if(SOCK_EAGAIN(sockerr))
|
||||
return CURLE_AGAIN;
|
||||
switch(sockerr) {
|
||||
case SOCKEMSGSIZE:
|
||||
/* UDP datagram is too large; caused by PMTUD. Let it be lost. */
|
||||
*psent = pktlen;
|
||||
|
|
@ -179,13 +177,13 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
|
|||
if(pktlen > gsolen) {
|
||||
/* GSO failure */
|
||||
infof(data, "sendmsg() returned %zd (errno %d); disable GSO", rv,
|
||||
SOCKERRNO);
|
||||
sockerr);
|
||||
qctx->no_gso = TRUE;
|
||||
return send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent);
|
||||
}
|
||||
FALLTHROUGH();
|
||||
default:
|
||||
failf(data, "sendmsg() returned %zd (errno %d)", rv, SOCKERRNO);
|
||||
failf(data, "sendmsg() returned %zd (errno %d)", rv, sockerr);
|
||||
result = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -206,7 +204,7 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
|
|||
;
|
||||
|
||||
if(!curlx_sztouz(rv, psent)) {
|
||||
if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
|
||||
if(SOCK_EAGAIN(SOCKERRNO)) {
|
||||
result = CURLE_AGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -487,7 +485,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
|
|||
(SOCKERRNO == SOCKEINTR || SOCKERRNO == SOCKEMSGSIZE))
|
||||
;
|
||||
if(mcount == -1) {
|
||||
if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
|
||||
if(SOCK_EAGAIN(SOCKERRNO)) {
|
||||
CURL_TRC_CF(data, cf, "ingress, recvmmsg -> EAGAIN");
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -574,7 +572,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
|
|||
(SOCKERRNO == SOCKEINTR || SOCKERRNO == SOCKEMSGSIZE))
|
||||
;
|
||||
if(!curlx_sztouz(rc, &nread)) {
|
||||
if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
|
||||
if(SOCK_EAGAIN(SOCKERRNO)) {
|
||||
goto out;
|
||||
}
|
||||
if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) {
|
||||
|
|
@ -644,7 +642,7 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf,
|
|||
(SOCKERRNO == SOCKEINTR || SOCKERRNO == SOCKEMSGSIZE))
|
||||
;
|
||||
if(!curlx_sztouz(rv, &nread)) {
|
||||
if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
|
||||
if(SOCK_EAGAIN(SOCKERRNO)) {
|
||||
CURL_TRC_CF(data, cf, "ingress, recvfrom -> EAGAIN");
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,12 @@
|
|||
#include "curlx/base64.h"
|
||||
#endif
|
||||
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
#define RAW_EAGAIN(e) ((e) == EWOULDBLOCK || (e) == EAGAIN)
|
||||
#else
|
||||
#define RAW_EAGAIN(e) ((e) == EWOULDBLOCK)
|
||||
#endif
|
||||
|
||||
struct rustls_ssl_backend_data {
|
||||
const struct rustls_client_config *config;
|
||||
struct rustls_connection *conn;
|
||||
|
|
@ -160,7 +166,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
|
|||
io_ctx.data = data;
|
||||
io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx,
|
||||
&tls_bytes_read);
|
||||
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
|
||||
if(RAW_EAGAIN(io_error)) {
|
||||
*err = CURLE_AGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -270,7 +276,7 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|||
while(rustls_connection_wants_write(rconn)) {
|
||||
io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
|
||||
&tlswritten);
|
||||
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
|
||||
if(RAW_EAGAIN(io_error)) {
|
||||
CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
|
||||
tlswritten_total);
|
||||
return CURLE_AGAIN;
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
|
|||
#ifndef CURL_WINDOWS_UWP
|
||||
rc = sread(per->infd, buffer, curlx_uztosi(sz * nmemb));
|
||||
if(rc < 0) {
|
||||
if(SOCKERRNO == SOCKEWOULDBLOCK) {
|
||||
if(SOCK_EAGAIN(SOCKERRNO)) {
|
||||
errno = 0;
|
||||
config->readbusy = TRUE;
|
||||
return CURL_READFUNC_PAUSE;
|
||||
|
|
|
|||
|
|
@ -976,7 +976,7 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req)
|
|||
retry:
|
||||
written = swrite(sock, buffer, num);
|
||||
if(written < 0) {
|
||||
if((SOCKEWOULDBLOCK == SOCKERRNO) || (EAGAIN == SOCKERRNO)) {
|
||||
if(SOCK_EAGAIN(SOCKERRNO)) {
|
||||
curlx_wait_ms(10);
|
||||
goto retry;
|
||||
}
|
||||
|
|
@ -1133,8 +1133,7 @@ static int sws_get_request(curl_socket_t sock, struct sws_httprequest *req)
|
|||
logmsg("Got %zd bytes from client", got);
|
||||
}
|
||||
|
||||
if((got == -1) &&
|
||||
((SOCKERRNO == EAGAIN) || (SOCKERRNO == SOCKEWOULDBLOCK))) {
|
||||
if((got == -1) && SOCK_EAGAIN(SOCKERRNO)) {
|
||||
int rc;
|
||||
fd_set input;
|
||||
fd_set output;
|
||||
|
|
@ -1194,7 +1193,7 @@ static int sws_get_request(curl_socket_t sock, struct sws_httprequest *req)
|
|||
else if(got < 0) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
int error = SOCKERRNO;
|
||||
if(EAGAIN == error || SOCKEWOULDBLOCK == error) {
|
||||
if(SOCK_EAGAIN(error)) {
|
||||
/* nothing to read at the moment */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1335,7 +1334,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
|
|||
|
||||
if(rc) {
|
||||
error = SOCKERRNO;
|
||||
if((error == SOCKEINPROGRESS) || (error == SOCKEWOULDBLOCK)) {
|
||||
if((error == SOCKEINPROGRESS) || SOCK_EAGAIN(error)) {
|
||||
fd_set output;
|
||||
struct timeval timeout = { 0 };
|
||||
timeout.tv_sec = 1; /* 1000 ms */
|
||||
|
|
@ -1353,7 +1352,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
|
|||
error = SOCKERRNO;
|
||||
if((error == 0) || (SOCKEISCONN == error))
|
||||
goto success;
|
||||
else if((error != SOCKEINPROGRESS) && (error != SOCKEWOULDBLOCK))
|
||||
else if((error != SOCKEINPROGRESS) && !SOCK_EAGAIN(error))
|
||||
goto error;
|
||||
}
|
||||
else if(!rc) {
|
||||
|
|
@ -1822,7 +1821,7 @@ static curl_socket_t accept_connection(curl_socket_t sock)
|
|||
|
||||
if(msgsock == CURL_SOCKET_BAD) {
|
||||
error = SOCKERRNO;
|
||||
if(EAGAIN == error || SOCKEWOULDBLOCK == error) {
|
||||
if(SOCK_EAGAIN(error)) {
|
||||
/* nothing to accept */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue