Skip to content

Commit f87f254

Browse files
dschomjcheetham
authored andcommitted
Merge pull request #2405 from dscho/mingw-setsockopt
Make sure `errno` is set when socket operations fail
2 parents 29416ed + 7691240 commit f87f254

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
@@ -2032,26 +2032,158 @@ static void ensure_socket_initialization(void)
20322032
initialized = 1;
20332033
}
20342034

2035+
static int winsock_error_to_errno(DWORD err)
2036+
{
2037+
switch (err) {
2038+
case WSAEINTR: return EINTR;
2039+
case WSAEBADF: return EBADF;
2040+
case WSAEACCES: return EACCES;
2041+
case WSAEFAULT: return EFAULT;
2042+
case WSAEINVAL: return EINVAL;
2043+
case WSAEMFILE: return EMFILE;
2044+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
2045+
case WSAEINPROGRESS: return EINPROGRESS;
2046+
case WSAEALREADY: return EALREADY;
2047+
case WSAENOTSOCK: return ENOTSOCK;
2048+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
2049+
case WSAEMSGSIZE: return EMSGSIZE;
2050+
case WSAEPROTOTYPE: return EPROTOTYPE;
2051+
case WSAENOPROTOOPT: return ENOPROTOOPT;
2052+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
2053+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
2054+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
2055+
case WSAEADDRINUSE: return EADDRINUSE;
2056+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
2057+
case WSAENETDOWN: return ENETDOWN;
2058+
case WSAENETUNREACH: return ENETUNREACH;
2059+
case WSAENETRESET: return ENETRESET;
2060+
case WSAECONNABORTED: return ECONNABORTED;
2061+
case WSAECONNRESET: return ECONNRESET;
2062+
case WSAENOBUFS: return ENOBUFS;
2063+
case WSAEISCONN: return EISCONN;
2064+
case WSAENOTCONN: return ENOTCONN;
2065+
case WSAETIMEDOUT: return ETIMEDOUT;
2066+
case WSAECONNREFUSED: return ECONNREFUSED;
2067+
case WSAELOOP: return ELOOP;
2068+
case WSAENAMETOOLONG: return ENAMETOOLONG;
2069+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
2070+
case WSAENOTEMPTY: return ENOTEMPTY;
2071+
/* No errno equivalent; default to EIO */
2072+
case WSAESOCKTNOSUPPORT:
2073+
case WSAEPFNOSUPPORT:
2074+
case WSAESHUTDOWN:
2075+
case WSAETOOMANYREFS:
2076+
case WSAEHOSTDOWN:
2077+
case WSAEPROCLIM:
2078+
case WSAEUSERS:
2079+
case WSAEDQUOT:
2080+
case WSAESTALE:
2081+
case WSAEREMOTE:
2082+
case WSASYSNOTREADY:
2083+
case WSAVERNOTSUPPORTED:
2084+
case WSANOTINITIALISED:
2085+
case WSAEDISCON:
2086+
case WSAENOMORE:
2087+
case WSAECANCELLED:
2088+
case WSAEINVALIDPROCTABLE:
2089+
case WSAEINVALIDPROVIDER:
2090+
case WSAEPROVIDERFAILEDINIT:
2091+
case WSASYSCALLFAILURE:
2092+
case WSASERVICE_NOT_FOUND:
2093+
case WSATYPE_NOT_FOUND:
2094+
case WSA_E_NO_MORE:
2095+
case WSA_E_CANCELLED:
2096+
case WSAEREFUSED:
2097+
case WSAHOST_NOT_FOUND:
2098+
case WSATRY_AGAIN:
2099+
case WSANO_RECOVERY:
2100+
case WSANO_DATA:
2101+
case WSA_QOS_RECEIVERS:
2102+
case WSA_QOS_SENDERS:
2103+
case WSA_QOS_NO_SENDERS:
2104+
case WSA_QOS_NO_RECEIVERS:
2105+
case WSA_QOS_REQUEST_CONFIRMED:
2106+
case WSA_QOS_ADMISSION_FAILURE:
2107+
case WSA_QOS_POLICY_FAILURE:
2108+
case WSA_QOS_BAD_STYLE:
2109+
case WSA_QOS_BAD_OBJECT:
2110+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
2111+
case WSA_QOS_GENERIC_ERROR:
2112+
case WSA_QOS_ESERVICETYPE:
2113+
case WSA_QOS_EFLOWSPEC:
2114+
case WSA_QOS_EPROVSPECBUF:
2115+
case WSA_QOS_EFILTERSTYLE:
2116+
case WSA_QOS_EFILTERTYPE:
2117+
case WSA_QOS_EFILTERCOUNT:
2118+
case WSA_QOS_EOBJLENGTH:
2119+
case WSA_QOS_EFLOWCOUNT:
2120+
#ifndef _MSC_VER
2121+
case WSA_QOS_EUNKNOWNPSOBJ:
2122+
#endif
2123+
case WSA_QOS_EPOLICYOBJ:
2124+
case WSA_QOS_EFLOWDESC:
2125+
case WSA_QOS_EPSFLOWSPEC:
2126+
case WSA_QOS_EPSFILTERSPEC:
2127+
case WSA_QOS_ESDMODEOBJ:
2128+
case WSA_QOS_ESHAPERATEOBJ:
2129+
case WSA_QOS_RESERVED_PETYPE:
2130+
default: return EIO;
2131+
}
2132+
}
2133+
2134+
/*
2135+
* On Windows, `errno` is a global macro to a function call.
2136+
* This makes it difficult to debug and single-step our mappings.
2137+
*/
2138+
static inline void set_wsa_errno(void)
2139+
{
2140+
DWORD wsa = WSAGetLastError();
2141+
int e = winsock_error_to_errno(wsa);
2142+
errno = e;
2143+
2144+
#ifdef DEBUG_WSA_ERRNO
2145+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2146+
fflush(stderr);
2147+
#endif
2148+
}
2149+
2150+
static inline int winsock_return(int ret)
2151+
{
2152+
if (ret < 0)
2153+
set_wsa_errno();
2154+
2155+
return ret;
2156+
}
2157+
2158+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2159+
20352160
#undef gethostname
20362161
int mingw_gethostname(char *name, int namelen)
20372162
{
2038-
ensure_socket_initialization();
2039-
return gethostname(name, namelen);
2163+
ensure_socket_initialization();
2164+
WINSOCK_RETURN(gethostname(name, namelen));
20402165
}
20412166

20422167
#undef gethostbyname
20432168
struct hostent *mingw_gethostbyname(const char *host)
20442169
{
2170+
struct hostent *ret;
2171+
20452172
ensure_socket_initialization();
2046-
return gethostbyname(host);
2173+
2174+
ret = gethostbyname(host);
2175+
if (!ret)
2176+
set_wsa_errno();
2177+
2178+
return ret;
20472179
}
20482180

20492181
#undef getaddrinfo
20502182
int mingw_getaddrinfo(const char *node, const char *service,
20512183
const struct addrinfo *hints, struct addrinfo **res)
20522184
{
20532185
ensure_socket_initialization();
2054-
return getaddrinfo(node, service, hints, res);
2186+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
20552187
}
20562188

20572189
int mingw_socket(int domain, int type, int protocol)
@@ -2071,7 +2203,7 @@ int mingw_socket(int domain, int type, int protocol)
20712203
* in errno so that _if_ someone looks up the code somewhere,
20722204
* then it is at least the number that are usually listed.
20732205
*/
2074-
errno = WSAGetLastError();
2206+
set_wsa_errno();
20752207
return -1;
20762208
}
20772209
/* convert into a file descriptor */
@@ -2087,35 +2219,35 @@ int mingw_socket(int domain, int type, int protocol)
20872219
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
20882220
{
20892221
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2090-
return connect(s, sa, sz);
2222+
WINSOCK_RETURN(connect(s, sa, sz));
20912223
}
20922224

20932225
#undef bind
20942226
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
20952227
{
20962228
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2097-
return bind(s, sa, sz);
2229+
WINSOCK_RETURN(bind(s, sa, sz));
20982230
}
20992231

21002232
#undef setsockopt
21012233
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
21022234
{
21032235
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2104-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2236+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
21052237
}
21062238

21072239
#undef shutdown
21082240
int mingw_shutdown(int sockfd, int how)
21092241
{
21102242
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2111-
return shutdown(s, how);
2243+
WINSOCK_RETURN(shutdown(s, how));
21122244
}
21132245

21142246
#undef listen
21152247
int mingw_listen(int sockfd, int backlog)
21162248
{
21172249
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2118-
return listen(s, backlog);
2250+
WINSOCK_RETURN(listen(s, backlog));
21192251
}
21202252

21212253
#undef accept
@@ -2126,6 +2258,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
21262258
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
21272259
SOCKET s2 = accept(s1, sa, sz);
21282260

2261+
if (s2 == INVALID_SOCKET) {
2262+
set_wsa_errno();
2263+
return -1;
2264+
}
2265+
21292266
/* convert into a file descriptor */
21302267
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
21312268
int err = errno;

0 commit comments

Comments
 (0)