Merge branch 'win-errno'

Improves errno handling for Winsock2 compatibility functions.
This commit is contained in:
Martin Willi 2014-06-17 15:24:06 +02:00
commit a2c2ce9693
2 changed files with 278 additions and 65 deletions

View File

@ -309,6 +309,66 @@ char* getpass(const char *prompt)
return buf; 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 * Set errno for a function setting WSA error on failure
*/ */
@ -316,74 +376,66 @@ static int wserr(int retval)
{ {
if (retval < 0) 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: if (map[i].wsa == wsa)
errno = EBADF; {
break; errno = map[i].err;
case WSAENETDOWN: return retval;
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;
} }
errno = ENOENT;
return retval;
} }
else errno = 0;
{
errno = 0;
}
return retval; return retval;
} }
@ -400,6 +452,90 @@ static bool check_dontwait(int *flags)
return FALSE; 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 * See header
*/ */

View File

@ -272,6 +272,63 @@ char* getpass(const char *prompt);
#define SHUT_WR SD_SEND #define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH #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 * close(2) working for file handles and Winsock sockets
*/ */
@ -304,6 +361,26 @@ 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, ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen); 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
*/
#define strerror_s strerror_s_extended
int strerror_s_extended(char *buf, size_t buflen, int errnum);
/**
* 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 * MinGW does provide extended errno values. Windows itself knowns them
* for POSIX compatibility; we define them as well. * for POSIX compatibility; we define them as well.