Skip to content

Commit 8315da4

Browse files
dschoGit for Windows Build Agent
authored andcommitted
Merge pull request #2405 from dscho/mingw-setsockopt
Make sure `errno` is set when socket operations fail
2 parents c928039 + cd06b88 commit 8315da4

File tree

1 file changed

+147
-10
lines changed

1 file changed

+147
-10
lines changed

compat/mingw.c

Lines changed: 147 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,26 +1979,158 @@ static void ensure_socket_initialization(void)
19791979
initialized = 1;
19801980
}
19811981

1982+
static int winsock_error_to_errno(DWORD err)
1983+
{
1984+
switch (err) {
1985+
case WSAEINTR: return EINTR;
1986+
case WSAEBADF: return EBADF;
1987+
case WSAEACCES: return EACCES;
1988+
case WSAEFAULT: return EFAULT;
1989+
case WSAEINVAL: return EINVAL;
1990+
case WSAEMFILE: return EMFILE;
1991+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
1992+
case WSAEINPROGRESS: return EINPROGRESS;
1993+
case WSAEALREADY: return EALREADY;
1994+
case WSAENOTSOCK: return ENOTSOCK;
1995+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
1996+
case WSAEMSGSIZE: return EMSGSIZE;
1997+
case WSAEPROTOTYPE: return EPROTOTYPE;
1998+
case WSAENOPROTOOPT: return ENOPROTOOPT;
1999+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
2000+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
2001+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
2002+
case WSAEADDRINUSE: return EADDRINUSE;
2003+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
2004+
case WSAENETDOWN: return ENETDOWN;
2005+
case WSAENETUNREACH: return ENETUNREACH;
2006+
case WSAENETRESET: return ENETRESET;
2007+
case WSAECONNABORTED: return ECONNABORTED;
2008+
case WSAECONNRESET: return ECONNRESET;
2009+
case WSAENOBUFS: return ENOBUFS;
2010+
case WSAEISCONN: return EISCONN;
2011+
case WSAENOTCONN: return ENOTCONN;
2012+
case WSAETIMEDOUT: return ETIMEDOUT;
2013+
case WSAECONNREFUSED: return ECONNREFUSED;
2014+
case WSAELOOP: return ELOOP;
2015+
case WSAENAMETOOLONG: return ENAMETOOLONG;
2016+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
2017+
case WSAENOTEMPTY: return ENOTEMPTY;
2018+
/* No errno equivalent; default to EIO */
2019+
case WSAESOCKTNOSUPPORT:
2020+
case WSAEPFNOSUPPORT:
2021+
case WSAESHUTDOWN:
2022+
case WSAETOOMANYREFS:
2023+
case WSAEHOSTDOWN:
2024+
case WSAEPROCLIM:
2025+
case WSAEUSERS:
2026+
case WSAEDQUOT:
2027+
case WSAESTALE:
2028+
case WSAEREMOTE:
2029+
case WSASYSNOTREADY:
2030+
case WSAVERNOTSUPPORTED:
2031+
case WSANOTINITIALISED:
2032+
case WSAEDISCON:
2033+
case WSAENOMORE:
2034+
case WSAECANCELLED:
2035+
case WSAEINVALIDPROCTABLE:
2036+
case WSAEINVALIDPROVIDER:
2037+
case WSAEPROVIDERFAILEDINIT:
2038+
case WSASYSCALLFAILURE:
2039+
case WSASERVICE_NOT_FOUND:
2040+
case WSATYPE_NOT_FOUND:
2041+
case WSA_E_NO_MORE:
2042+
case WSA_E_CANCELLED:
2043+
case WSAEREFUSED:
2044+
case WSAHOST_NOT_FOUND:
2045+
case WSATRY_AGAIN:
2046+
case WSANO_RECOVERY:
2047+
case WSANO_DATA:
2048+
case WSA_QOS_RECEIVERS:
2049+
case WSA_QOS_SENDERS:
2050+
case WSA_QOS_NO_SENDERS:
2051+
case WSA_QOS_NO_RECEIVERS:
2052+
case WSA_QOS_REQUEST_CONFIRMED:
2053+
case WSA_QOS_ADMISSION_FAILURE:
2054+
case WSA_QOS_POLICY_FAILURE:
2055+
case WSA_QOS_BAD_STYLE:
2056+
case WSA_QOS_BAD_OBJECT:
2057+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
2058+
case WSA_QOS_GENERIC_ERROR:
2059+
case WSA_QOS_ESERVICETYPE:
2060+
case WSA_QOS_EFLOWSPEC:
2061+
case WSA_QOS_EPROVSPECBUF:
2062+
case WSA_QOS_EFILTERSTYLE:
2063+
case WSA_QOS_EFILTERTYPE:
2064+
case WSA_QOS_EFILTERCOUNT:
2065+
case WSA_QOS_EOBJLENGTH:
2066+
case WSA_QOS_EFLOWCOUNT:
2067+
#ifndef _MSC_VER
2068+
case WSA_QOS_EUNKNOWNPSOBJ:
2069+
#endif
2070+
case WSA_QOS_EPOLICYOBJ:
2071+
case WSA_QOS_EFLOWDESC:
2072+
case WSA_QOS_EPSFLOWSPEC:
2073+
case WSA_QOS_EPSFILTERSPEC:
2074+
case WSA_QOS_ESDMODEOBJ:
2075+
case WSA_QOS_ESHAPERATEOBJ:
2076+
case WSA_QOS_RESERVED_PETYPE:
2077+
default: return EIO;
2078+
}
2079+
}
2080+
2081+
/*
2082+
* On Windows, `errno` is a global macro to a function call.
2083+
* This makes it difficult to debug and single-step our mappings.
2084+
*/
2085+
static inline void set_wsa_errno(void)
2086+
{
2087+
DWORD wsa = WSAGetLastError();
2088+
int e = winsock_error_to_errno(wsa);
2089+
errno = e;
2090+
2091+
#ifdef DEBUG_WSA_ERRNO
2092+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2093+
fflush(stderr);
2094+
#endif
2095+
}
2096+
2097+
static inline int winsock_return(int ret)
2098+
{
2099+
if (ret < 0)
2100+
set_wsa_errno();
2101+
2102+
return ret;
2103+
}
2104+
2105+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2106+
19822107
#undef gethostname
19832108
int mingw_gethostname(char *name, int namelen)
19842109
{
1985-
ensure_socket_initialization();
1986-
return gethostname(name, namelen);
2110+
ensure_socket_initialization();
2111+
WINSOCK_RETURN(gethostname(name, namelen));
19872112
}
19882113

19892114
#undef gethostbyname
19902115
struct hostent *mingw_gethostbyname(const char *host)
19912116
{
2117+
struct hostent *ret;
2118+
19922119
ensure_socket_initialization();
1993-
return gethostbyname(host);
2120+
2121+
ret = gethostbyname(host);
2122+
if (!ret)
2123+
set_wsa_errno();
2124+
2125+
return ret;
19942126
}
19952127

19962128
#undef getaddrinfo
19972129
int mingw_getaddrinfo(const char *node, const char *service,
19982130
const struct addrinfo *hints, struct addrinfo **res)
19992131
{
20002132
ensure_socket_initialization();
2001-
return getaddrinfo(node, service, hints, res);
2133+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
20022134
}
20032135

20042136
int mingw_socket(int domain, int type, int protocol)
@@ -2018,7 +2150,7 @@ int mingw_socket(int domain, int type, int protocol)
20182150
* in errno so that _if_ someone looks up the code somewhere,
20192151
* then it is at least the number that are usually listed.
20202152
*/
2021-
errno = WSAGetLastError();
2153+
set_wsa_errno();
20222154
return -1;
20232155
}
20242156
/* convert into a file descriptor */
@@ -2034,35 +2166,35 @@ int mingw_socket(int domain, int type, int protocol)
20342166
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
20352167
{
20362168
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2037-
return connect(s, sa, sz);
2169+
WINSOCK_RETURN(connect(s, sa, sz));
20382170
}
20392171

20402172
#undef bind
20412173
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
20422174
{
20432175
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2044-
return bind(s, sa, sz);
2176+
WINSOCK_RETURN(bind(s, sa, sz));
20452177
}
20462178

20472179
#undef setsockopt
20482180
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
20492181
{
20502182
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2051-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2183+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
20522184
}
20532185

20542186
#undef shutdown
20552187
int mingw_shutdown(int sockfd, int how)
20562188
{
20572189
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2058-
return shutdown(s, how);
2190+
WINSOCK_RETURN(shutdown(s, how));
20592191
}
20602192

20612193
#undef listen
20622194
int mingw_listen(int sockfd, int backlog)
20632195
{
20642196
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2065-
return listen(s, backlog);
2197+
WINSOCK_RETURN(listen(s, backlog));
20662198
}
20672199

20682200
#undef accept
@@ -2073,6 +2205,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
20732205
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
20742206
SOCKET s2 = accept(s1, sa, sz);
20752207

2208+
if (s2 == INVALID_SOCKET) {
2209+
set_wsa_errno();
2210+
return -1;
2211+
}
2212+
20762213
/* convert into a file descriptor */
20772214
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
20782215
int err = errno;

0 commit comments

Comments
 (0)