Skip to content

Commit 2014f2b

Browse files
dschoGit for Windows Build Agent
authored and
Git for Windows Build Agent
committed
credential-cache: handle ECONNREFUSED gracefully (#5329)
I should probably add some tests for this.
2 parents d067850 + dceab83 commit 2014f2b

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
@@ -1367,6 +1367,7 @@ CLAR_TEST_SUITES += u-example-decorate
13671367
CLAR_TEST_SUITES += u-hash
13681368
CLAR_TEST_SUITES += u-hashmap
13691369
CLAR_TEST_SUITES += u-mem-pool
1370+
CLAR_TEST_SUITES += u-mingw
13701371
CLAR_TEST_SUITES += u-oid-array
13711372
CLAR_TEST_SUITES += u-oidmap
13721373
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
@@ -292,6 +292,11 @@ int mingw_socket(int domain, int type, int protocol);
292292
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
293293
#define connect mingw_connect
294294

295+
char *mingw_strerror(int errnum);
296+
#ifndef _UCRT
297+
#define strerror mingw_strerror
298+
#endif
299+
295300
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
296301
#define bind mingw_bind
297302

compat/mingw.c

Lines changed: 232 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,26 +2254,243 @@ static void ensure_socket_initialization(void)
22542254
initialized = 1;
22552255
}
22562256

2257+
static int winsock_error_to_errno(DWORD err)
2258+
{
2259+
switch (err) {
2260+
case WSAEINTR: return EINTR;
2261+
case WSAEBADF: return EBADF;
2262+
case WSAEACCES: return EACCES;
2263+
case WSAEFAULT: return EFAULT;
2264+
case WSAEINVAL: return EINVAL;
2265+
case WSAEMFILE: return EMFILE;
2266+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
2267+
case WSAEINPROGRESS: return EINPROGRESS;
2268+
case WSAEALREADY: return EALREADY;
2269+
case WSAENOTSOCK: return ENOTSOCK;
2270+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
2271+
case WSAEMSGSIZE: return EMSGSIZE;
2272+
case WSAEPROTOTYPE: return EPROTOTYPE;
2273+
case WSAENOPROTOOPT: return ENOPROTOOPT;
2274+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
2275+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
2276+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
2277+
case WSAEADDRINUSE: return EADDRINUSE;
2278+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
2279+
case WSAENETDOWN: return ENETDOWN;
2280+
case WSAENETUNREACH: return ENETUNREACH;
2281+
case WSAENETRESET: return ENETRESET;
2282+
case WSAECONNABORTED: return ECONNABORTED;
2283+
case WSAECONNRESET: return ECONNRESET;
2284+
case WSAENOBUFS: return ENOBUFS;
2285+
case WSAEISCONN: return EISCONN;
2286+
case WSAENOTCONN: return ENOTCONN;
2287+
case WSAETIMEDOUT: return ETIMEDOUT;
2288+
case WSAECONNREFUSED: return ECONNREFUSED;
2289+
case WSAELOOP: return ELOOP;
2290+
case WSAENAMETOOLONG: return ENAMETOOLONG;
2291+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
2292+
case WSAENOTEMPTY: return ENOTEMPTY;
2293+
/* No errno equivalent; default to EIO */
2294+
case WSAESOCKTNOSUPPORT:
2295+
case WSAEPFNOSUPPORT:
2296+
case WSAESHUTDOWN:
2297+
case WSAETOOMANYREFS:
2298+
case WSAEHOSTDOWN:
2299+
case WSAEPROCLIM:
2300+
case WSAEUSERS:
2301+
case WSAEDQUOT:
2302+
case WSAESTALE:
2303+
case WSAEREMOTE:
2304+
case WSASYSNOTREADY:
2305+
case WSAVERNOTSUPPORTED:
2306+
case WSANOTINITIALISED:
2307+
case WSAEDISCON:
2308+
case WSAENOMORE:
2309+
case WSAECANCELLED:
2310+
case WSAEINVALIDPROCTABLE:
2311+
case WSAEINVALIDPROVIDER:
2312+
case WSAEPROVIDERFAILEDINIT:
2313+
case WSASYSCALLFAILURE:
2314+
case WSASERVICE_NOT_FOUND:
2315+
case WSATYPE_NOT_FOUND:
2316+
case WSA_E_NO_MORE:
2317+
case WSA_E_CANCELLED:
2318+
case WSAEREFUSED:
2319+
case WSAHOST_NOT_FOUND:
2320+
case WSATRY_AGAIN:
2321+
case WSANO_RECOVERY:
2322+
case WSANO_DATA:
2323+
case WSA_QOS_RECEIVERS:
2324+
case WSA_QOS_SENDERS:
2325+
case WSA_QOS_NO_SENDERS:
2326+
case WSA_QOS_NO_RECEIVERS:
2327+
case WSA_QOS_REQUEST_CONFIRMED:
2328+
case WSA_QOS_ADMISSION_FAILURE:
2329+
case WSA_QOS_POLICY_FAILURE:
2330+
case WSA_QOS_BAD_STYLE:
2331+
case WSA_QOS_BAD_OBJECT:
2332+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
2333+
case WSA_QOS_GENERIC_ERROR:
2334+
case WSA_QOS_ESERVICETYPE:
2335+
case WSA_QOS_EFLOWSPEC:
2336+
case WSA_QOS_EPROVSPECBUF:
2337+
case WSA_QOS_EFILTERSTYLE:
2338+
case WSA_QOS_EFILTERTYPE:
2339+
case WSA_QOS_EFILTERCOUNT:
2340+
case WSA_QOS_EOBJLENGTH:
2341+
case WSA_QOS_EFLOWCOUNT:
2342+
#ifndef _MSC_VER
2343+
case WSA_QOS_EUNKNOWNPSOBJ:
2344+
#endif
2345+
case WSA_QOS_EPOLICYOBJ:
2346+
case WSA_QOS_EFLOWDESC:
2347+
case WSA_QOS_EPSFLOWSPEC:
2348+
case WSA_QOS_EPSFILTERSPEC:
2349+
case WSA_QOS_ESDMODEOBJ:
2350+
case WSA_QOS_ESHAPERATEOBJ:
2351+
case WSA_QOS_RESERVED_PETYPE:
2352+
default: return EIO;
2353+
}
2354+
}
2355+
2356+
/*
2357+
* On Windows, `errno` is a global macro to a function call.
2358+
* This makes it difficult to debug and single-step our mappings.
2359+
*/
2360+
static inline void set_wsa_errno(void)
2361+
{
2362+
DWORD wsa = WSAGetLastError();
2363+
int e = winsock_error_to_errno(wsa);
2364+
errno = e;
2365+
2366+
#ifdef DEBUG_WSA_ERRNO
2367+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2368+
fflush(stderr);
2369+
#endif
2370+
}
2371+
2372+
static inline int winsock_return(int ret)
2373+
{
2374+
if (ret < 0)
2375+
set_wsa_errno();
2376+
2377+
return ret;
2378+
}
2379+
2380+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2381+
2382+
#undef strerror
2383+
char *mingw_strerror(int errnum)
2384+
{
2385+
static char buf[41] ="";
2386+
switch (errnum) {
2387+
case EWOULDBLOCK:
2388+
xsnprintf(buf, 41, "%s", "Operation would block");
2389+
break;
2390+
case EINPROGRESS:
2391+
xsnprintf(buf, 41, "%s", "Operation now in progress");
2392+
break;
2393+
case EALREADY:
2394+
xsnprintf(buf, 41, "%s", "Operation already in progress");
2395+
break;
2396+
case ENOTSOCK:
2397+
xsnprintf(buf, 41, "%s", "Socket operation on non-socket");
2398+
break;
2399+
case EDESTADDRREQ:
2400+
xsnprintf(buf, 41, "%s", "Destination address required");
2401+
break;
2402+
case EMSGSIZE:
2403+
xsnprintf(buf, 41, "%s", "Message too long");
2404+
break;
2405+
case EPROTOTYPE:
2406+
xsnprintf(buf, 41, "%s", "Protocol wrong type for socket");
2407+
break;
2408+
case ENOPROTOOPT:
2409+
xsnprintf(buf, 41, "%s", "Protocol not available");
2410+
break;
2411+
case EPROTONOSUPPORT:
2412+
xsnprintf(buf, 41, "%s", "Protocol not supported");
2413+
break;
2414+
case EOPNOTSUPP:
2415+
xsnprintf(buf, 41, "%s", "Operation not supported");
2416+
break;
2417+
case EAFNOSUPPORT:
2418+
xsnprintf(buf, 41, "%s", "Address family not supported by protocol");
2419+
break;
2420+
case EADDRINUSE:
2421+
xsnprintf(buf, 41, "%s", "Address already in use");
2422+
break;
2423+
case EADDRNOTAVAIL:
2424+
xsnprintf(buf, 41, "%s", "Cannot assign requested address");
2425+
break;
2426+
case ENETDOWN:
2427+
xsnprintf(buf, 41, "%s", "Network is down");
2428+
break;
2429+
case ENETUNREACH:
2430+
xsnprintf(buf, 41, "%s", "Network is unreachable");
2431+
break;
2432+
case ENETRESET:
2433+
xsnprintf(buf, 41, "%s", "Network dropped connection on reset");
2434+
break;
2435+
case ECONNABORTED:
2436+
xsnprintf(buf, 41, "%s", "Software caused connection abort");
2437+
break;
2438+
case ECONNRESET:
2439+
xsnprintf(buf, 41, "%s", "Connection reset by peer");
2440+
break;
2441+
case ENOBUFS:
2442+
xsnprintf(buf, 41, "%s", "No buffer space available");
2443+
break;
2444+
case EISCONN:
2445+
xsnprintf(buf, 41, "%s", "Transport endpoint is already connected");
2446+
break;
2447+
case ENOTCONN:
2448+
xsnprintf(buf, 41, "%s", "Transport endpoint is not connected");
2449+
break;
2450+
case ETIMEDOUT:
2451+
xsnprintf(buf, 41, "%s", "Connection timed out");
2452+
break;
2453+
case ECONNREFUSED:
2454+
xsnprintf(buf, 41, "%s", "Connection refused");
2455+
break;
2456+
case ELOOP:
2457+
xsnprintf(buf, 41, "%s", "Too many levels of symbolic links");
2458+
break;
2459+
case EHOSTUNREACH:
2460+
xsnprintf(buf, 41, "%s", "No route to host");
2461+
break;
2462+
default: return strerror(errnum);
2463+
}
2464+
return buf;
2465+
}
2466+
22572467
#undef gethostname
22582468
int mingw_gethostname(char *name, int namelen)
22592469
{
2260-
ensure_socket_initialization();
2261-
return gethostname(name, namelen);
2470+
ensure_socket_initialization();
2471+
WINSOCK_RETURN(gethostname(name, namelen));
22622472
}
22632473

22642474
#undef gethostbyname
22652475
struct hostent *mingw_gethostbyname(const char *host)
22662476
{
2477+
struct hostent *ret;
2478+
22672479
ensure_socket_initialization();
2268-
return gethostbyname(host);
2480+
2481+
ret = gethostbyname(host);
2482+
if (!ret)
2483+
set_wsa_errno();
2484+
2485+
return ret;
22692486
}
22702487

22712488
#undef getaddrinfo
22722489
int mingw_getaddrinfo(const char *node, const char *service,
22732490
const struct addrinfo *hints, struct addrinfo **res)
22742491
{
22752492
ensure_socket_initialization();
2276-
return getaddrinfo(node, service, hints, res);
2493+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
22772494
}
22782495

22792496
int mingw_socket(int domain, int type, int protocol)
@@ -2284,16 +2501,7 @@ int mingw_socket(int domain, int type, int protocol)
22842501
ensure_socket_initialization();
22852502
s = WSASocket(domain, type, protocol, NULL, 0, 0);
22862503
if (s == INVALID_SOCKET) {
2287-
/*
2288-
* WSAGetLastError() values are regular BSD error codes
2289-
* biased by WSABASEERR.
2290-
* However, strerror() does not know about networking
2291-
* specific errors, which are values beginning at 38 or so.
2292-
* Therefore, we choose to leave the biased error code
2293-
* in errno so that _if_ someone looks up the code somewhere,
2294-
* then it is at least the number that are usually listed.
2295-
*/
2296-
errno = WSAGetLastError();
2504+
set_wsa_errno();
22972505
return -1;
22982506
}
22992507
/* convert into a file descriptor */
@@ -2309,35 +2517,35 @@ int mingw_socket(int domain, int type, int protocol)
23092517
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
23102518
{
23112519
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2312-
return connect(s, sa, sz);
2520+
WINSOCK_RETURN(connect(s, sa, sz));
23132521
}
23142522

23152523
#undef bind
23162524
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
23172525
{
23182526
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2319-
return bind(s, sa, sz);
2527+
WINSOCK_RETURN(bind(s, sa, sz));
23202528
}
23212529

23222530
#undef setsockopt
23232531
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
23242532
{
23252533
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2326-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2534+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
23272535
}
23282536

23292537
#undef shutdown
23302538
int mingw_shutdown(int sockfd, int how)
23312539
{
23322540
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2333-
return shutdown(s, how);
2541+
WINSOCK_RETURN(shutdown(s, how));
23342542
}
23352543

23362544
#undef listen
23372545
int mingw_listen(int sockfd, int backlog)
23382546
{
23392547
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2340-
return listen(s, backlog);
2548+
WINSOCK_RETURN(listen(s, backlog));
23412549
}
23422550

23432551
#undef accept
@@ -2348,6 +2556,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
23482556
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
23492557
SOCKET s2 = accept(s1, sa, sz);
23502558

2559+
if (s2 == INVALID_SOCKET) {
2560+
set_wsa_errno();
2561+
return -1;
2562+
}
2563+
23512564
/* convert into a file descriptor */
23522565
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
23532566
int err = errno;

t/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ clar_test_suites = [
44
'unit-tests/u-hash.c',
55
'unit-tests/u-hashmap.c',
66
'unit-tests/u-mem-pool.c',
7+
'unit-tests/u-mingw.c',
78
'unit-tests/u-oid-array.c',
89
'unit-tests/u-oidmap.c',
910
'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)