Skip to content

Commit 442f2c6

Browse files
committed
Merge pull request #2405 from dscho/mingw-setsockopt
Make sure `errno` is set when socket operations fail
2 parents 92221e4 + e32bc5e commit 442f2c6

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
@@ -2191,26 +2191,158 @@ static void ensure_socket_initialization(void)
21912191
initialized = 1;
21922192
}
21932193

2194+
static int winsock_error_to_errno(DWORD err)
2195+
{
2196+
switch (err) {
2197+
case WSAEINTR: return EINTR;
2198+
case WSAEBADF: return EBADF;
2199+
case WSAEACCES: return EACCES;
2200+
case WSAEFAULT: return EFAULT;
2201+
case WSAEINVAL: return EINVAL;
2202+
case WSAEMFILE: return EMFILE;
2203+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
2204+
case WSAEINPROGRESS: return EINPROGRESS;
2205+
case WSAEALREADY: return EALREADY;
2206+
case WSAENOTSOCK: return ENOTSOCK;
2207+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
2208+
case WSAEMSGSIZE: return EMSGSIZE;
2209+
case WSAEPROTOTYPE: return EPROTOTYPE;
2210+
case WSAENOPROTOOPT: return ENOPROTOOPT;
2211+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
2212+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
2213+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
2214+
case WSAEADDRINUSE: return EADDRINUSE;
2215+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
2216+
case WSAENETDOWN: return ENETDOWN;
2217+
case WSAENETUNREACH: return ENETUNREACH;
2218+
case WSAENETRESET: return ENETRESET;
2219+
case WSAECONNABORTED: return ECONNABORTED;
2220+
case WSAECONNRESET: return ECONNRESET;
2221+
case WSAENOBUFS: return ENOBUFS;
2222+
case WSAEISCONN: return EISCONN;
2223+
case WSAENOTCONN: return ENOTCONN;
2224+
case WSAETIMEDOUT: return ETIMEDOUT;
2225+
case WSAECONNREFUSED: return ECONNREFUSED;
2226+
case WSAELOOP: return ELOOP;
2227+
case WSAENAMETOOLONG: return ENAMETOOLONG;
2228+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
2229+
case WSAENOTEMPTY: return ENOTEMPTY;
2230+
/* No errno equivalent; default to EIO */
2231+
case WSAESOCKTNOSUPPORT:
2232+
case WSAEPFNOSUPPORT:
2233+
case WSAESHUTDOWN:
2234+
case WSAETOOMANYREFS:
2235+
case WSAEHOSTDOWN:
2236+
case WSAEPROCLIM:
2237+
case WSAEUSERS:
2238+
case WSAEDQUOT:
2239+
case WSAESTALE:
2240+
case WSAEREMOTE:
2241+
case WSASYSNOTREADY:
2242+
case WSAVERNOTSUPPORTED:
2243+
case WSANOTINITIALISED:
2244+
case WSAEDISCON:
2245+
case WSAENOMORE:
2246+
case WSAECANCELLED:
2247+
case WSAEINVALIDPROCTABLE:
2248+
case WSAEINVALIDPROVIDER:
2249+
case WSAEPROVIDERFAILEDINIT:
2250+
case WSASYSCALLFAILURE:
2251+
case WSASERVICE_NOT_FOUND:
2252+
case WSATYPE_NOT_FOUND:
2253+
case WSA_E_NO_MORE:
2254+
case WSA_E_CANCELLED:
2255+
case WSAEREFUSED:
2256+
case WSAHOST_NOT_FOUND:
2257+
case WSATRY_AGAIN:
2258+
case WSANO_RECOVERY:
2259+
case WSANO_DATA:
2260+
case WSA_QOS_RECEIVERS:
2261+
case WSA_QOS_SENDERS:
2262+
case WSA_QOS_NO_SENDERS:
2263+
case WSA_QOS_NO_RECEIVERS:
2264+
case WSA_QOS_REQUEST_CONFIRMED:
2265+
case WSA_QOS_ADMISSION_FAILURE:
2266+
case WSA_QOS_POLICY_FAILURE:
2267+
case WSA_QOS_BAD_STYLE:
2268+
case WSA_QOS_BAD_OBJECT:
2269+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
2270+
case WSA_QOS_GENERIC_ERROR:
2271+
case WSA_QOS_ESERVICETYPE:
2272+
case WSA_QOS_EFLOWSPEC:
2273+
case WSA_QOS_EPROVSPECBUF:
2274+
case WSA_QOS_EFILTERSTYLE:
2275+
case WSA_QOS_EFILTERTYPE:
2276+
case WSA_QOS_EFILTERCOUNT:
2277+
case WSA_QOS_EOBJLENGTH:
2278+
case WSA_QOS_EFLOWCOUNT:
2279+
#ifndef _MSC_VER
2280+
case WSA_QOS_EUNKNOWNPSOBJ:
2281+
#endif
2282+
case WSA_QOS_EPOLICYOBJ:
2283+
case WSA_QOS_EFLOWDESC:
2284+
case WSA_QOS_EPSFLOWSPEC:
2285+
case WSA_QOS_EPSFILTERSPEC:
2286+
case WSA_QOS_ESDMODEOBJ:
2287+
case WSA_QOS_ESHAPERATEOBJ:
2288+
case WSA_QOS_RESERVED_PETYPE:
2289+
default: return EIO;
2290+
}
2291+
}
2292+
2293+
/*
2294+
* On Windows, `errno` is a global macro to a function call.
2295+
* This makes it difficult to debug and single-step our mappings.
2296+
*/
2297+
static inline void set_wsa_errno(void)
2298+
{
2299+
DWORD wsa = WSAGetLastError();
2300+
int e = winsock_error_to_errno(wsa);
2301+
errno = e;
2302+
2303+
#ifdef DEBUG_WSA_ERRNO
2304+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2305+
fflush(stderr);
2306+
#endif
2307+
}
2308+
2309+
static inline int winsock_return(int ret)
2310+
{
2311+
if (ret < 0)
2312+
set_wsa_errno();
2313+
2314+
return ret;
2315+
}
2316+
2317+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2318+
21942319
#undef gethostname
21952320
int mingw_gethostname(char *name, int namelen)
21962321
{
2197-
ensure_socket_initialization();
2198-
return gethostname(name, namelen);
2322+
ensure_socket_initialization();
2323+
WINSOCK_RETURN(gethostname(name, namelen));
21992324
}
22002325

22012326
#undef gethostbyname
22022327
struct hostent *mingw_gethostbyname(const char *host)
22032328
{
2329+
struct hostent *ret;
2330+
22042331
ensure_socket_initialization();
2205-
return gethostbyname(host);
2332+
2333+
ret = gethostbyname(host);
2334+
if (!ret)
2335+
set_wsa_errno();
2336+
2337+
return ret;
22062338
}
22072339

22082340
#undef getaddrinfo
22092341
int mingw_getaddrinfo(const char *node, const char *service,
22102342
const struct addrinfo *hints, struct addrinfo **res)
22112343
{
22122344
ensure_socket_initialization();
2213-
return getaddrinfo(node, service, hints, res);
2345+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
22142346
}
22152347

22162348
int mingw_socket(int domain, int type, int protocol)
@@ -2230,7 +2362,7 @@ int mingw_socket(int domain, int type, int protocol)
22302362
* in errno so that _if_ someone looks up the code somewhere,
22312363
* then it is at least the number that are usually listed.
22322364
*/
2233-
errno = WSAGetLastError();
2365+
set_wsa_errno();
22342366
return -1;
22352367
}
22362368
/* convert into a file descriptor */
@@ -2246,35 +2378,35 @@ int mingw_socket(int domain, int type, int protocol)
22462378
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
22472379
{
22482380
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2249-
return connect(s, sa, sz);
2381+
WINSOCK_RETURN(connect(s, sa, sz));
22502382
}
22512383

22522384
#undef bind
22532385
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
22542386
{
22552387
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2256-
return bind(s, sa, sz);
2388+
WINSOCK_RETURN(bind(s, sa, sz));
22572389
}
22582390

22592391
#undef setsockopt
22602392
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
22612393
{
22622394
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2263-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2395+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
22642396
}
22652397

22662398
#undef shutdown
22672399
int mingw_shutdown(int sockfd, int how)
22682400
{
22692401
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2270-
return shutdown(s, how);
2402+
WINSOCK_RETURN(shutdown(s, how));
22712403
}
22722404

22732405
#undef listen
22742406
int mingw_listen(int sockfd, int backlog)
22752407
{
22762408
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2277-
return listen(s, backlog);
2409+
WINSOCK_RETURN(listen(s, backlog));
22782410
}
22792411

22802412
#undef accept
@@ -2285,6 +2417,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
22852417
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
22862418
SOCKET s2 = accept(s1, sa, sz);
22872419

2420+
if (s2 == INVALID_SOCKET) {
2421+
set_wsa_errno();
2422+
return -1;
2423+
}
2424+
22882425
/* convert into a file descriptor */
22892426
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
22902427
int err = errno;

0 commit comments

Comments
 (0)