Skip to content

Commit 1d4b605

Browse files
dschoGit for Windows Build Agent
authored andcommitted
credential-cache: handle ECONNREFUSED gracefully (git-for-windows#5329)
I should probably add some tests for this.
2 parents 6f56c5f + 76ef3ae commit 1d4b605

7 files changed

Lines changed: 313 additions & 21 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,7 @@ CLAR_TEST_SUITES += u-hash
15381538
CLAR_TEST_SUITES += u-hashmap
15391539
CLAR_TEST_SUITES += u-list-objects-filter-options
15401540
CLAR_TEST_SUITES += u-mem-pool
1541+
CLAR_TEST_SUITES += u-mingw
15411542
CLAR_TEST_SUITES += u-odb-inmemory
15421543
CLAR_TEST_SUITES += u-oid-array
15431544
CLAR_TEST_SUITES += u-oidmap

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
@@ -288,6 +288,11 @@ int mingw_socket(int domain, int type, int protocol);
288288
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
289289
#define connect mingw_connect
290290

291+
char *mingw_strerror(int errnum);
292+
#ifndef _UCRT
293+
#define strerror mingw_strerror
294+
#endif
295+
291296
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
292297
#define bind mingw_bind
293298

compat/mingw.c

Lines changed: 232 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,26 +2519,243 @@ static void ensure_socket_initialization(void)
25192519
initialized = 1;
25202520
}
25212521

2522+
static int winsock_error_to_errno(DWORD err)
2523+
{
2524+
switch (err) {
2525+
case WSAEINTR: return EINTR;
2526+
case WSAEBADF: return EBADF;
2527+
case WSAEACCES: return EACCES;
2528+
case WSAEFAULT: return EFAULT;
2529+
case WSAEINVAL: return EINVAL;
2530+
case WSAEMFILE: return EMFILE;
2531+
case WSAEWOULDBLOCK: return EWOULDBLOCK;
2532+
case WSAEINPROGRESS: return EINPROGRESS;
2533+
case WSAEALREADY: return EALREADY;
2534+
case WSAENOTSOCK: return ENOTSOCK;
2535+
case WSAEDESTADDRREQ: return EDESTADDRREQ;
2536+
case WSAEMSGSIZE: return EMSGSIZE;
2537+
case WSAEPROTOTYPE: return EPROTOTYPE;
2538+
case WSAENOPROTOOPT: return ENOPROTOOPT;
2539+
case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
2540+
case WSAEOPNOTSUPP: return EOPNOTSUPP;
2541+
case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
2542+
case WSAEADDRINUSE: return EADDRINUSE;
2543+
case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
2544+
case WSAENETDOWN: return ENETDOWN;
2545+
case WSAENETUNREACH: return ENETUNREACH;
2546+
case WSAENETRESET: return ENETRESET;
2547+
case WSAECONNABORTED: return ECONNABORTED;
2548+
case WSAECONNRESET: return ECONNRESET;
2549+
case WSAENOBUFS: return ENOBUFS;
2550+
case WSAEISCONN: return EISCONN;
2551+
case WSAENOTCONN: return ENOTCONN;
2552+
case WSAETIMEDOUT: return ETIMEDOUT;
2553+
case WSAECONNREFUSED: return ECONNREFUSED;
2554+
case WSAELOOP: return ELOOP;
2555+
case WSAENAMETOOLONG: return ENAMETOOLONG;
2556+
case WSAEHOSTUNREACH: return EHOSTUNREACH;
2557+
case WSAENOTEMPTY: return ENOTEMPTY;
2558+
/* No errno equivalent; default to EIO */
2559+
case WSAESOCKTNOSUPPORT:
2560+
case WSAEPFNOSUPPORT:
2561+
case WSAESHUTDOWN:
2562+
case WSAETOOMANYREFS:
2563+
case WSAEHOSTDOWN:
2564+
case WSAEPROCLIM:
2565+
case WSAEUSERS:
2566+
case WSAEDQUOT:
2567+
case WSAESTALE:
2568+
case WSAEREMOTE:
2569+
case WSASYSNOTREADY:
2570+
case WSAVERNOTSUPPORTED:
2571+
case WSANOTINITIALISED:
2572+
case WSAEDISCON:
2573+
case WSAENOMORE:
2574+
case WSAECANCELLED:
2575+
case WSAEINVALIDPROCTABLE:
2576+
case WSAEINVALIDPROVIDER:
2577+
case WSAEPROVIDERFAILEDINIT:
2578+
case WSASYSCALLFAILURE:
2579+
case WSASERVICE_NOT_FOUND:
2580+
case WSATYPE_NOT_FOUND:
2581+
case WSA_E_NO_MORE:
2582+
case WSA_E_CANCELLED:
2583+
case WSAEREFUSED:
2584+
case WSAHOST_NOT_FOUND:
2585+
case WSATRY_AGAIN:
2586+
case WSANO_RECOVERY:
2587+
case WSANO_DATA:
2588+
case WSA_QOS_RECEIVERS:
2589+
case WSA_QOS_SENDERS:
2590+
case WSA_QOS_NO_SENDERS:
2591+
case WSA_QOS_NO_RECEIVERS:
2592+
case WSA_QOS_REQUEST_CONFIRMED:
2593+
case WSA_QOS_ADMISSION_FAILURE:
2594+
case WSA_QOS_POLICY_FAILURE:
2595+
case WSA_QOS_BAD_STYLE:
2596+
case WSA_QOS_BAD_OBJECT:
2597+
case WSA_QOS_TRAFFIC_CTRL_ERROR:
2598+
case WSA_QOS_GENERIC_ERROR:
2599+
case WSA_QOS_ESERVICETYPE:
2600+
case WSA_QOS_EFLOWSPEC:
2601+
case WSA_QOS_EPROVSPECBUF:
2602+
case WSA_QOS_EFILTERSTYLE:
2603+
case WSA_QOS_EFILTERTYPE:
2604+
case WSA_QOS_EFILTERCOUNT:
2605+
case WSA_QOS_EOBJLENGTH:
2606+
case WSA_QOS_EFLOWCOUNT:
2607+
#ifndef _MSC_VER
2608+
case WSA_QOS_EUNKNOWNPSOBJ:
2609+
#endif
2610+
case WSA_QOS_EPOLICYOBJ:
2611+
case WSA_QOS_EFLOWDESC:
2612+
case WSA_QOS_EPSFLOWSPEC:
2613+
case WSA_QOS_EPSFILTERSPEC:
2614+
case WSA_QOS_ESDMODEOBJ:
2615+
case WSA_QOS_ESHAPERATEOBJ:
2616+
case WSA_QOS_RESERVED_PETYPE:
2617+
default: return EIO;
2618+
}
2619+
}
2620+
2621+
/*
2622+
* On Windows, `errno` is a global macro to a function call.
2623+
* This makes it difficult to debug and single-step our mappings.
2624+
*/
2625+
static inline void set_wsa_errno(void)
2626+
{
2627+
DWORD wsa = WSAGetLastError();
2628+
int e = winsock_error_to_errno(wsa);
2629+
errno = e;
2630+
2631+
#ifdef DEBUG_WSA_ERRNO
2632+
fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
2633+
fflush(stderr);
2634+
#endif
2635+
}
2636+
2637+
static inline int winsock_return(int ret)
2638+
{
2639+
if (ret < 0)
2640+
set_wsa_errno();
2641+
2642+
return ret;
2643+
}
2644+
2645+
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
2646+
2647+
#undef strerror
2648+
char *mingw_strerror(int errnum)
2649+
{
2650+
static char buf[41] ="";
2651+
switch (errnum) {
2652+
case EWOULDBLOCK:
2653+
xsnprintf(buf, 41, "%s", "Operation would block");
2654+
break;
2655+
case EINPROGRESS:
2656+
xsnprintf(buf, 41, "%s", "Operation now in progress");
2657+
break;
2658+
case EALREADY:
2659+
xsnprintf(buf, 41, "%s", "Operation already in progress");
2660+
break;
2661+
case ENOTSOCK:
2662+
xsnprintf(buf, 41, "%s", "Socket operation on non-socket");
2663+
break;
2664+
case EDESTADDRREQ:
2665+
xsnprintf(buf, 41, "%s", "Destination address required");
2666+
break;
2667+
case EMSGSIZE:
2668+
xsnprintf(buf, 41, "%s", "Message too long");
2669+
break;
2670+
case EPROTOTYPE:
2671+
xsnprintf(buf, 41, "%s", "Protocol wrong type for socket");
2672+
break;
2673+
case ENOPROTOOPT:
2674+
xsnprintf(buf, 41, "%s", "Protocol not available");
2675+
break;
2676+
case EPROTONOSUPPORT:
2677+
xsnprintf(buf, 41, "%s", "Protocol not supported");
2678+
break;
2679+
case EOPNOTSUPP:
2680+
xsnprintf(buf, 41, "%s", "Operation not supported");
2681+
break;
2682+
case EAFNOSUPPORT:
2683+
xsnprintf(buf, 41, "%s", "Address family not supported by protocol");
2684+
break;
2685+
case EADDRINUSE:
2686+
xsnprintf(buf, 41, "%s", "Address already in use");
2687+
break;
2688+
case EADDRNOTAVAIL:
2689+
xsnprintf(buf, 41, "%s", "Cannot assign requested address");
2690+
break;
2691+
case ENETDOWN:
2692+
xsnprintf(buf, 41, "%s", "Network is down");
2693+
break;
2694+
case ENETUNREACH:
2695+
xsnprintf(buf, 41, "%s", "Network is unreachable");
2696+
break;
2697+
case ENETRESET:
2698+
xsnprintf(buf, 41, "%s", "Network dropped connection on reset");
2699+
break;
2700+
case ECONNABORTED:
2701+
xsnprintf(buf, 41, "%s", "Software caused connection abort");
2702+
break;
2703+
case ECONNRESET:
2704+
xsnprintf(buf, 41, "%s", "Connection reset by peer");
2705+
break;
2706+
case ENOBUFS:
2707+
xsnprintf(buf, 41, "%s", "No buffer space available");
2708+
break;
2709+
case EISCONN:
2710+
xsnprintf(buf, 41, "%s", "Transport endpoint is already connected");
2711+
break;
2712+
case ENOTCONN:
2713+
xsnprintf(buf, 41, "%s", "Transport endpoint is not connected");
2714+
break;
2715+
case ETIMEDOUT:
2716+
xsnprintf(buf, 41, "%s", "Connection timed out");
2717+
break;
2718+
case ECONNREFUSED:
2719+
xsnprintf(buf, 41, "%s", "Connection refused");
2720+
break;
2721+
case ELOOP:
2722+
xsnprintf(buf, 41, "%s", "Too many levels of symbolic links");
2723+
break;
2724+
case EHOSTUNREACH:
2725+
xsnprintf(buf, 41, "%s", "No route to host");
2726+
break;
2727+
default: return strerror(errnum);
2728+
}
2729+
return buf;
2730+
}
2731+
25222732
#undef gethostname
25232733
int mingw_gethostname(char *name, int namelen)
25242734
{
2525-
ensure_socket_initialization();
2526-
return gethostname(name, namelen);
2735+
ensure_socket_initialization();
2736+
WINSOCK_RETURN(gethostname(name, namelen));
25272737
}
25282738

25292739
#undef gethostbyname
25302740
struct hostent *mingw_gethostbyname(const char *host)
25312741
{
2742+
struct hostent *ret;
2743+
25322744
ensure_socket_initialization();
2533-
return gethostbyname(host);
2745+
2746+
ret = gethostbyname(host);
2747+
if (!ret)
2748+
set_wsa_errno();
2749+
2750+
return ret;
25342751
}
25352752

25362753
#undef getaddrinfo
25372754
int mingw_getaddrinfo(const char *node, const char *service,
25382755
const struct addrinfo *hints, struct addrinfo **res)
25392756
{
25402757
ensure_socket_initialization();
2541-
return getaddrinfo(node, service, hints, res);
2758+
WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
25422759
}
25432760

25442761
int mingw_socket(int domain, int type, int protocol)
@@ -2549,16 +2766,7 @@ int mingw_socket(int domain, int type, int protocol)
25492766
ensure_socket_initialization();
25502767
s = WSASocket(domain, type, protocol, NULL, 0, 0);
25512768
if (s == INVALID_SOCKET) {
2552-
/*
2553-
* WSAGetLastError() values are regular BSD error codes
2554-
* biased by WSABASEERR.
2555-
* However, strerror() does not know about networking
2556-
* specific errors, which are values beginning at 38 or so.
2557-
* Therefore, we choose to leave the biased error code
2558-
* in errno so that _if_ someone looks up the code somewhere,
2559-
* then it is at least the number that are usually listed.
2560-
*/
2561-
errno = WSAGetLastError();
2769+
set_wsa_errno();
25622770
return -1;
25632771
}
25642772
/* convert into a file descriptor */
@@ -2574,35 +2782,35 @@ int mingw_socket(int domain, int type, int protocol)
25742782
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
25752783
{
25762784
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2577-
return connect(s, sa, sz);
2785+
WINSOCK_RETURN(connect(s, sa, sz));
25782786
}
25792787

25802788
#undef bind
25812789
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
25822790
{
25832791
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2584-
return bind(s, sa, sz);
2792+
WINSOCK_RETURN(bind(s, sa, sz));
25852793
}
25862794

25872795
#undef setsockopt
25882796
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
25892797
{
25902798
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2591-
return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2799+
WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
25922800
}
25932801

25942802
#undef shutdown
25952803
int mingw_shutdown(int sockfd, int how)
25962804
{
25972805
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2598-
return shutdown(s, how);
2806+
WINSOCK_RETURN(shutdown(s, how));
25992807
}
26002808

26012809
#undef listen
26022810
int mingw_listen(int sockfd, int backlog)
26032811
{
26042812
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2605-
return listen(s, backlog);
2813+
WINSOCK_RETURN(listen(s, backlog));
26062814
}
26072815

26082816
#undef accept
@@ -2613,6 +2821,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
26132821
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
26142822
SOCKET s2 = accept(s1, sa, sz);
26152823

2824+
if (s2 == INVALID_SOCKET) {
2825+
set_wsa_errno();
2826+
return -1;
2827+
}
2828+
26162829
/* convert into a file descriptor */
26172830
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
26182831
int err = errno;

t/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ clar_test_suites = [
66
'unit-tests/u-hashmap.c',
77
'unit-tests/u-list-objects-filter-options.c',
88
'unit-tests/u-mem-pool.c',
9+
'unit-tests/u-mingw.c',
910
'unit-tests/u-odb-inmemory.c',
1011
'unit-tests/u-oid-array.c',
1112
'unit-tests/u-oidmap.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)