Skip to content

Commit ed025b5

Browse files
dschoGit for Windows Build Agent
authored and
Git for Windows Build Agent
committed
Merge pull request #2405 from dscho/mingw-setsockopt
Make sure `errno` is set when socket operations fail
2 parents f0ec9ed + 91e60e5 commit ed025b5

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
@@ -2186,26 +2186,158 @@ static void ensure_socket_initialization(void)
21862186
initialized = 1;
21872187
}
21882188

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

21962321
#undef gethostbyname
21972322
struct hostent *mingw_gethostbyname(const char *host)
21982323
{
2324+
struct hostent *ret;
2325+
21992326
ensure_socket_initialization();
2200-
return gethostbyname(host);
2327+
2328+
ret = gethostbyname(host);
2329+
if (!ret)
2330+
set_wsa_errno();
2331+
2332+
return ret;
22012333
}
22022334

22032335
#undef getaddrinfo
22042336
int mingw_getaddrinfo(const char *node, const char *service,
22052337
const struct addrinfo *hints, struct addrinfo **res)
22062338
{
22072339
ensure_socket_initialization();
2208-
return getaddrinfo(node, service, hints, res);
2340+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
22092341
}
22102342

22112343
int mingw_socket(int domain, int type, int protocol)
@@ -2225,7 +2357,7 @@ int mingw_socket(int domain, int type, int protocol)
22252357
* in errno so that _if_ someone looks up the code somewhere,
22262358
* then it is at least the number that are usually listed.
22272359
*/
2228-
errno = WSAGetLastError();
2360+
set_wsa_errno();
22292361
return -1;
22302362
}
22312363
/* convert into a file descriptor */
@@ -2241,35 +2373,35 @@ int mingw_socket(int domain, int type, int protocol)
22412373
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
22422374
{
22432375
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2244-
return connect(s, sa, sz);
2376+
WINSOCK_RETURN(connect(s, sa, sz));
22452377
}
22462378

22472379
#undef bind
22482380
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
22492381
{
22502382
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2251-
return bind(s, sa, sz);
2383+
WINSOCK_RETURN(bind(s, sa, sz));
22522384
}
22532385

22542386
#undef setsockopt
22552387
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
22562388
{
22572389
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2258-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2390+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
22592391
}
22602392

22612393
#undef shutdown
22622394
int mingw_shutdown(int sockfd, int how)
22632395
{
22642396
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2265-
return shutdown(s, how);
2397+
WINSOCK_RETURN(shutdown(s, how));
22662398
}
22672399

22682400
#undef listen
22692401
int mingw_listen(int sockfd, int backlog)
22702402
{
22712403
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2272-
return listen(s, backlog);
2404+
WINSOCK_RETURN(listen(s, backlog));
22732405
}
22742406

22752407
#undef accept
@@ -2280,6 +2412,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
22802412
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
22812413
SOCKET s2 = accept(s1, sa, sz);
22822414

2415+
if (s2 == INVALID_SOCKET) {
2416+
set_wsa_errno();
2417+
return -1;
2418+
}
2419+
22832420
/* convert into a file descriptor */
22842421
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
22852422
int err = errno;

0 commit comments

Comments
 (0)