Skip to content

Commit ed0f7ca

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 7c809bf + fe570bf commit ed0f7ca

File tree

7 files changed

+313
-21
lines changed

7 files changed

+313
-21
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,7 @@ CLAR_TEST_SUITES += u-mem-pool
13541354
CLAR_TEST_SUITES += u-prio-queue
13551355
CLAR_TEST_SUITES += u-reftable-tree
13561356
CLAR_TEST_SUITES += u-strvec
1357+
CLAR_TEST_SUITES += u-mingw
13571358
CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
13581359
CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES))
13591360
CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o

builtin/credential-cache.c

+1-1
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.c

+232-19
Original file line numberDiff line numberDiff line change
@@ -2231,26 +2231,243 @@ static void ensure_socket_initialization(void)
22312231
initialized = 1;
22322232
}
22332233

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

22412451
#undef gethostbyname
22422452
struct hostent *mingw_gethostbyname(const char *host)
22432453
{
2454+
struct hostent *ret;
2455+
22442456
ensure_socket_initialization();
2245-
return gethostbyname(host);
2457+
2458+
ret = gethostbyname(host);
2459+
if (!ret)
2460+
set_wsa_errno();
2461+
2462+
return ret;
22462463
}
22472464

22482465
#undef getaddrinfo
22492466
int mingw_getaddrinfo(const char *node, const char *service,
22502467
const struct addrinfo *hints, struct addrinfo **res)
22512468
{
22522469
ensure_socket_initialization();
2253-
return getaddrinfo(node, service, hints, res);
2470+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
22542471
}
22552472

22562473
int mingw_socket(int domain, int type, int protocol)
@@ -2261,16 +2478,7 @@ int mingw_socket(int domain, int type, int protocol)
22612478
ensure_socket_initialization();
22622479
s = WSASocket(domain, type, protocol, NULL, 0, 0);
22632480
if (s == INVALID_SOCKET) {
2264-
/*
2265-
* WSAGetLastError() values are regular BSD error codes
2266-
* biased by WSABASEERR.
2267-
* However, strerror() does not know about networking
2268-
* specific errors, which are values beginning at 38 or so.
2269-
* Therefore, we choose to leave the biased error code
2270-
* in errno so that _if_ someone looks up the code somewhere,
2271-
* then it is at least the number that are usually listed.
2272-
*/
2273-
errno = WSAGetLastError();
2481+
set_wsa_errno();
22742482
return -1;
22752483
}
22762484
/* convert into a file descriptor */
@@ -2286,35 +2494,35 @@ int mingw_socket(int domain, int type, int protocol)
22862494
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
22872495
{
22882496
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2289-
return connect(s, sa, sz);
2497+
WINSOCK_RETURN(connect(s, sa, sz));
22902498
}
22912499

22922500
#undef bind
22932501
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
22942502
{
22952503
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2296-
return bind(s, sa, sz);
2504+
WINSOCK_RETURN(bind(s, sa, sz));
22972505
}
22982506

22992507
#undef setsockopt
23002508
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
23012509
{
23022510
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2303-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2511+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
23042512
}
23052513

23062514
#undef shutdown
23072515
int mingw_shutdown(int sockfd, int how)
23082516
{
23092517
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2310-
return shutdown(s, how);
2518+
WINSOCK_RETURN(shutdown(s, how));
23112519
}
23122520

23132521
#undef listen
23142522
int mingw_listen(int sockfd, int backlog)
23152523
{
23162524
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2317-
return listen(s, backlog);
2525+
WINSOCK_RETURN(listen(s, backlog));
23182526
}
23192527

23202528
#undef accept
@@ -2325,6 +2533,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
23252533
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
23262534
SOCKET s2 = accept(s1, sa, sz);
23272535

2536+
if (s2 == INVALID_SOCKET) {
2537+
set_wsa_errno();
2538+
return -1;
2539+
}
2540+
23282541
/* convert into a file descriptor */
23292542
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
23302543
int err = errno;

compat/mingw.h

+5
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,11 @@ int mingw_socket(int domain, int type, int protocol);
311311
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
312312
#define connect mingw_connect
313313

314+
char *mingw_strerror(int errnum);
315+
#ifndef _UCRT
316+
#define strerror mingw_strerror
317+
#endif
318+
314319
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
315320
#define bind mingw_bind
316321

t/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ clar_test_suites = [
22
'unit-tests/u-ctype.c',
33
'unit-tests/u-hash.c',
44
'unit-tests/u-mem-pool.c',
5+
'unit-tests/u-mingw.c',
56
'unit-tests/u-prio-queue.c',
67
'unit-tests/u-reftable-tree.c',
78
'unit-tests/u-strvec.c',

t/t0301-credential-cache.sh

+1-1
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)