From b0b6b56bb75a17476d9da0eadc3e0d2d3aad586a Mon Sep 17 00:00:00 2001 From: mehrdadn Date: Fri, 20 Dec 2019 12:32:07 -0800 Subject: [PATCH] Platform shims for Windows (#6548) * Platform shims for Windows * Satisfy linter --- bazel/BUILD.plasma | 3 + src/shims/windows/arpa/inet.h | 4 + src/shims/windows/getopt.cc | 103 +++++++++++++++++ src/shims/windows/getopt.h | 8 ++ src/shims/windows/msg.cc | 190 ++++++++++++++++++++++++++++++++ src/shims/windows/netdb.h | 6 + src/shims/windows/netinet/in.h | 4 + src/shims/windows/netinet/tcp.h | 4 + src/shims/windows/poll.h | 7 ++ src/shims/windows/pthread.h | 13 +++ src/shims/windows/socketpair.cc | 138 +++++++++++++++++++++++ src/shims/windows/strings.h | 12 ++ src/shims/windows/sys/ioctl.h | 4 + src/shims/windows/sys/mman.h | 39 +++++++ src/shims/windows/sys/select.h | 4 + src/shims/windows/sys/socket.h | 46 ++++++++ src/shims/windows/sys/statvfs.h | 4 + src/shims/windows/sys/syslog.h | 4 + src/shims/windows/sys/time.cc | 18 +++ src/shims/windows/sys/time.h | 15 +++ src/shims/windows/sys/un.h | 17 +++ src/shims/windows/sys/wait.h | 4 + src/shims/windows/syslog.h | 1 + src/shims/windows/unistd.cc | 10 ++ src/shims/windows/unistd.h | 37 +++++++ 25 files changed, 695 insertions(+) create mode 100644 src/shims/windows/arpa/inet.h create mode 100644 src/shims/windows/getopt.cc create mode 100644 src/shims/windows/getopt.h create mode 100644 src/shims/windows/msg.cc create mode 100644 src/shims/windows/netdb.h create mode 100644 src/shims/windows/netinet/in.h create mode 100644 src/shims/windows/netinet/tcp.h create mode 100644 src/shims/windows/poll.h create mode 100644 src/shims/windows/pthread.h create mode 100644 src/shims/windows/socketpair.cc create mode 100644 src/shims/windows/strings.h create mode 100644 src/shims/windows/sys/ioctl.h create mode 100644 src/shims/windows/sys/mman.h create mode 100644 src/shims/windows/sys/select.h create mode 100644 src/shims/windows/sys/socket.h create mode 100644 src/shims/windows/sys/statvfs.h create mode 100644 src/shims/windows/sys/syslog.h create mode 100644 src/shims/windows/sys/time.cc create mode 100644 src/shims/windows/sys/time.h create mode 100644 src/shims/windows/sys/un.h create mode 100644 src/shims/windows/sys/wait.h create mode 100644 src/shims/windows/syslog.h diff --git a/bazel/BUILD.plasma b/bazel/BUILD.plasma index e1c422139..eddd5e287 100644 --- a/bazel/BUILD.plasma +++ b/bazel/BUILD.plasma @@ -186,6 +186,9 @@ cc_library( ], strip_include_prefix = "cpp/src", visibility = ["//visibility:public"], + deps = [ + "@com_github_ray_project_ray//:platform_shims", + ], ) cc_library( diff --git a/src/shims/windows/arpa/inet.h b/src/shims/windows/arpa/inet.h new file mode 100644 index 000000000..ee3f2f94f --- /dev/null +++ b/src/shims/windows/arpa/inet.h @@ -0,0 +1,4 @@ +#ifndef INET_H +#define INET_H + +#endif /* INET_H */ diff --git a/src/shims/windows/getopt.cc b/src/shims/windows/getopt.cc new file mode 100644 index 000000000..92816c2ef --- /dev/null +++ b/src/shims/windows/getopt.cc @@ -0,0 +1,103 @@ +/* +From: + http://stackoverflow.com/a/17195644/541686 +Also posted on: + https://gist.github.com/superwills/5815344 +Previously from: + http://www.raspberryginger.com/jbailey/minix/html/lib_2posix_2getopt_8c-source.html +*/ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +static char EMSG[] = ""; + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char *const nargv[], const char *ostr) { + static char *place = EMSG; /* option letter processing */ + const char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') return (-1); + if (!*place) ++optind; + if (opterr && *ostr != ':') (void)printf("illegal option -- %c\n", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') return (BADARG); + if (opterr) (void)printf("option requires an argument -- %c\n", optopt); + return (BADCH); + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/src/shims/windows/getopt.h b/src/shims/windows/getopt.h new file mode 100644 index 000000000..48060ed33 --- /dev/null +++ b/src/shims/windows/getopt.h @@ -0,0 +1,8 @@ +#ifndef GETOPT_H +#define GETOPT_H + +extern char *optarg; +extern int optind, opterr, optopt; +int getopt(int nargc, char *const nargv[], const char *ostr); + +#endif /* GETOPT_H */ diff --git a/src/shims/windows/msg.cc b/src/shims/windows/msg.cc new file mode 100644 index 000000000..f00581bda --- /dev/null +++ b/src/shims/windows/msg.cc @@ -0,0 +1,190 @@ +#include +#include + +#include // include before other socket headers on Windows + +#include +#include + +#pragma comment(lib, "IPHlpAPI.lib") + +int socketpair(int domain, int type, int protocol, int sv[2]) { + if ((domain != AF_UNIX && domain != AF_INET) || type != SOCK_STREAM) { + return (int)INVALID_SOCKET; + } + SOCKET sockets[2]; + int r = dumb_socketpair(sockets); + sv[0] = (int)sockets[0]; + sv[1] = (int)sockets[1]; + return r; +} + +static DWORD getsockpid(SOCKET client) { + /* http://stackoverflow.com/a/25431340 */ + DWORD pid = 0; + + struct sockaddr_in Server = {0}; + int ServerSize = sizeof(Server); + + struct sockaddr_in Client = {0}; + int ClientSize = sizeof(Client); + + if ((getsockname(client, (struct sockaddr *)&Server, &ServerSize) == 0) && + (getpeername(client, (struct sockaddr *)&Client, &ClientSize) == 0)) { + struct _MIB_TCPTABLE2 *TcpTable = NULL; + ULONG TcpTableSize = 0; + ULONG result; + do { + result = GetTcpTable2(TcpTable, &TcpTableSize, TRUE); + if (result != ERROR_INSUFFICIENT_BUFFER) { + break; + } + free(TcpTable); + TcpTable = (struct _MIB_TCPTABLE2 *)malloc(TcpTableSize); + } while (TcpTable != NULL); + + if (result == NO_ERROR) { + for (DWORD dw = 0; dw < TcpTable->dwNumEntries; ++dw) { + struct _MIB_TCPROW2 *row = &(TcpTable->table[dw]); + if ((row->dwState == 5 /* MIB_TCP_STATE_ESTAB */) && + (row->dwLocalAddr == Client.sin_addr.s_addr) && + ((row->dwLocalPort & 0xFFFF) == Client.sin_port) && + (row->dwRemoteAddr == Server.sin_addr.s_addr) && + ((row->dwRemotePort & 0xFFFF) == Server.sin_port)) { + pid = row->dwOwningPid; + break; + } + } + } + + free(TcpTable); + } + + return pid; +} + +ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags) { + ssize_t result = -1; + struct cmsghdr *header = CMSG_FIRSTHDR(msg); + if (header->cmsg_level == SOL_SOCKET && header->cmsg_type == SCM_RIGHTS) { + /* We're trying to send over a handle of some kind. + * We have to look up which process we're communicating with, + * open a handle to it, and then duplicate our handle into it. + * However, the first two steps cannot be done atomically. + * Therefore, this code HAS A RACE CONDITIONS and is therefore NOT SECURE. + * In the absense of a malicious actor, though, it is exceedingly unlikely + * that the child process closes AND that its process ID is reassigned + * to another existing process. + */ + struct msghdr const old_msg = *msg; + int *const pfd = (int *)CMSG_DATA(header); + msg->msg_control = NULL; + msg->msg_controllen = 0; + WSAPROTOCOL_INFO protocol_info = {0}; + /* assume socket if it's a pipe, until proven otherwise */ + BOOL is_socket = GetFileType((HANDLE)(SOCKET)(*pfd)) == FILE_TYPE_PIPE; + DWORD const target_pid = getsockpid(sockfd); + HANDLE target_process = NULL; + if (target_pid) { + if (is_socket) { + result = WSADuplicateSocket(*pfd, target_pid, &protocol_info); + if (result == -1 && WSAGetLastError() == WSAENOTSOCK) { + is_socket = FALSE; + } + } + if (!is_socket) { + /* This is a regular handle... fit it into the same struct */ + target_process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, target_pid); + if (target_process) { + if (DuplicateHandle(GetCurrentProcess(), (HANDLE)(intptr_t)*pfd, target_process, + (HANDLE *)&protocol_info, 0, TRUE, DUPLICATE_SAME_ACCESS)) { + result = 0; + } + } + } + } + if (result == 0) { + int const nbufs = msg->dwBufferCount + 1; + WSABUF *const bufs = (struct _WSABUF *)_alloca(sizeof(*msg->lpBuffers) * nbufs); + bufs[0].buf = (char *)&protocol_info; + bufs[0].len = sizeof(protocol_info); + memcpy(&bufs[1], msg->lpBuffers, msg->dwBufferCount * sizeof(*msg->lpBuffers)); + DWORD nb; + msg->lpBuffers = bufs; + msg->dwBufferCount = nbufs; + GUID wsaid_WSASendMsg = { + 0xa441e712, 0x754f, 0x43ca, {0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d}}; + typedef INT PASCAL WSASendMsg_t( + SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, LPDWORD lpNumberOfBytesSent, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WSASendMsg_t *WSASendMsg = NULL; + result = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid_WSASendMsg, + sizeof(wsaid_WSASendMsg), &WSASendMsg, sizeof(WSASendMsg), &nb, + NULL, 0); + if (result == 0) { + result = (*WSASendMsg)(sockfd, msg, flags, &nb, NULL, NULL) == 0 + ? (ssize_t)(nb - sizeof(protocol_info)) + : 0; + } + } + if (result != 0 && target_process && !is_socket) { + /* we failed to send the handle, and it needs cleaning up! */ + HANDLE duplicated_back = NULL; + if (DuplicateHandle(target_process, *(HANDLE *)&protocol_info, GetCurrentProcess(), + &duplicated_back, 0, FALSE, DUPLICATE_CLOSE_SOURCE)) { + CloseHandle(duplicated_back); + } + } + if (target_process) { + CloseHandle(target_process); + } + *msg = old_msg; + } + return result; +} + +ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) { + int result = -1; + struct cmsghdr *header = CMSG_FIRSTHDR(msg); + if (msg->msg_controllen && flags == 0 /* We can't send flags on Windows... */) { + struct msghdr const old_msg = *msg; + msg->msg_control = NULL; + msg->msg_controllen = 0; + WSAPROTOCOL_INFO protocol_info = {0}; + int const nbufs = msg->dwBufferCount + 1; + WSABUF *const bufs = (struct _WSABUF *)_alloca(sizeof(*msg->lpBuffers) * nbufs); + bufs[0].buf = (char *)&protocol_info; + bufs[0].len = sizeof(protocol_info); + memcpy(&bufs[1], msg->lpBuffers, msg->dwBufferCount * sizeof(*msg->lpBuffers)); + typedef INT PASCAL WSARecvMsg_t( + SOCKET s, LPWSAMSG lpMsg, LPDWORD lpNumberOfBytesRecvd, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WSARecvMsg_t *WSARecvMsg = NULL; + DWORD nb; + GUID wsaid_WSARecvMsg = { + 0xf689d7c8, 0x6f1f, 0x436b, {0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22}}; + result = + WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid_WSARecvMsg, + sizeof(wsaid_WSARecvMsg), &WSARecvMsg, sizeof(WSARecvMsg), &nb, NULL, 0); + if (result == 0) { + result = (*WSARecvMsg)(sockfd, msg, &nb, NULL, NULL) == 0 + ? (ssize_t)(nb - sizeof(protocol_info)) + : 0; + } + if (result == 0) { + int *const pfd = (int *)CMSG_DATA(header); + if (protocol_info.iSocketType == 0 && protocol_info.iProtocol == 0) { + *pfd = *(int *)&protocol_info; + } else { + *pfd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, + &protocol_info, 0, 0); + } + header->cmsg_level = SOL_SOCKET; + header->cmsg_type = SCM_RIGHTS; + } + *msg = old_msg; + } + return result; +} diff --git a/src/shims/windows/netdb.h b/src/shims/windows/netdb.h new file mode 100644 index 000000000..7afa2197f --- /dev/null +++ b/src/shims/windows/netdb.h @@ -0,0 +1,6 @@ +#ifndef NETDB_H +#define NETDB_H + +#include + +#endif /* NETDB_H */ diff --git a/src/shims/windows/netinet/in.h b/src/shims/windows/netinet/in.h new file mode 100644 index 000000000..a60db3e05 --- /dev/null +++ b/src/shims/windows/netinet/in.h @@ -0,0 +1,4 @@ +#ifndef IN_H +#define IN_H + +#endif /* IN_H */ diff --git a/src/shims/windows/netinet/tcp.h b/src/shims/windows/netinet/tcp.h new file mode 100644 index 000000000..4c6d384e2 --- /dev/null +++ b/src/shims/windows/netinet/tcp.h @@ -0,0 +1,4 @@ +#ifndef TCP_H +#define TCP_H + +#endif /* TCP_H */ diff --git a/src/shims/windows/poll.h b/src/shims/windows/poll.h new file mode 100644 index 000000000..f6b2d62ff --- /dev/null +++ b/src/shims/windows/poll.h @@ -0,0 +1,7 @@ +#ifndef POLL_H +#define POLL_H + +typedef unsigned long int nfds_t; +int poll(struct pollfd fds[], nfds_t nfds, int timeout); + +#endif /* POLL_H */ diff --git a/src/shims/windows/pthread.h b/src/shims/windows/pthread.h new file mode 100644 index 000000000..88a4eef16 --- /dev/null +++ b/src/shims/windows/pthread.h @@ -0,0 +1,13 @@ +#ifndef _PTHREAD_H +#define _PTHREAD_H 1 + +#ifndef _INC_WINDOWS +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +typedef CRITICAL_SECTION pthread_mutex_t; + +#endif /* pthread.h */ diff --git a/src/shims/windows/socketpair.cc b/src/shims/windows/socketpair.cc new file mode 100644 index 000000000..15ad0a3ff --- /dev/null +++ b/src/shims/windows/socketpair.cc @@ -0,0 +1,138 @@ +/* socketpair.c +Copyright 2007, 2010 by Nathan C. Myers +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + The name of the author must not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Changes: + * 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements + * git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54 + * github.com/GerHobbelt/selectable-socketpair + * always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64 + * and UNIX/other platforms + * 2013-07-18: Change to BSD 3-clause license + * 2010-03-31: + * set addr to 127.0.0.1 because win32 getsockname does not always set it. + * 2010-02-25: + * set SO_REUSEADDR option to avoid leaking some windows resource. + * Windows System Error 10049, "Event ID 4226 TCP/IP has reached + * the security limit imposed on the number of concurrent TCP connect + * attempts." Bleah. + * 2007-04-25: + * preserve value of WSAGetLastError() on all error returns. + * 2007-04-22: (Thanks to Matthew Gregan ) + * s/EINVAL/WSAEINVAL/ fix trivial compile failure + * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout + * of a child process. + * add argument make_overlapped + */ + +#include + +#ifdef _WIN32 +#include +#include +#include /* socklen_t, et al (MSVC20xx) */ +#else +#include +#include +#include +#endif + +#ifdef WIN32 + +/* dumb_socketpair: + * If make_overlapped is nonzero, both sockets created will be usable for + * "overlapped" operations via WSASend etc. If make_overlapped is zero, + * socks[0] (only) will be usable with regular ReadFile etc., and thus + * suitable for use as stdin or stdout of a child process. Note that the + * sockets must be closed with closesocket() regardless. + */ + +int dumb_socketpair(SOCKET socks[2]) { + union { + struct sockaddr_in inaddr; + struct sockaddr addr; + } a; + SOCKET listener; + int e; + socklen_t addrlen = sizeof(a.inaddr); + int reuse = 1; + + if (socks == 0) { + return SOCKET_ERROR; + } + socks[0] = socks[1] = -1; + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listener == -1) return SOCKET_ERROR; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + for (;;) { + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, + (socklen_t)sizeof(reuse)) == -1) + break; + if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) break; + + memset(&a, 0, sizeof(a)); + if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) break; + // win32 getsockname may only set the port number, p=0.0005. + // ( http://msdn.microsoft.com/library/ms738543.aspx ): + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_family = AF_INET; + + if (listen(listener, 1) == SOCKET_ERROR) break; + + socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0); + if (socks[0] == -1) break; + if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) break; + + socks[1] = accept(listener, NULL, NULL); + if (socks[1] == -1) break; + + closesocket(listener); + return 0; + } + + closesocket(listener); + closesocket(socks[0]); + closesocket(socks[1]); + socks[0] = socks[1] = -1; + return SOCKET_ERROR; +} +#else +int dumb_socketpair(int socks[2], int dummy) { + if (socks == 0) { + errno = EINVAL; + return -1; + } + dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, socks); + if (dummy) socks[0] = socks[1] = -1; + return dummy; +} +#endif diff --git a/src/shims/windows/strings.h b/src/shims/windows/strings.h new file mode 100644 index 000000000..03c885a19 --- /dev/null +++ b/src/shims/windows/strings.h @@ -0,0 +1,12 @@ +#ifndef STRINGS_H +#define STRINGS_H + +#include + +static int strcasecmp(const char *s1, const char *s2) { return stricmp(s1, s2); } + +static int strncasecmp(const char *s1, const char *s2, size_t n) { + return strnicmp(s1, s2, n); +} + +#endif /* STRINGS_H */ diff --git a/src/shims/windows/sys/ioctl.h b/src/shims/windows/sys/ioctl.h new file mode 100644 index 000000000..00f7a55ed --- /dev/null +++ b/src/shims/windows/sys/ioctl.h @@ -0,0 +1,4 @@ +#ifndef IOCTL_H +#define IOCTL_H + +#endif /* IOCTL_H */ diff --git a/src/shims/windows/sys/mman.h b/src/shims/windows/sys/mman.h new file mode 100644 index 000000000..e5bec12eb --- /dev/null +++ b/src/shims/windows/sys/mman.h @@ -0,0 +1,39 @@ +#ifndef MMAN_H +#define MMAN_H + +#include + +#define MAP_SHARED 0x0010 /* share changes */ +#define MAP_FAILED ((void *)-1) +#define PROT_READ 0x04 /* pages can be read */ +#define PROT_WRITE 0x02 /* pages can be written */ +#define PROT_EXEC 0x01 /* pages can be executed */ +#ifndef FILE_MAP_ALL_ACCESS +enum { FILE_MAP_ALL_ACCESS = 0xF001F }; +#endif +EXTERN_C WINBASEAPI void *WINAPI MapViewOfFile(HANDLE hFileMappingObject, + DWORD dwDesiredAccess, + DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, + SIZE_T dwNumberOfBytesToMap); +EXTERN_C WINBASEAPI BOOL WINAPI UnmapViewOfFile(void const *lpBaseAddress); +static void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) { + void *result = (void *)(-1); + if (!addr && prot == MAP_SHARED) { + /* HACK: we're assuming handle sizes can't exceed 32 bits, which is wrong... + * but works for now. */ + void *ptr = MapViewOfFile((HANDLE)(intptr_t)fd, FILE_MAP_ALL_ACCESS, + (DWORD)(off >> (CHAR_BIT * sizeof(DWORD))), (DWORD)off, + (SIZE_T)len); + if (ptr) { + result = ptr; + } + } + return result; +} +static int munmap(void *addr, size_t length) { + (void)length; + return UnmapViewOfFile(addr) ? 0 : -1; +} + +#endif /* MMAN_H */ diff --git a/src/shims/windows/sys/select.h b/src/shims/windows/sys/select.h new file mode 100644 index 000000000..8aef7950e --- /dev/null +++ b/src/shims/windows/sys/select.h @@ -0,0 +1,4 @@ +#ifndef SELECT_H +#define SELECT_H + +#endif /* SELECT_H */ diff --git a/src/shims/windows/sys/socket.h b/src/shims/windows/sys/socket.h new file mode 100644 index 000000000..ba2dea79b --- /dev/null +++ b/src/shims/windows/sys/socket.h @@ -0,0 +1,46 @@ +#ifndef SOCKET_H +#define SOCKET_H + +typedef unsigned short sa_family_t; + +#include +#include // ssize_t + +#define cmsghdr _WSACMSGHDR +#undef CMSG_DATA +#define CMSG_DATA WSA_CMSG_DATA +#define CMSG_SPACE WSA_CMSG_SPACE +#define CMSG_FIRSTHDR WSA_CMSG_FIRSTHDR +#define CMSG_LEN WSA_CMSG_LEN +#define CMSG_NXTHDR WSA_CMSG_NXTHDR + +#define SCM_RIGHTS 1 + +#define iovec _WSABUF +#define iov_base buf +#define iov_len len +#define msghdr _WSAMSG +#define msg_name name +#define msg_namelen namelen +#define msg_iov lpBuffers +#define msg_iovlen dwBufferCount +#define msg_control Control.buf +#define msg_controllen Control.len +#define msg_flags dwFlags + +int dumb_socketpair(SOCKET socks[2]); +ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags); +ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); +int socketpair(int domain, int type, int protocol, int sv[2]); + +#ifdef __cplusplus +namespace { +inline int send(SOCKET s, const void *buf, int len, int flags) { + // Call the const char* overload version + int (*psend)(SOCKET s, const char *buf, int len, int flags) = ::send; + return (*psend)(s, (const char *)buf, len, flags); +} +} // namespace +#endif + +#endif /* SOCKET_H */ diff --git a/src/shims/windows/sys/statvfs.h b/src/shims/windows/sys/statvfs.h new file mode 100644 index 000000000..c86674d71 --- /dev/null +++ b/src/shims/windows/sys/statvfs.h @@ -0,0 +1,4 @@ +#ifndef STATVFS_H +#define STATVFS_H 1 + +#endif diff --git a/src/shims/windows/sys/syslog.h b/src/shims/windows/sys/syslog.h new file mode 100644 index 000000000..37141327a --- /dev/null +++ b/src/shims/windows/sys/syslog.h @@ -0,0 +1,4 @@ +#ifndef _SYS_SYSLOG_H +#define _SYS_SYSLOG_H 1 + +#endif /* sys/syslog.h */ diff --git a/src/shims/windows/sys/time.cc b/src/shims/windows/sys/time.cc new file mode 100644 index 000000000..d48e9e851 --- /dev/null +++ b/src/shims/windows/sys/time.cc @@ -0,0 +1,18 @@ +#include +#include + +int gettimeofday(struct timeval *tv, struct timezone *tz) { + // Free implementation from: https://stackoverflow.com/a/26085827 + SYSTEMTIME systime; + GetSystemTime(&systime); + FILETIME filetime; + SystemTimeToFileTime(&systime, &filetime); + unsigned long long const epoch_time_offset = 11644473600ULL * 60 * 60 * 24, + time_high = filetime.dwHighDateTime, + time = + filetime.dwLowDateTime + + (time_high << (CHAR_BIT * sizeof(filetime.dwLowDateTime))); + tv->tv_sec = static_cast((time - epoch_time_offset) / 10000000); + tv->tv_usec = static_cast(systime.wMilliseconds * 1000); + return 0; +} diff --git a/src/shims/windows/sys/time.h b/src/shims/windows/sys/time.h new file mode 100644 index 000000000..846dde313 --- /dev/null +++ b/src/shims/windows/sys/time.h @@ -0,0 +1,15 @@ +#ifndef TIME_H +#define TIME_H + +#include // clients require timeval definition + +struct timeval; +struct timezone; + +#ifdef __cplusplus +extern "C" +#endif + int + gettimeofday(struct timeval *tv, struct timezone *tz); + +#endif /* TIME_H */ diff --git a/src/shims/windows/sys/un.h b/src/shims/windows/sys/un.h new file mode 100644 index 000000000..531f5e4fe --- /dev/null +++ b/src/shims/windows/sys/un.h @@ -0,0 +1,17 @@ +#ifndef UN_H +#define UN_H + +#include + +#define UNIX_PATH_MAX 108 + +typedef struct sockaddr_un { + ADDRESS_FAMILY sun_family; + char sun_path[UNIX_PATH_MAX]; +} SOCKADDR_UN, *PSOCKADDR_UN; + +#ifndef AF_LOCAL +#define AF_LOCAL AF_UNIX +#endif + +#endif /* UN_H */ diff --git a/src/shims/windows/sys/wait.h b/src/shims/windows/sys/wait.h new file mode 100644 index 000000000..442218408 --- /dev/null +++ b/src/shims/windows/sys/wait.h @@ -0,0 +1,4 @@ +#ifndef WAIT_H +#define WAIT_H + +#endif /* WAIT_H */ diff --git a/src/shims/windows/syslog.h b/src/shims/windows/syslog.h new file mode 100644 index 000000000..830b4928a --- /dev/null +++ b/src/shims/windows/syslog.h @@ -0,0 +1 @@ +#include diff --git a/src/shims/windows/unistd.cc b/src/shims/windows/unistd.cc index e1705c35d..d69655791 100644 --- a/src/shims/windows/unistd.cc +++ b/src/shims/windows/unistd.cc @@ -5,6 +5,16 @@ #endif #include +int usleep(useconds_t usec) { + Sleep((usec + (1000 - 1)) / 1000); + return 0; +} + +unsigned sleep(unsigned seconds) { + Sleep(seconds * 1000); + return 0; +} + int kill(pid_t pid, int sig) { int result; if (HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, pid)) { diff --git a/src/shims/windows/unistd.h b/src/shims/windows/unistd.h index a5c191160..ea8cd4224 100644 --- a/src/shims/windows/unistd.h +++ b/src/shims/windows/unistd.h @@ -1,8 +1,45 @@ #ifndef UNISTD_H #define UNISTD_H +#include + +#include // open/read/write/close +#ifndef EXTERN_C +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C +#endif +#endif +#ifndef DECLSPEC_IMPORT +#define DECLSPEC_IMPORT __declspec(dllimport) +#endif +#ifndef WINBASEAPI +#define WINBASEAPI DECLSPEC_IMPORT +#endif +#ifndef WINAPI +#define WINAPI __stdcall +#endif +typedef int BOOL; +typedef void *HANDLE; +typedef unsigned long DWORD; +#ifdef _WIN64 +typedef unsigned long long UINT_PTR; +typedef unsigned long long ULONG_PTR; +typedef long long ssize_t; +#else +typedef unsigned int UINT_PTR; +typedef unsigned long ULONG_PTR; +typedef int ssize_t; +#endif typedef int pid_t /* technically unsigned on Windows, but no practical concern */; enum { SIGKILL = 9 }; +typedef ULONG_PTR SIZE_T; +EXTERN_C WINBASEAPI void WINAPI Sleep(DWORD dwMilliseconds); + +typedef unsigned int useconds_t; +int usleep(useconds_t usec); +unsigned sleep(unsigned seconds); __declspec( deprecated("Killing a process by ID has an inherent race condition on Windows"