Skip to content

Commit 0c9fc43

Browse files
dschoGit for Windows Build Agent
authored andcommitted
mingw: make sure errno is set correctly when socket operations fail
The winsock2 library provides functions that work on different data types than file descriptors, therefore we wrap them. But that is not the only difference: they also do not set `errno` but expect the callers to enquire about errors via `WSAGetLastError()`. Let's translate that into appropriate `errno` values whenever the socket operations fail so that Git's code base does not have to change its expectations. This closes #2404 Helped-by: Jeff Hostetler <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 529e7fb commit 0c9fc43

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
@@ -1907,26 +1907,158 @@ static void ensure_socket_initialization(void)
19071907
initialized = 1;
19081908
}
19091909

1910+
static int winsock_error_to_errno(DWORD err)
1911+
{
1912+
switch (err) {
1913+
case WSAEINTR: return EINTR;
1914+
case WSAEBADF: return EBADF;
1915+
case WSAEACCES: return EACCES;
1916+
case WSAEFAULT: return EFAULT;
1917+
case WSAEINVAL: return EINVAL;
1918+
case WSAEMFILE: return EMFILE;
1919+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
1920+
case WSAEINPROGRESS: return EINPROGRESS;
1921+
case WSAEALREADY: return EALREADY;
1922+
case WSAENOTSOCK: return ENOTSOCK;
1923+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
1924+
case WSAEMSGSIZE: return EMSGSIZE;
1925+
case WSAEPROTOTYPE: return EPROTOTYPE;
1926+
case WSAENOPROTOOPT: return ENOPROTOOPT;
1927+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
1928+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
1929+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
1930+
case WSAEADDRINUSE: return EADDRINUSE;
1931+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
1932+
case WSAENETDOWN: return ENETDOWN;
1933+
case WSAENETUNREACH: return ENETUNREACH;
1934+
case WSAENETRESET: return ENETRESET;
1935+
case WSAECONNABORTED: return ECONNABORTED;
1936+
case WSAECONNRESET: return ECONNRESET;
1937+
case WSAENOBUFS: return ENOBUFS;
1938+
case WSAEISCONN: return EISCONN;
1939+
case WSAENOTCONN: return ENOTCONN;
1940+
case WSAETIMEDOUT: return ETIMEDOUT;
1941+
case WSAECONNREFUSED: return ECONNREFUSED;
1942+
case WSAELOOP: return ELOOP;
1943+
case WSAENAMETOOLONG: return ENAMETOOLONG;
1944+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
1945+
case WSAENOTEMPTY: return ENOTEMPTY;
1946+
/* No errno equivalent; default to EIO */
1947+
case WSAESOCKTNOSUPPORT:
1948+
case WSAEPFNOSUPPORT:
1949+
case WSAESHUTDOWN:
1950+
case WSAETOOMANYREFS:
1951+
case WSAEHOSTDOWN:
1952+
case WSAEPROCLIM:
1953+
case WSAEUSERS:
1954+
case WSAEDQUOT:
1955+
case WSAESTALE:
1956+
case WSAEREMOTE:
1957+
case WSASYSNOTREADY:
1958+
case WSAVERNOTSUPPORTED:
1959+
case WSANOTINITIALISED:
1960+
case WSAEDISCON:
1961+
case WSAENOMORE:
1962+
case WSAECANCELLED:
1963+
case WSAEINVALIDPROCTABLE:
1964+
case WSAEINVALIDPROVIDER:
1965+
case WSAEPROVIDERFAILEDINIT:
1966+
case WSASYSCALLFAILURE:
1967+
case WSASERVICE_NOT_FOUND:
1968+
case WSATYPE_NOT_FOUND:
1969+
case WSA_E_NO_MORE:
1970+
case WSA_E_CANCELLED:
1971+
case WSAEREFUSED:
1972+
case WSAHOST_NOT_FOUND:
1973+
case WSATRY_AGAIN:
1974+
case WSANO_RECOVERY:
1975+
case WSANO_DATA:
1976+
case WSA_QOS_RECEIVERS:
1977+
case WSA_QOS_SENDERS:
1978+
case WSA_QOS_NO_SENDERS:
1979+
case WSA_QOS_NO_RECEIVERS:
1980+
case WSA_QOS_REQUEST_CONFIRMED:
1981+
case WSA_QOS_ADMISSION_FAILURE:
1982+
case WSA_QOS_POLICY_FAILURE:
1983+
case WSA_QOS_BAD_STYLE:
1984+
case WSA_QOS_BAD_OBJECT:
1985+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
1986+
case WSA_QOS_GENERIC_ERROR:
1987+
case WSA_QOS_ESERVICETYPE:
1988+
case WSA_QOS_EFLOWSPEC:
1989+
case WSA_QOS_EPROVSPECBUF:
1990+
case WSA_QOS_EFILTERSTYLE:
1991+
case WSA_QOS_EFILTERTYPE:
1992+
case WSA_QOS_EFILTERCOUNT:
1993+
case WSA_QOS_EOBJLENGTH:
1994+
case WSA_QOS_EFLOWCOUNT:
1995+
#ifndef _MSC_VER
1996+
case WSA_QOS_EUNKNOWNPSOBJ:
1997+
#endif
1998+
case WSA_QOS_EPOLICYOBJ:
1999+
case WSA_QOS_EFLOWDESC:
2000+
case WSA_QOS_EPSFLOWSPEC:
2001+
case WSA_QOS_EPSFILTERSPEC:
2002+
case WSA_QOS_ESDMODEOBJ:
2003+
case WSA_QOS_ESHAPERATEOBJ:
2004+
case WSA_QOS_RESERVED_PETYPE:
2005+
default: return EIO;
2006+
}
2007+
}
2008+
2009+
/*
2010+
* On Windows, `errno` is a global macro to a function call.
2011+
* This makes it difficult to debug and single-step our mappings.
2012+
*/
2013+
static inline void set_wsa_errno(void)
2014+
{
2015+
DWORD wsa = WSAGetLastError();
2016+
int e = winsock_error_to_errno(wsa);
2017+
errno = e;
2018+
2019+
#ifdef DEBUG_WSA_ERRNO
2020+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2021+
fflush(stderr);
2022+
#endif
2023+
}
2024+
2025+
static inline int winsock_return(int ret)
2026+
{
2027+
if (ret < 0)
2028+
set_wsa_errno();
2029+
2030+
return ret;
2031+
}
2032+
2033+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2034+
19102035
#undef gethostname
19112036
int mingw_gethostname(char *name, int namelen)
19122037
{
1913-
ensure_socket_initialization();
1914-
return gethostname(name, namelen);
2038+
ensure_socket_initialization();
2039+
WINSOCK_RETURN(gethostname(name, namelen));
19152040
}
19162041

19172042
#undef gethostbyname
19182043
struct hostent *mingw_gethostbyname(const char *host)
19192044
{
2045+
struct hostent *ret;
2046+
19202047
ensure_socket_initialization();
1921-
return gethostbyname(host);
2048+
2049+
ret = gethostbyname(host);
2050+
if (!ret)
2051+
set_wsa_errno();
2052+
2053+
return ret;
19222054
}
19232055

19242056
#undef getaddrinfo
19252057
int mingw_getaddrinfo(const char *node, const char *service,
19262058
const struct addrinfo *hints, struct addrinfo **res)
19272059
{
19282060
ensure_socket_initialization();
1929-
return getaddrinfo(node, service, hints, res);
2061+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
19302062
}
19312063

19322064
int mingw_socket(int domain, int type, int protocol)
@@ -1946,7 +2078,7 @@ int mingw_socket(int domain, int type, int protocol)
19462078
* in errno so that _if_ someone looks up the code somewhere,
19472079
* then it is at least the number that are usually listed.
19482080
*/
1949-
errno = WSAGetLastError();
2081+
set_wsa_errno();
19502082
return -1;
19512083
}
19522084
/* convert into a file descriptor */
@@ -1962,35 +2094,35 @@ int mingw_socket(int domain, int type, int protocol)
19622094
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
19632095
{
19642096
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
1965-
return connect(s, sa, sz);
2097+
WINSOCK_RETURN(connect(s, sa, sz));
19662098
}
19672099

19682100
#undef bind
19692101
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
19702102
{
19712103
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
1972-
return bind(s, sa, sz);
2104+
WINSOCK_RETURN(bind(s, sa, sz));
19732105
}
19742106

19752107
#undef setsockopt
19762108
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
19772109
{
19782110
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
1979-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2111+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
19802112
}
19812113

19822114
#undef shutdown
19832115
int mingw_shutdown(int sockfd, int how)
19842116
{
19852117
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
1986-
return shutdown(s, how);
2118+
WINSOCK_RETURN(shutdown(s, how));
19872119
}
19882120

19892121
#undef listen
19902122
int mingw_listen(int sockfd, int backlog)
19912123
{
19922124
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
1993-
return listen(s, backlog);
2125+
WINSOCK_RETURN(listen(s, backlog));
19942126
}
19952127

19962128
#undef accept
@@ -2001,6 +2133,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
20012133
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
20022134
SOCKET s2 = accept(s1, sa, sz);
20032135

2136+
if (s2 == INVALID_SOCKET) {
2137+
set_wsa_errno();
2138+
return -1;
2139+
}
2140+
20042141
/* convert into a file descriptor */
20052142
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
20062143
int err = errno;

0 commit comments

Comments
 (0)