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:
Viktor Szakats 2026-06-08 01:21:44 +02:00
parent 7c51a33877
commit 879a1514c3
No known key found for this signature in database
7 changed files with 63 additions and 95 deletions

View file

@ -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];