From 8b5d41a2746cfb23058f52d2d70f25c18f6f8cb8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 11 Jun 2014 11:08:03 +0200 Subject: [PATCH 1/4] windows: Wrap most Winsock2 Posix functions to set errno While Winsock provides many Posix compatibility functions, they do not set errno, but use WSAGetLastError() for error reporting. The wrapped functions derive an errno from WSAGetLastError() on failure. --- src/libstrongswan/utils/windows.c | 206 ++++++++++++++++++++---------- src/libstrongswan/utils/windows.h | 57 +++++++++ 2 files changed, 198 insertions(+), 65 deletions(-) diff --git a/src/libstrongswan/utils/windows.c b/src/libstrongswan/utils/windows.c index 741d199ec..6963086b7 100644 --- a/src/libstrongswan/utils/windows.c +++ b/src/libstrongswan/utils/windows.c @@ -316,74 +316,66 @@ static int wserr(int retval) { if (retval < 0) { - switch (WSAGetLastError()) + static const struct { + DWORD wsa; + int err; + } map[] = { + { WSANOTINITIALISED, EBADF }, + { WSAENETDOWN, ENETDOWN }, + { WSAENETRESET, ENETRESET }, + { WSAECONNABORTED, ECONNABORTED }, + { WSAESHUTDOWN, ECONNABORTED }, + { WSAEACCES, EACCES }, + { WSAEINTR, EINTR }, + { WSAEINPROGRESS, EINPROGRESS }, + { WSAEFAULT, EFAULT }, + { WSAENOBUFS, ENOBUFS }, + { WSAENOTSOCK, ENOTSOCK }, + { WSAEOPNOTSUPP, EOPNOTSUPP }, + { WSAEWOULDBLOCK, EWOULDBLOCK }, + { WSAEMSGSIZE, EMSGSIZE }, + { WSAEINVAL, EINVAL }, + { WSAENOTCONN, ENOTCONN }, + { WSAEHOSTUNREACH, EHOSTUNREACH }, + { WSAENETUNREACH, ENETUNREACH }, + { WSAECONNABORTED, ECONNABORTED }, + { WSAECONNRESET, ECONNRESET }, + { WSAETIMEDOUT, ETIMEDOUT }, + { WSAEMFILE, EMFILE }, + { WSAEALREADY, EALREADY }, + { WSAEDESTADDRREQ, EDESTADDRREQ }, + { WSAEISCONN, EISCONN }, + { WSAEOPNOTSUPP, EOPNOTSUPP }, + { WSAEPROTOTYPE, EPROTOTYPE }, + { WSAENOPROTOOPT, ENOPROTOOPT }, + { WSAEPROTONOSUPPORT, EPROTONOSUPPORT }, + { WSAEPFNOSUPPORT, EPROTONOSUPPORT }, + { WSAEAFNOSUPPORT, EAFNOSUPPORT }, + { WSAEADDRNOTAVAIL, EADDRNOTAVAIL }, + { WSAEADDRINUSE, EADDRINUSE }, + { WSAETIMEDOUT, ETIMEDOUT }, + { WSAECONNREFUSED, ECONNREFUSED }, + { WSAELOOP, ELOOP }, + { WSAENAMETOOLONG, ENAMETOOLONG }, + { WSAENOTEMPTY, ENOTEMPTY }, + { WSAEPROTOTYPE, EPROTOTYPE }, + { WSAVERNOTSUPPORTED, ENOTSUP }, + }; + DWORD wsa, i; + + wsa = WSAGetLastError(); + for (i = 0; i < countof(map); i++) { - case WSANOTINITIALISED: - errno = EBADF; - break; - case WSAENETDOWN: - errno = ENETDOWN; - break; - case WSAENETRESET: - errno = ENETRESET; - break; - case WSAESHUTDOWN: - errno = ECONNABORTED; - break; - case WSAEACCES: - errno = EACCES; - break; - case WSAEINTR: - errno = EINTR; - break; - case WSAEINPROGRESS: - errno = EINPROGRESS; - break; - case WSAEFAULT: - errno = EFAULT; - break; - case WSAENOBUFS: - errno = ENOBUFS; - break; - case WSAENOTSOCK: - errno = ENOTSOCK; - break; - case WSAEOPNOTSUPP: - errno = EOPNOTSUPP; - break; - case WSAEWOULDBLOCK: - errno = EWOULDBLOCK; - break; - case WSAEMSGSIZE: - errno = EMSGSIZE; - break; - case WSAEINVAL: - errno = EINVAL; - break; - case WSAENOTCONN: - errno = ENOTCONN; - break; - case WSAEHOSTUNREACH: - errno = EHOSTUNREACH; - break; - case WSAECONNABORTED: - errno = ECONNABORTED; - break; - case WSAECONNRESET: - errno = ECONNRESET; - break; - case WSAETIMEDOUT: - errno = ETIMEDOUT; - break; - default: - errno = ENOENT; - break; + if (map[i].wsa == wsa) + { + errno = map[i].err; + return retval; + } } + errno = ENOENT; + return retval; } - else - { - errno = 0; - } + errno = 0; return retval; } @@ -400,6 +392,90 @@ static bool check_dontwait(int *flags) return FALSE; } +/** + * See header + */ +#undef shutdown +int windows_shutdown(int sockfd, int how) +{ + return wserr(shutdown(sockfd, how)); +} + +/** + * See header + */ +#undef accept +int windows_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + return wserr(accept(sockfd, addr, addrlen)); +} + +/** + * See header + */ +#undef bind +int windows_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + return wserr(bind(sockfd, addr, addrlen)); +} + +/** + * See header + */ +#undef connect +int windows_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + return wserr(connect(sockfd, addr, addrlen)); +} + +/** + * See header + */ +#undef getsockname +int windows_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + return wserr(getsockname(sockfd, addr, addrlen)); +} + +/** + * See header + */ +#undef getsockopt +int windows_getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen) +{ + return wserr(getsockopt(sockfd, level, optname, optval, optlen)); +} + +/** + * See header + */ +#undef setsockopt +int windows_setsockopt(int sockfd, int level, int optname, + const void *optval, socklen_t optlen) +{ + return wserr(setsockopt(sockfd, level, optname, optval, optlen)); +} + +/** + * See header + */ +#undef socket +int windows_socket(int domain, int type, int protocol) +{ + return wserr(socket(domain, type, protocol)); +} + +/** + * See header + */ +#undef select +int windows_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) +{ + return wserr(select(nfds, readfds, writefds, exceptfds, timeout)); +} + /** * See header */ diff --git a/src/libstrongswan/utils/windows.h b/src/libstrongswan/utils/windows.h index fd4338455..991bb2a55 100644 --- a/src/libstrongswan/utils/windows.h +++ b/src/libstrongswan/utils/windows.h @@ -272,6 +272,63 @@ char* getpass(const char *prompt); #define SHUT_WR SD_SEND #define SHUT_RDWR SD_BOTH +/** + * shutdown(2) setting errno + */ +#define shutdown windows_shutdown +int windows_shutdown(int sockfd, int how); + +/** + * accept(2) setting errno + */ +#define accept windows_accept +int windows_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +/** + * bind(2) setting errno + */ +#define bind windows_bind +int windows_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +/** + * connect(2) setting errno + */ +#define connect windows_connect +int windows_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +/** + * getsockname(2) setting errno + */ +#define getsockname windows_getsockname +int windows_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +/** + * getsockopt(2) setting errno + */ +#define getsockopt windows_getsockopt +int windows_getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen); + +/** + * setsockopt(2) setting errno + */ +#define setsockopt windows_setsockopt +int windows_setsockopt(int sockfd, int level, int optname, + const void *optval, socklen_t optlen); + +/** + * socket(2) setting errno + */ +#define socket windows_socket +int windows_socket(int domain, int type, int protocol); + +/** + * select(2) setting errno + */ +#define select windows_select +int windows_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); + /** * close(2) working for file handles and Winsock sockets */ From c2119cded4f743cdf2bf6320af82069b5428f256 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 11 Jun 2014 11:38:52 +0200 Subject: [PATCH 2/4] windows: Implement strerror_r using strerror_s --- src/libstrongswan/utils/windows.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libstrongswan/utils/windows.h b/src/libstrongswan/utils/windows.h index 991bb2a55..ac940e644 100644 --- a/src/libstrongswan/utils/windows.h +++ b/src/libstrongswan/utils/windows.h @@ -361,6 +361,15 @@ ssize_t windows_send(int sockfd, const void *buf, size_t len, int flags); ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +/** + * strerror_r(2) replacement, XSI variant + */ +static inline int strerror_r(int errnum, char *buf, size_t buflen) +{ + return strerror_s(buf, buflen, errnum); +} +#define HAVE_STRERROR_R /* but not STRERROR_R_CHAR_P */ + /** * MinGW does provide extended errno values. Windows itself knowns them * for POSIX compatibility; we define them as well. From 1bcf850738d81f5aeda071d4c72912909bfe6447 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 11 Jun 2014 12:07:34 +0200 Subject: [PATCH 3/4] windows: Extend strerror_r/s by extended POSIX errno strings --- src/libstrongswan/utils/windows.c | 60 +++++++++++++++++++++++++++++++ src/libstrongswan/utils/windows.h | 6 ++++ 2 files changed, 66 insertions(+) diff --git a/src/libstrongswan/utils/windows.c b/src/libstrongswan/utils/windows.c index 6963086b7..397f3b156 100644 --- a/src/libstrongswan/utils/windows.c +++ b/src/libstrongswan/utils/windows.c @@ -309,6 +309,66 @@ char* getpass(const char *prompt) return buf; } +/** + * See header. + */ +#undef strerror_s +int strerror_s_extended(char *buf, size_t buflen, int errnum) +{ + const char *errstr [] = { + /* EADDRINUSE */ "Address in use", + /* EADDRNOTAVAIL */ "Address not available", + /* EAFNOSUPPORT */ "Address family not supported", + /* EALREADY */ "Connection already in progress", + /* EBADMSG */ "Bad message", + /* ECANCELED */ "Operation canceled", + /* ECONNABORTED */ "Connection aborted", + /* ECONNREFUSED */ "Connection refused", + /* ECONNRESET */ "Connection reset", + /* EDESTADDRREQ */ "Destination address required", + /* EHOSTUNREACH */ "Host is unreachable", + /* EIDRM */ "Identifier removed", + /* EINPROGRESS */ "Operation in progress", + /* EISCONN */ "Socket is connected", + /* ELOOP */ "Too many levels of symbolic links", + /* EMSGSIZE */ "Message too large", + /* ENETDOWN */ "Network is down", + /* ENETRESET */ "Connection aborted by network", + /* ENETUNREACH */ "Network unreachable", + /* ENOBUFS */ "No buffer space available", + /* ENODATA */ "No message is available", + /* ENOLINK */ "No link", + /* ENOMSG */ "No message of the desired type", + /* ENOPROTOOPT */ "Protocol not available", + /* ENOSR */ "No stream resources", + /* ENOSTR */ "Not a stream", + /* ENOTCONN */ "The socket is not connected", + /* ENOTRECOVERABLE */ "State not recoverable", + /* ENOTSOCK */ "Not a socket", + /* ENOTSUP */ "Not supported", + /* EOPNOTSUPP */ "Operation not supported on socket", + /* EOTHER */ "Other error", + /* EOVERFLOW */ "Value too large to be stored in data type", + /* EOWNERDEAD */ "Previous owner died", + /* EPROTO */ "Protocol error", + /* EPROTONOSUPPORT */ "Protocol not supported", + /* EPROTOTYPE */ "Protocol wrong type for socket", + /* ETIME */ "Timeout", + /* ETIMEDOUT */ "Connection timed out", + /* ETXTBSY */ "Text file busy", + /* EWOULDBLOCK */ "Operation would block", + }; + int offset = EADDRINUSE; + + if (errnum < offset || errnum > offset + countof(errstr)) + { + return strerror_s(buf, buflen, errnum); + } + strncpy(buf, errstr[errnum - offset], buflen); + buf[buflen - 1] = '\0'; + return 0; +} + /** * Set errno for a function setting WSA error on failure */ diff --git a/src/libstrongswan/utils/windows.h b/src/libstrongswan/utils/windows.h index ac940e644..053354f25 100644 --- a/src/libstrongswan/utils/windows.h +++ b/src/libstrongswan/utils/windows.h @@ -361,6 +361,12 @@ ssize_t windows_send(int sockfd, const void *buf, size_t len, int flags); ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +/** + * strerror_s, but supporting POSIX compatiblity errno >= 100 + */ +#define strerror_s strerror_s_extended +int strerror_s_extended(char *buf, size_t buflen, int errnum); + /** * strerror_r(2) replacement, XSI variant */ From dff39a4c5b0a0d560346e59244c085c552f9dabb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 11 Jun 2014 17:10:19 +0200 Subject: [PATCH 4/4] windows: Declare strerror_s() Older MinGW versions seem to miss this function declaration. Fixes build on Travis using Ubuntu 12.04. --- src/libstrongswan/utils/windows.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstrongswan/utils/windows.h b/src/libstrongswan/utils/windows.h index 053354f25..a06a89ebf 100644 --- a/src/libstrongswan/utils/windows.h +++ b/src/libstrongswan/utils/windows.h @@ -361,6 +361,11 @@ ssize_t windows_send(int sockfd, const void *buf, size_t len, int flags); ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +/** + * Declaration missing on older WinGW + */ +_CRTIMP errno_t strerror_s(char *buf, size_t size, int errnum); + /** * strerror_s, but supporting POSIX compatiblity errno >= 100 */