#include "wincompat.h"
#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdint.h>
+
+// helper: convert WSAGetLastError() to an errno constant
+static int wsa_errno(void)
+{
+ switch(WSAGetLastError()) {
+ case WSAECONNRESET: return ECONNRESET;
+ case WSAEFAULT: return EFAULT;
+ case WSAEINPROGRESS: return EINPROGRESS;
+ case WSAEINTR: return EINTR;
+ case WSAEINVAL: return EINVAL;
+ case WSAEMSGSIZE: return EMSGSIZE;
+ case WSAENETDOWN: return ENETDOWN;
+ case WSAENETRESET: return ENETRESET;
+ case WSAENOTCONN: return ENOTCONN;
+ case WSAENOTSOCK: return ENOTSOCK;
+ case WSAEOPNOTSUPP: return EOPNOTSUPP;
+ case WSAEWOULDBLOCK: return EWOULDBLOCK;
+ default:
+ return EINVAL;
+ }
+}
+
+ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
+{
+ LPFN_WSARECVMSG WSARecvMsg = NULL;
+ GUID wsaid = WSAID_WSARECVMSG;
+ DWORD b;
+
+ DWORD bytesrcvd;
+ 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 WSARecvMsg
+ r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &wsaid, sizeof(wsaid), &WSARecvMsg, sizeof(WSARecvMsg),
+ &b, NULL, NULL);
+ if(r == SOCKET_ERROR) {
+ errno = wsa_errno();
+ return -1;
+ }
+ assert(b == sizeof(WSARecvMsg));
+ assert(WSARecvMsg != 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 = (DWORD)flags;
+
+ // all flags that fit into dwFlags also fit through the flags argument
+ assert(sizeof(DWORD) <= sizeof(flags));
+
+ if(wsamsg.lpBuffers == NULL) {
+ // malloc will have set errno
+ return -1;
+ }
+
+ // re-wrap iovecs as WSABUFs
+ for(i=0; i<msg->msg_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 = WSARecvMsg(sockfd, &wsamsg, &bytesrcvd, 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, EMSGSIZE, ETIMEDOUT?
+ errno = wsa_errno();
+ return -1;
+ }
+
+ // DWORD has one bit more than ssize_t on 32bit
+ if(bytesrcvd > SSIZE_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // transfer results from wsamsg to msg
+ // NB: the data and control buffers are shared
+ msg->msg_controllen = wsamsg.Control.len;
+ msg->msg_flags = (int)wsamsg.dwFlags;
+ // all flags that fit into dwFlags also fit into msg_flags (see above)
+
+ return bytesrcvd;
+}
int uname(struct utsname *buf)
{
#ifndef foowincompatfoo
#define foowincompatfoo
+// This file and its companion wincompat.c provide some Posix interfaces to
+// Windows APIs so the rest of the code can keep using them.
+
+
+// require at least Windows Vista
#undef WINVER
#undef _WIN32_WINNT
-
-#define WINVER 0x0600 // Vista
+#define WINVER 0x0600
#define _WIN32_WINNT WINVER
#include <winsock2.h>
#include <ws2tcpip.h>
+#include <mswsock.h>
+
+
+// Winsock doesn't have recvmsg/sendmsg but offers the same functionality
+// with WSARecvMsg/WSASendMsg, so we implement the former in terms of the
+// latter.
+
+struct iovec { /* Scatter/gather array items */
+ void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes to transfer */
+};
+
+struct msghdr {
+ void *msg_name; /* optional address */
+ socklen_t msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ size_t msg_iovlen; /* # elements in msg_iov */
+ void *msg_control; /* ancillary data, see below */
+ size_t msg_controllen; /* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+
+// MSDN says this struct is called wsacmsghdr but MingW uses _WSACMSGHDR.
+// TODO: Verify what it is on actual Windows.
+// cf. http://msdn.microsoft.com/en-us/library/ms741645(v=vs.85).aspx
+#ifdef __MINGW32__
+#define cmsghdr _WSACMSGHDR // as in 'struct cmsghdr'
+#else
+#define cmsghdr wsacmsghdr // as in 'struct cmsghdr'
+#endif
+
+static inline struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *m) {
+ WSAMSG wm;
+ wm.Control.len = m->msg_controllen;
+ wm.Control.buf = m->msg_control;
+ return WSA_CMSG_FIRSTHDR(&wm);
+}
+
+static inline struct cmsghdr *CMSG_NXTHDR(struct msghdr *m, struct cmsghdr *c) {
+ WSAMSG wm;
+ wm.Control.len = m->msg_controllen;
+ wm.Control.buf = m->msg_control;
+ return WSA_CMSG_NXTHDR(&wm, c);
+}
+
+#define CMSG_SPACE(len) WSA_CMSG_SPACE(len)
+#define CMSG_LEN(len) WSA_CMSG_LEN(len)
+
+// we're going to be naughty and redefine CMSG_DATA as an alias even though it
+// is also a constant defined in wincrypt.h which we don't care about.
+#undef CMSG_DATA
+#define CMSG_DATA(c) WSA_CMSG_DATA(c)
+
+ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
+ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
+
+// Windows logically doesn't have uname, so we supply a replacement.
struct utsname {
char sysname[9]; /* Operating system name (e.g., "Linux") */