From bd7ae7e2408425e4c646c8b68c72625818670224 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 6 Feb 2014 11:46:53 +0000 Subject: [PATCH] Use closesocket() and fix errno handling for MinGW Based on a patch from Nikos Mavrogiannopoulos. Signed-off-by: David Woodhouse --- compat.c | 41 +++++++++++++++++++++++++++++++++++++++++ configure.ac | 11 ++++++++++- dtls.c | 12 ++++++------ gnutls.c | 16 ++++++++-------- openconnect-internal.h | 8 ++++++++ openssl.c | 16 ++++++++-------- ssl.c | 10 +++++----- 7 files changed, 86 insertions(+), 28 deletions(-) diff --git a/compat.c b/compat.c index 3ed8045a..2b2c77bc 100644 --- a/compat.c +++ b/compat.c @@ -198,3 +198,44 @@ int openconnect__inet_aton(const char *cp, struct in_addr *addr) return (addr->s_addr == 0xffffffff) ? 0 : 1; } #endif + +#ifdef _WIN32 +int openconnect__win32_neterrno() +{ + switch (WSAGetLastError()) { + case WSAEINTR: return EINTR; + case WSAEWOULDBLOCK: return EWOULDBLOCK; + case WSAEINPROGRESS: return EINPROGRESS; + case WSAEALREADY: return EALREADY; + case WSAENOTSOCK: return ENOTSOCK; + case WSAEDESTADDRREQ: return EDESTADDRREQ; + case WSAEMSGSIZE: return EMSGSIZE; + case WSAEPROTOTYPE: return EPROTOTYPE; + case WSAENOPROTOOPT: return ENOPROTOOPT; + case WSAEPROTONOSUPPORT:return EPROTONOSUPPORT; + case WSAEOPNOTSUPP: return EOPNOTSUPP; + case WSAEPFNOSUPPORT: return EAFNOSUPPORT; + case WSAEAFNOSUPPORT: return EAFNOSUPPORT; + case WSAEADDRINUSE: return EADDRINUSE; + case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL; + case WSAENETDOWN: return ENETDOWN; + case WSAENETUNREACH: return ENETUNREACH; + case WSAENETRESET: return ENETRESET; + case WSAECONNABORTED: return ECONNABORTED; + case WSAECONNRESET: return ECONNRESET; + case WSAENOBUFS: return ENOBUFS; + case WSAEISCONN: return EISCONN; + case WSAENOTCONN: return ENOTCONN; + case WSAETIMEDOUT: return ETIMEDOUT; + case WSAECONNREFUSED: return ECONNREFUSED; + case WSAELOOP: return ELOOP; + case WSAENAMETOOLONG: return ENAMETOOLONG; + case WSAEHOSTUNREACH: return EHOSTUNREACH; + case WSAENOTEMPTY: return ENOTEMPTY; + case WSAEINVAL: return EINVAL; + case WSAEFAULT: return EFAULT; + case 0: return 0; + default: return EIO; + } +} +#endif /* _WIN32 */ diff --git a/configure.ac b/configure.ac index d2605ffe..39d173bd 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,10 @@ case $host_os in AC_DEFINE(HAVE_SUNOS_BROKEN_TIME) symver_time="openconnect__time;" ;; + *mingw32*|*mingw64*) + AC_MSG_NOTICE([Applying feature macros for MinGW/Windows build]) + have_win=yes + ;; *) # On FreeBSD the only way to get vsyslog() visible is to define # *nothing*, which makes absolutely everything visible. @@ -140,7 +144,12 @@ AS_COMPILER_FLAGS(WFLAGS, -Wwrite-strings") AC_SUBST(WFLAGS, [$WFLAGS]) -AC_CHECK_FUNC(socket, [], AC_CHECK_LIB(socket, socket, [], AC_ERROR(Cannot find socket() function))) +if test "$have_win" = yes; then + # Checking "properly" for __attribute__((dllimport,stdcall)) functions is non-trivial + LIBS="$LIBS -lws2_32" +else + AC_CHECK_FUNC(socket, [], AC_CHECK_LIB(socket, socket, [], AC_ERROR(Cannot find socket() function))) +fi have_inet_aton=yes AC_CHECK_FUNC(inet_aton, [], AC_CHECK_LIB(nsl, inet_aton, [], have_inet_aton=no)) diff --git a/dtls.c b/dtls.c index 249f4544..5a2666e0 100644 --- a/dtls.c +++ b/dtls.c @@ -524,20 +524,20 @@ int connect_dtls_socket(struct openconnect_info *vpninfo) _("Unknown protocol family %d. Cannot do DTLS\n"), vpninfo->peer_addr->sa_family); vpninfo->dtls_attempt_period = 0; - close(dtls_fd); + closesocket(dtls_fd); return -EINVAL; } if (bind(dtls_fd, (struct sockaddr *)&dtls_bind_addr, dtls_bind_addrlen)) { perror(_("Bind UDP socket for DTLS")); - close(dtls_fd); + closesocket(dtls_fd); return -EINVAL; } } if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) { perror(_("UDP (DTLS) connect:\n")); - close(dtls_fd); + closesocket(dtls_fd); return -EINVAL; } @@ -546,7 +546,7 @@ int connect_dtls_socket(struct openconnect_info *vpninfo) ret = start_dtls_handshake(vpninfo, dtls_fd); if (ret) { - close(dtls_fd); + closesocket(dtls_fd); return ret; } @@ -566,7 +566,7 @@ void dtls_close(struct openconnect_info *vpninfo, int kill_handshake_too) { if (vpninfo->dtls_ssl) { DTLS_FREE(vpninfo->dtls_ssl); - close(vpninfo->dtls_fd); + closesocket(vpninfo->dtls_fd); FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds); FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds); FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds); @@ -575,7 +575,7 @@ void dtls_close(struct openconnect_info *vpninfo, int kill_handshake_too) } if (kill_handshake_too && vpninfo->new_dtls_ssl) { DTLS_FREE(vpninfo->new_dtls_ssl); - close(vpninfo->new_dtls_fd); + closesocket(vpninfo->new_dtls_fd); FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds); FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds); vpninfo->new_dtls_ssl = NULL; diff --git a/gnutls.c b/gnutls.c index 7644b48b..fb344fa6 100644 --- a/gnutls.c +++ b/gnutls.c @@ -1862,7 +1862,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_free(datum.data); gnutls_certificate_free_credentials(vpninfo->https_cred); vpninfo->https_cred = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -ENOMEM; } err = gnutls_x509_crt_list_import(certs, &nr_certs, &datum, @@ -1883,7 +1883,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_strerror(err)); gnutls_certificate_free_credentials(vpninfo->https_cred); vpninfo->https_cred = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } } @@ -1899,7 +1899,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) vpninfo->cafile, gnutls_strerror(err)); gnutls_certificate_free_credentials(vpninfo->https_cred); vpninfo->https_cred = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } } @@ -1911,7 +1911,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) _("Loading certificate failed. Aborting.\n")); gnutls_certificate_free_credentials(vpninfo->https_cred); vpninfo->https_cred = NULL; - close(ssl_sock); + closesocket(ssl_sock); return err; } } @@ -1937,7 +1937,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_strerror(err)); gnutls_deinit(vpninfo->https_sess); vpninfo->https_sess = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EIO; } @@ -1967,7 +1967,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n")); gnutls_deinit(vpninfo->https_sess); vpninfo->https_sess = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EINTR; } } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) { @@ -1975,7 +1975,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_strerror(err)); gnutls_deinit(vpninfo->https_sess); vpninfo->https_sess = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EIO; } else { /* non-fatal error or warning. Ignore it and continue */ @@ -2004,7 +2004,7 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final) vpninfo->https_sess = NULL; } if (vpninfo->ssl_fd != -1) { - close(vpninfo->ssl_fd); + closesocket(vpninfo->ssl_fd); FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds); FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds); FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds); diff --git a/openconnect-internal.h b/openconnect-internal.h index 231a2347..1e4c1430 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -369,6 +369,14 @@ void openconnect__unsetenv(const char *name); int openconnect__inet_aton(const char *cp, struct in_addr *addr); #endif +#ifdef _WIN32 +#define neterrno openconnect__win32_neterrno +int openconnect__win32_neterrno(); +#else +#define neterrno() errno +#define closesocket close +#endif + /* I always coded as if it worked like this. Now it does. */ #define realloc_inplace(p, size) do { \ void *__realloc_old = p; \ diff --git a/openssl.c b/openssl.c index 322644f1..eb6bc4e8 100644 --- a/openssl.c +++ b/openssl.c @@ -1283,7 +1283,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) _("Loading certificate failed. Aborting.\n")); SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; - close(ssl_sock); + closesocket(ssl_sock); return err; } check_certificate_expiry(vpninfo); @@ -1316,7 +1316,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) if (!b) { SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } @@ -1330,7 +1330,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -ENOENT; } @@ -1354,7 +1354,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) openconnect_report_ssl_errors(vpninfo); SSL_CTX_free(vpninfo->https_ctx); vpninfo->https_ctx = NULL; - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } } @@ -1386,7 +1386,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo) vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n")); openconnect_report_ssl_errors(vpninfo); SSL_free(https_ssl); - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } @@ -1395,14 +1395,14 @@ int openconnect_open_https(struct openconnect_info *vpninfo) if (is_cancel_pending(vpninfo, &rd_set)) { vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n")); SSL_free(https_ssl); - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } } if (verify_peer(vpninfo, https_ssl)) { SSL_free(https_ssl); - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } @@ -1430,7 +1430,7 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final) vpninfo->https_ssl = NULL; } if (vpninfo->ssl_fd != -1) { - close(vpninfo->ssl_fd); + closesocket(vpninfo->ssl_fd); FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds); FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds); FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds); diff --git a/ssl.c b/ssl.c index 613ef066..399e56a9 100644 --- a/ssl.c +++ b/ssl.c @@ -66,7 +66,7 @@ static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd, if (vpninfo->protect_socket) vpninfo->protect_socket(vpninfo->cbdata, sockfd); - if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS) + if (connect(sockfd, addr, addrlen) < 0 && neterrno() != EINPROGRESS) return -1; do { @@ -119,7 +119,7 @@ int connect_https_socket(struct openconnect_info *vpninfo) vpninfo->hostname); } if (ssl_sock >= 0) - close(ssl_sock); + closesocket(ssl_sock); return -EINVAL; } } else { @@ -242,7 +242,7 @@ int connect_https_socket(struct openconnect_info *vpninfo) if (!vpninfo->peer_addr) { vpn_progress(vpninfo, PRG_ERR, _("Failed to allocate sockaddr storage\n")); - close(ssl_sock); + closesocket(ssl_sock); return -ENOMEM; } vpninfo->peer_addrlen = rp->ai_addrlen; @@ -266,7 +266,7 @@ int connect_https_socket(struct openconnect_info *vpninfo) } break; } - close(ssl_sock); + closesocket(ssl_sock); ssl_sock = -1; } freeaddrinfo(result); @@ -282,7 +282,7 @@ int connect_https_socket(struct openconnect_info *vpninfo) if (vpninfo->proxy) { err = process_proxy(vpninfo, ssl_sock); if (err) { - close(ssl_sock); + closesocket(ssl_sock); return err; } }