Skip to content

Commit 783fac4

Browse files
committed
credential-cache: handle ECONNREFUSED gracefully (git-for-windows#5329)
I should probably add some tests for this.
2 parents 19a0d61 + ef52c17 commit 783fac4

File tree

7 files changed

+166
-11
lines changed

7 files changed

+166
-11
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,7 @@ THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
13511351

13521352
CLAR_TEST_SUITES += u-ctype
13531353
CLAR_TEST_SUITES += u-strvec
1354+
CLAR_TEST_SUITES += u-mingw
13541355
CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
13551356
CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES))
13561357
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

+85-9
Original file line numberDiff line numberDiff line change
@@ -2673,6 +2673,91 @@ static inline int winsock_return(int ret)
26732673

26742674
#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
26752675

2676+
#undef strerror
2677+
char *mingw_strerror(int errnum)
2678+
{
2679+
static char buf[41] ="";
2680+
switch (errnum) {
2681+
case EWOULDBLOCK:
2682+
xsnprintf(buf, 41, "%s", "Operation would block");
2683+
break;
2684+
case EINPROGRESS:
2685+
xsnprintf(buf, 41, "%s", "Operation now in progress");
2686+
break;
2687+
case EALREADY:
2688+
xsnprintf(buf, 41, "%s", "Operation already in progress");
2689+
break;
2690+
case ENOTSOCK:
2691+
xsnprintf(buf, 41, "%s", "Socket operation on non-socket");
2692+
break;
2693+
case EDESTADDRREQ:
2694+
xsnprintf(buf, 41, "%s", "Destination address required");
2695+
break;
2696+
case EMSGSIZE:
2697+
xsnprintf(buf, 41, "%s", "Message too long");
2698+
break;
2699+
case EPROTOTYPE:
2700+
xsnprintf(buf, 41, "%s", "Protocol wrong type for socket");
2701+
break;
2702+
case ENOPROTOOPT:
2703+
xsnprintf(buf, 41, "%s", "Protocol not available");
2704+
break;
2705+
case EPROTONOSUPPORT:
2706+
xsnprintf(buf, 41, "%s", "Protocol not supported");
2707+
break;
2708+
case EOPNOTSUPP:
2709+
xsnprintf(buf, 41, "%s", "Operation not supported");
2710+
break;
2711+
case EAFNOSUPPORT:
2712+
xsnprintf(buf, 41, "%s", "Address family not supported by protocol");
2713+
break;
2714+
case EADDRINUSE:
2715+
xsnprintf(buf, 41, "%s", "Address already in use");
2716+
break;
2717+
case EADDRNOTAVAIL:
2718+
xsnprintf(buf, 41, "%s", "Cannot assign requested address");
2719+
break;
2720+
case ENETDOWN:
2721+
xsnprintf(buf, 41, "%s", "Network is down");
2722+
break;
2723+
case ENETUNREACH:
2724+
xsnprintf(buf, 41, "%s", "Network is unreachable");
2725+
break;
2726+
case ENETRESET:
2727+
xsnprintf(buf, 41, "%s", "Network dropped connection on reset");
2728+
break;
2729+
case ECONNABORTED:
2730+
xsnprintf(buf, 41, "%s", "Software caused connection abort");
2731+
break;
2732+
case ECONNRESET:
2733+
xsnprintf(buf, 41, "%s", "Connection reset by peer");
2734+
break;
2735+
case ENOBUFS:
2736+
xsnprintf(buf, 41, "%s", "No buffer space available");
2737+
break;
2738+
case EISCONN:
2739+
xsnprintf(buf, 41, "%s", "Transport endpoint is already connected");
2740+
break;
2741+
case ENOTCONN:
2742+
xsnprintf(buf, 41, "%s", "Transport endpoint is not connected");
2743+
break;
2744+
case ETIMEDOUT:
2745+
xsnprintf(buf, 41, "%s", "Connection timed out");
2746+
break;
2747+
case ECONNREFUSED:
2748+
xsnprintf(buf, 41, "%s", "Connection refused");
2749+
break;
2750+
case ELOOP:
2751+
xsnprintf(buf, 41, "%s", "Too many levels of symbolic links");
2752+
break;
2753+
case EHOSTUNREACH:
2754+
xsnprintf(buf, 41, "%s", "No route to host");
2755+
break;
2756+
default: return strerror(errnum);
2757+
}
2758+
return buf;
2759+
}
2760+
26762761
#undef gethostname
26772762
int mingw_gethostname(char *name, int namelen)
26782763
{
@@ -2710,15 +2795,6 @@ int mingw_socket(int domain, int type, int protocol)
27102795
ensure_socket_initialization();
27112796
s = WSASocket(domain, type, protocol, NULL, 0, 0);
27122797
if (s == INVALID_SOCKET) {
2713-
/*
2714-
* WSAGetLastError() values are regular BSD error codes
2715-
* biased by WSABASEERR.
2716-
* However, strerror() does not know about networking
2717-
* specific errors, which are values beginning at 38 or so.
2718-
* Therefore, we choose to leave the biased error code
2719-
* in errno so that _if_ someone looks up the code somewhere,
2720-
* then it is at least the number that are usually listed.
2721-
*/
27222798
set_wsa_errno();
27232799
return -1;
27242800
}

compat/mingw.h

+5
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,11 @@ int mingw_socket(int domain, int type, int protocol);
314314
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
315315
#define connect mingw_connect
316316

317+
char *mingw_strerror(int errnum);
318+
#ifndef _UCRT
319+
#define strerror mingw_strerror
320+
#endif
321+
317322
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
318323
#define bind mingw_bind
319324

t/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
clar_test_suites = [
22
'unit-tests/u-ctype.c',
3+
'unit-tests/u-mingw.c',
34
'unit-tests/u-strvec.c',
45
]
56

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
}

t/unit-tests/u-mingw.c

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "unit-test.h"
2+
3+
#if defined(GIT_WINDOWS_NATIVE) && !defined(_UCRT)
4+
#undef strerror
5+
int errnos_contains(int);
6+
static int errnos [53]={
7+
/* errnos in err_win_to_posix */
8+
EACCES, EBUSY, EEXIST, ERANGE, EIO, ENODEV, ENXIO, ENOEXEC, EINVAL, ENOENT,
9+
EPIPE, ENAMETOOLONG, ENOSYS, ENOTEMPTY, ENOSPC, EFAULT, EBADF, EPERM, EINTR,
10+
E2BIG, ESPIPE, ENOMEM, EXDEV, EAGAIN, ENFILE, EMFILE, ECHILD, EROFS,
11+
/* errnos only in winsock_error_to_errno */
12+
EWOULDBLOCK, EINPROGRESS, EALREADY, ENOTSOCK, EDESTADDRREQ, EMSGSIZE,
13+
EPROTOTYPE, ENOPROTOOPT, EPROTONOSUPPORT, EOPNOTSUPP, EAFNOSUPPORT,
14+
EADDRINUSE, EADDRNOTAVAIL, ENETDOWN, ENETUNREACH, ENETRESET, ECONNABORTED,
15+
ECONNRESET, ENOBUFS, EISCONN, ENOTCONN, ETIMEDOUT, ECONNREFUSED, ELOOP,
16+
EHOSTUNREACH
17+
};
18+
19+
int errnos_contains(int errnum)
20+
{
21+
for(int i=0;i<53;i++)
22+
if(errnos[i]==errnum)
23+
return 1;
24+
return 0;
25+
}
26+
#endif
27+
28+
void test_mingw__no_strerror_shim_on_ucrt(void)
29+
{
30+
#if defined(GIT_WINDOWS_NATIVE) && defined(_UCRT)
31+
cl_assert_(strerror != mingw_strerror,
32+
"mingw_strerror is unnescessary when building against UCRT");
33+
#else
34+
cl_skip();
35+
#endif
36+
}
37+
38+
void test_mingw__strerror(void)
39+
{
40+
#if defined(GIT_WINDOWS_NATIVE) && !defined(_UCRT)
41+
for(int i=0;i<53;i++)
42+
{
43+
char *crt;
44+
char *mingw;
45+
mingw = mingw_strerror(errnos[i]);
46+
crt = strerror(errnos[i]);
47+
cl_assert_(!strcasestr(mingw, "unknown error"),
48+
"mingw_strerror should know all errno values we care about");
49+
if(!strcasestr(crt, "unknown error"))
50+
cl_assert_equal_s(crt,mingw);
51+
}
52+
#else
53+
cl_skip();
54+
#endif
55+
}
56+
57+
void test_mingw__errno_translation(void)
58+
{
59+
#if defined(GIT_WINDOWS_NATIVE) && !defined(_UCRT)
60+
/* GetLastError() return values are currently defined from 0 to 15841,
61+
testing up to 20000 covers some room for future expansion */
62+
for (int i=0;i<20000;i++)
63+
{
64+
if(i!=ERROR_SUCCESS)
65+
cl_assert_(errnos_contains(err_win_to_posix(i)),
66+
"all err_win_to_posix return values should be tested against mingw_strerror");
67+
/* ideally we'd test the same for winsock_error_to_errno, but it's static */
68+
}
69+
#else
70+
cl_skip();
71+
#endif
72+
}

0 commit comments

Comments
 (0)