From 473963ea000bfe23a0d4754988223e4e6e2fb3f2 Mon Sep 17 00:00:00 2001 From: "Sven M. Hallberg" Date: Fri, 29 Aug 2014 13:24:17 +0200 Subject: [PATCH] add (untested) implementation of sendmsg in terms of WSASendMsg --- src/compat/windows/wincompat.c | 81 ++++++++++++++++++++++++++++++++++ src/compat/windows/wincompat.h | 7 +++ 2 files changed, 88 insertions(+) diff --git a/src/compat/windows/wincompat.c b/src/compat/windows/wincompat.c index d0d239c..1a05d9f 100644 --- a/src/compat/windows/wincompat.c +++ b/src/compat/windows/wincompat.c @@ -8,6 +8,7 @@ static int wsa_errno(void) { switch(WSAGetLastError()) { + case WSAEACCES: return EACCES; case WSAECONNRESET: return ECONNRESET; case WSAEFAULT: return EFAULT; case WSAEINPROGRESS: return EINPROGRESS; @@ -16,9 +17,12 @@ static int wsa_errno(void) case WSAEMSGSIZE: return EMSGSIZE; case WSAENETDOWN: return ENETDOWN; case WSAENETRESET: return ENETRESET; + case WSAENOBUFS: return ENOBUFS; case WSAENOTCONN: return ENOTCONN; case WSAENOTSOCK: return ENOTSOCK; case WSAEOPNOTSUPP: return EOPNOTSUPP; + case WSAESHUTDOWN: return ESHUTDOWN; + case WSAETIMEDOUT: return ETIMEDOUT; case WSAEWOULDBLOCK: return EWOULDBLOCK; default: return EINVAL; @@ -95,6 +99,7 @@ ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) } // DWORD has one bit more than ssize_t on 32bit + // XXX check for this condition before the WSARecvMsg call if(bytesrcvd > SSIZE_MAX) { errno = EINVAL; return -1; @@ -109,6 +114,82 @@ ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) return bytesrcvd; } +ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) +{ + LPFN_WSASENDMSG WSASendMsg = NULL; + GUID wsaid = WSAID_WSASENDMSG; + DWORD b; + + DWORD bytessent; + WSAMSG wsamsg; + size_t i; + int r; + + // size_t is larger than DWORD on 64bit + if(msg->msg_iovlen > UINT32_MAX) { + errno = EINVAL; + return -1; + } + + // obtain the function pointer to WSASendMsg + r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER, + &wsaid, sizeof(wsaid), &WSASendMsg, sizeof(WSASendMsg), + &b, NULL, NULL); + if(r == SOCKET_ERROR) { + errno = wsa_errno(); + return -1; + } + assert(b == sizeof(WSASendMsg)); + assert(WSASendMsg != NULL); + + // convert msghdr to WSAMSG structure + wsamsg.name = msg->msg_name; + wsamsg.namelen = msg->msg_namelen; + wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF)); + wsamsg.dwBufferCount = msg->msg_iovlen; + wsamsg.Control.len = msg->msg_controllen; + wsamsg.Control.buf = msg->msg_control; + wsamsg.dwFlags = 0; // ignored + + if(wsamsg.lpBuffers == NULL) { + // malloc will have set errno + return -1; + } + + // re-wrap iovecs as WSABUFs + for(i=0; imsg_iovlen; i++) { + // size_t vs. u_long + if(msg->msg_iov[i].iov_len > ULONG_MAX) { + free(wsamsg.lpBuffers); + errno = EINVAL; + return -1; + } + + wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len; + wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base; + } + + r = WSASendMsg(sockfd, &wsamsg, flags, &bytessent, NULL, NULL); + + // the allocated WSABUF wrappers are no longer needed + free(wsamsg.lpBuffers); + + if(r == SOCKET_ERROR) { + // XXX do we need special handling for ENETRESET, ETIMEDOUT? + errno = wsa_errno(); + return -1; + } + + // DWORD has one bit more than ssize_t on 32bit + // XXX check for this condition before sending anything + if(bytessent > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + return bytessent; +} + int uname(struct utsname *buf) { SYSTEM_INFO si; diff --git a/src/compat/windows/wincompat.h b/src/compat/windows/wincompat.h index 6510183..f76dbc4 100644 --- a/src/compat/windows/wincompat.h +++ b/src/compat/windows/wincompat.h @@ -69,6 +69,13 @@ static inline struct cmsghdr *CMSG_NXTHDR(struct msghdr *m, struct cmsghdr *c) { ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); +// ESHUTDOWN does not seem to exist on Windows, even though WSAESHUTDOWN does. +// MingW doesn't define it and MSDN doesn't list it, so we alias it to EBADF. +// cf. http://msdn.microsoft.com/en-us/library/5814770t.aspx +#ifndef ESHUTDOWN +#define ESHUTDOWN EBADF +#endif + // Windows logically doesn't have uname, so we supply a replacement. -- 2.39.5