Skip to content

Commit dbff26b

Browse files
dschoGit for Windows Build Agent
authored andcommitted
credential-cache: handle ECONNREFUSED gracefully (#5329)
I should probably add some tests for this.
2 parents a5f2a23 + 695072a commit dbff26b

File tree

7 files changed

+313
-21
lines changed

7 files changed

+313
-21
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,7 @@ CLAR_TEST_SUITES += u-example-decorate
15151515
CLAR_TEST_SUITES += u-hash
15161516
CLAR_TEST_SUITES += u-hashmap
15171517
CLAR_TEST_SUITES += u-mem-pool
1518+
CLAR_TEST_SUITES += u-mingw
15181519
CLAR_TEST_SUITES += u-oid-array
15191520
CLAR_TEST_SUITES += u-oidmap
15201521
CLAR_TEST_SUITES += u-oidtree

builtin/credential-cache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ static int connection_closed(int error)
2323

2424
static int connection_fatally_broken(int error)
2525
{
26-
return (error != ENOENT) && (error != ENETDOWN);
26+
return (error != ENOENT) && (error != ENETDOWN) && (error != ECONNREFUSED);
2727
}
2828

2929
#else

compat/mingw-posix.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ int mingw_socket(int domain, int type, int protocol);
290290
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
291291
#define connect mingw_connect
292292

293+
char *mingw_strerror(int errnum);
294+
#ifndef _UCRT
295+
#define strerror mingw_strerror
296+
#endif
297+
293298
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
294299
#define bind mingw_bind
295300

compat/mingw.c

Lines changed: 232 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,26 +2187,243 @@ static void ensure_socket_initialization(void)
21872187
initialized = 1;
21882188
}
21892189

2190+
static int winsock_error_to_errno(DWORD err)
2191+
{
2192+
switch (err) {
2193+
case WSAEINTR: return EINTR;
2194+
case WSAEBADF: return EBADF;
2195+
case WSAEACCES: return EACCES;
2196+
case WSAEFAULT: return EFAULT;
2197+
case WSAEINVAL: return EINVAL;
2198+
case WSAEMFILE: return EMFILE;
2199+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
2200+
case WSAEINPROGRESS: return EINPROGRESS;
2201+
case WSAEALREADY: return EALREADY;
2202+
case WSAENOTSOCK: return ENOTSOCK;
2203+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
2204+
case WSAEMSGSIZE: return EMSGSIZE;
2205+
case WSAEPROTOTYPE: return EPROTOTYPE;
2206+
case WSAENOPROTOOPT: return ENOPROTOOPT;
2207+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
2208+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
2209+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
2210+
case WSAEADDRINUSE: return EADDRINUSE;
2211+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
2212+
case WSAENETDOWN: return ENETDOWN;
2213+
case WSAENETUNREACH: return ENETUNREACH;
2214+
case WSAENETRESET: return ENETRESET;
2215+
case WSAECONNABORTED: return ECONNABORTED;
2216+
case WSAECONNRESET: return ECONNRESET;
2217+
case WSAENOBUFS: return ENOBUFS;
2218+
case WSAEISCONN: return EISCONN;
2219+
case WSAENOTCONN: return ENOTCONN;
2220+
case WSAETIMEDOUT: return ETIMEDOUT;
2221+
case WSAECONNREFUSED: return ECONNREFUSED;
2222+
case WSAELOOP: return ELOOP;
2223+
case WSAENAMETOOLONG: return ENAMETOOLONG;
2224+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
2225+
case WSAENOTEMPTY: return ENOTEMPTY;
2226+
/* No errno equivalent; default to EIO */
2227+
case WSAESOCKTNOSUPPORT:
2228+
case WSAEPFNOSUPPORT:
2229+
case WSAESHUTDOWN:
2230+
case WSAETOOMANYREFS:
2231+
case WSAEHOSTDOWN:
2232+
case WSAEPROCLIM:
2233+
case WSAEUSERS:
2234+
case WSAEDQUOT:
2235+
case WSAESTALE:
2236+
case WSAEREMOTE:
2237+
case WSASYSNOTREADY:
2238+
case WSAVERNOTSUPPORTED:
2239+
case WSANOTINITIALISED:
2240+
case WSAEDISCON:
2241+
case WSAENOMORE:
2242+
case WSAECANCELLED:
2243+
case WSAEINVALIDPROCTABLE:
2244+
case WSAEINVALIDPROVIDER:
2245+
case WSAEPROVIDERFAILEDINIT:
2246+
case WSASYSCALLFAILURE:
2247+
case WSASERVICE_NOT_FOUND:
2248+
case WSATYPE_NOT_FOUND:
2249+
case WSA_E_NO_MORE:
2250+
case WSA_E_CANCELLED:
2251+
case WSAEREFUSED:
2252+
case WSAHOST_NOT_FOUND:
2253+
case WSATRY_AGAIN:
2254+
case WSANO_RECOVERY:
2255+
case WSANO_DATA:
2256+
case WSA_QOS_RECEIVERS:
2257+
case WSA_QOS_SENDERS:
2258+
case WSA_QOS_NO_SENDERS:
2259+
case WSA_QOS_NO_RECEIVERS:
2260+
case WSA_QOS_REQUEST_CONFIRMED:
2261+
case WSA_QOS_ADMISSION_FAILURE:
2262+
case WSA_QOS_POLICY_FAILURE:
2263+
case WSA_QOS_BAD_STYLE:
2264+
case WSA_QOS_BAD_OBJECT:
2265+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
2266+
case WSA_QOS_GENERIC_ERROR:
2267+
case WSA_QOS_ESERVICETYPE:
2268+
case WSA_QOS_EFLOWSPEC:
2269+
case WSA_QOS_EPROVSPECBUF:
2270+
case WSA_QOS_EFILTERSTYLE:
2271+
case WSA_QOS_EFILTERTYPE:
2272+
case WSA_QOS_EFILTERCOUNT:
2273+
case WSA_QOS_EOBJLENGTH:
2274+
case WSA_QOS_EFLOWCOUNT:
2275+
#ifndef _MSC_VER
2276+
case WSA_QOS_EUNKNOWNPSOBJ:
2277+
#endif
2278+
case WSA_QOS_EPOLICYOBJ:
2279+
case WSA_QOS_EFLOWDESC:
2280+
case WSA_QOS_EPSFLOWSPEC:
2281+
case WSA_QOS_EPSFILTERSPEC:
2282+
case WSA_QOS_ESDMODEOBJ:
2283+
case WSA_QOS_ESHAPERATEOBJ:
2284+
case WSA_QOS_RESERVED_PETYPE:
2285+
default: return EIO;
2286+
}
2287+
}
2288+
2289+
/*
2290+
* On Windows, `errno` is a global macro to a function call.
2291+
* This makes it difficult to debug and single-step our mappings.
2292+
*/
2293+
static inline void set_wsa_errno(void)
2294+
{
2295+
DWORD wsa = WSAGetLastError();
2296+
int e = winsock_error_to_errno(wsa);
2297+
errno = e;
2298+
2299+
#ifdef DEBUG_WSA_ERRNO
2300+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2301+
fflush(stderr);
2302+
#endif
2303+
}
2304+
2305+
static inline int winsock_return(int ret)
2306+
{
2307+
if (ret < 0)
2308+
set_wsa_errno();
2309+
2310+
return ret;
2311+
}
2312+
2313+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2314+
2315+
#undef strerror
2316+
char *mingw_strerror(int errnum)
2317+
{
2318+
static char buf[41] ="";
2319+
switch (errnum) {
2320+
case EWOULDBLOCK:
2321+
xsnprintf(buf, 41, "%s", "Operation would block");
2322+
break;
2323+
case EINPROGRESS:
2324+
xsnprintf(buf, 41, "%s", "Operation now in progress");
2325+
break;
2326+
case EALREADY:
2327+
xsnprintf(buf, 41, "%s", "Operation already in progress");
2328+
break;
2329+
case ENOTSOCK:
2330+
xsnprintf(buf, 41, "%s", "Socket operation on non-socket");
2331+
break;
2332+
case EDESTADDRREQ:
2333+
xsnprintf(buf, 41, "%s", "Destination address required");
2334+
break;
2335+
case EMSGSIZE:
2336+
xsnprintf(buf, 41, "%s", "Message too long");
2337+
break;
2338+
case EPROTOTYPE:
2339+
xsnprintf(buf, 41, "%s", "Protocol wrong type for socket");
2340+
break;
2341+
case ENOPROTOOPT:
2342+
xsnprintf(buf, 41, "%s", "Protocol not available");
2343+
break;
2344+
case EPROTONOSUPPORT:
2345+
xsnprintf(buf, 41, "%s", "Protocol not supported");
2346+
break;
2347+
case EOPNOTSUPP:
2348+
xsnprintf(buf, 41, "%s", "Operation not supported");
2349+
break;
2350+
case EAFNOSUPPORT:
2351+
xsnprintf(buf, 41, "%s", "Address family not supported by protocol");
2352+
break;
2353+
case EADDRINUSE:
2354+
xsnprintf(buf, 41, "%s", "Address already in use");
2355+
break;
2356+
case EADDRNOTAVAIL:
2357+
xsnprintf(buf, 41, "%s", "Cannot assign requested address");
2358+
break;
2359+
case ENETDOWN:
2360+
xsnprintf(buf, 41, "%s", "Network is down");
2361+
break;
2362+
case ENETUNREACH:
2363+
xsnprintf(buf, 41, "%s", "Network is unreachable");
2364+
break;
2365+
case ENETRESET:
2366+
xsnprintf(buf, 41, "%s", "Network dropped connection on reset");
2367+
break;
2368+
case ECONNABORTED:
2369+
xsnprintf(buf, 41, "%s", "Software caused connection abort");
2370+
break;
2371+
case ECONNRESET:
2372+
xsnprintf(buf, 41, "%s", "Connection reset by peer");
2373+
break;
2374+
case ENOBUFS:
2375+
xsnprintf(buf, 41, "%s", "No buffer space available");
2376+
break;
2377+
case EISCONN:
2378+
xsnprintf(buf, 41, "%s", "Transport endpoint is already connected");
2379+
break;
2380+
case ENOTCONN:
2381+
xsnprintf(buf, 41, "%s", "Transport endpoint is not connected");
2382+
break;
2383+
case ETIMEDOUT:
2384+
xsnprintf(buf, 41, "%s", "Connection timed out");
2385+
break;
2386+
case ECONNREFUSED:
2387+
xsnprintf(buf, 41, "%s", "Connection refused");
2388+
break;
2389+
case ELOOP:
2390+
xsnprintf(buf, 41, "%s", "Too many levels of symbolic links");
2391+
break;
2392+
case EHOSTUNREACH:
2393+
xsnprintf(buf, 41, "%s", "No route to host");
2394+
break;
2395+
default: return strerror(errnum);
2396+
}
2397+
return buf;
2398+
}
2399+
21902400
#undef gethostname
21912401
int mingw_gethostname(char *name, int namelen)
21922402
{
2193-
ensure_socket_initialization();
2194-
return gethostname(name, namelen);
2403+
ensure_socket_initialization();
2404+
WINSOCK_RETURN(gethostname(name, namelen));
21952405
}
21962406

21972407
#undef gethostbyname
21982408
struct hostent *mingw_gethostbyname(const char *host)
21992409
{
2410+
struct hostent *ret;
2411+
22002412
ensure_socket_initialization();
2201-
return gethostbyname(host);
2413+
2414+
ret = gethostbyname(host);
2415+
if (!ret)
2416+
set_wsa_errno();
2417+
2418+
return ret;
22022419
}
22032420

22042421
#undef getaddrinfo
22052422
int mingw_getaddrinfo(const char *node, const char *service,
22062423
const struct addrinfo *hints, struct addrinfo **res)
22072424
{
22082425
ensure_socket_initialization();
2209-
return getaddrinfo(node, service, hints, res);
2426+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
22102427
}
22112428

22122429
int mingw_socket(int domain, int type, int protocol)
@@ -2217,16 +2434,7 @@ int mingw_socket(int domain, int type, int protocol)
22172434
ensure_socket_initialization();
22182435
s = WSASocket(domain, type, protocol, NULL, 0, 0);
22192436
if (s == INVALID_SOCKET) {
2220-
/*
2221-
* WSAGetLastError() values are regular BSD error codes
2222-
* biased by WSABASEERR.
2223-
* However, strerror() does not know about networking
2224-
* specific errors, which are values beginning at 38 or so.
2225-
* Therefore, we choose to leave the biased error code
2226-
* in errno so that _if_ someone looks up the code somewhere,
2227-
* then it is at least the number that are usually listed.
2228-
*/
2229-
errno = WSAGetLastError();
2437+
set_wsa_errno();
22302438
return -1;
22312439
}
22322440
/* convert into a file descriptor */
@@ -2242,35 +2450,35 @@ int mingw_socket(int domain, int type, int protocol)
22422450
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
22432451
{
22442452
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2245-
return connect(s, sa, sz);
2453+
WINSOCK_RETURN(connect(s, sa, sz));
22462454
}
22472455

22482456
#undef bind
22492457
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
22502458
{
22512459
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2252-
return bind(s, sa, sz);
2460+
WINSOCK_RETURN(bind(s, sa, sz));
22532461
}
22542462

22552463
#undef setsockopt
22562464
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
22572465
{
22582466
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2259-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2467+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
22602468
}
22612469

22622470
#undef shutdown
22632471
int mingw_shutdown(int sockfd, int how)
22642472
{
22652473
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2266-
return shutdown(s, how);
2474+
WINSOCK_RETURN(shutdown(s, how));
22672475
}
22682476

22692477
#undef listen
22702478
int mingw_listen(int sockfd, int backlog)
22712479
{
22722480
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2273-
return listen(s, backlog);
2481+
WINSOCK_RETURN(listen(s, backlog));
22742482
}
22752483

22762484
#undef accept
@@ -2281,6 +2489,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
22812489
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
22822490
SOCKET s2 = accept(s1, sa, sz);
22832491

2492+
if (s2 == INVALID_SOCKET) {
2493+
set_wsa_errno();
2494+
return -1;
2495+
}
2496+
22842497
/* convert into a file descriptor */
22852498
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
22862499
int err = errno;

t/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ clar_test_suites = [
55
'unit-tests/u-hash.c',
66
'unit-tests/u-hashmap.c',
77
'unit-tests/u-mem-pool.c',
8+
'unit-tests/u-mingw.c',
89
'unit-tests/u-oid-array.c',
910
'unit-tests/u-oidmap.c',
1011
'unit-tests/u-oidtree.c',

t/t0301-credential-cache.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ test -z "$NO_UNIX_SOCKETS" || {
1212
if test_have_prereq MINGW
1313
then
1414
service_running=$(sc query afunix | grep "4 RUNNING")
15-
test -z "$service_running" || {
15+
test -n "$service_running" || {
1616
skip_all='skipping credential-cache tests, unix sockets not available'
1717
test_done
1818
}

0 commit comments

Comments
 (0)