From 21f627ad0adeb41e49112ff071c40e5609f93736 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 4 Feb 2015 01:31:14 +0100 Subject: [PATCH 1/7] First draft of the win32 implementation of iomgr. Caveats: -) The win32 pollset isn't threadsafe (yet). -) Only client code is implemented. -) Only very simple code has been tested with it yet. --- Makefile | 21 ++ build.json | 8 + include/grpc/support/log_win32.h | 53 +++ include/grpc/support/port_platform.h | 2 + include/grpc/support/time_win32.h | 2 +- src/core/iomgr/iomgr_posix.c | 6 + src/core/iomgr/iomgr_windows.c | 67 ++++ src/core/iomgr/iomgr_windows.h | 42 +++ src/core/iomgr/pollset_windows.c | 185 ++++++++- src/core/iomgr/pollset_windows.h | 19 +- src/core/iomgr/sockaddr_win32.h | 2 + src/core/iomgr/socket_windows.c | 76 ++++ src/core/iomgr/socket_windows.h | 73 ++++ src/core/iomgr/tcp_client_windows.c | 219 +++++++++++ src/core/iomgr/tcp_windows.c | 357 ++++++++++++++++++ src/core/iomgr/tcp_windows.h | 57 +++ src/core/support/log_win32.c | 37 +- test/core/end2end/cq_verifier.c | 7 - vsprojects/vs2013/global.props | 24 +- vsprojects/vs2013/gpr.vcxproj | 1 + vsprojects/vs2013/gpr.vcxproj.filters | 3 + vsprojects/vs2013/grpc.vcxproj | 11 + vsprojects/vs2013/grpc.vcxproj.filters | 21 ++ vsprojects/vs2013/grpc_unsecure.vcxproj | 11 + .../vs2013/grpc_unsecure.vcxproj.filters | 21 ++ 25 files changed, 1299 insertions(+), 26 deletions(-) create mode 100644 include/grpc/support/log_win32.h create mode 100644 src/core/iomgr/iomgr_windows.c create mode 100644 src/core/iomgr/iomgr_windows.h create mode 100644 src/core/iomgr/socket_windows.c create mode 100644 src/core/iomgr/socket_windows.h create mode 100644 src/core/iomgr/tcp_client_windows.c create mode 100644 src/core/iomgr/tcp_windows.c create mode 100644 src/core/iomgr/tcp_windows.h diff --git a/Makefile b/Makefile index bd094150b77..fb46a936749 100644 --- a/Makefile +++ b/Makefile @@ -1246,6 +1246,7 @@ PUBLIC_HEADERS_C += \ include/grpc/support/histogram.h \ include/grpc/support/host_port.h \ include/grpc/support/log.h \ + include/grpc/support/log_win32.h \ include/grpc/support/port_platform.h \ include/grpc/support/slice.h \ include/grpc/support/slice_buffer.h \ @@ -1408,6 +1409,7 @@ LIBGRPC_SRC = \ src/core/iomgr/fd_posix.c \ src/core/iomgr/iomgr.c \ src/core/iomgr/iomgr_posix.c \ + src/core/iomgr/iomgr_windows.c \ src/core/iomgr/pollset_kick.c \ src/core/iomgr/pollset_multipoller_with_poll_posix.c \ src/core/iomgr/pollset_posix.c \ @@ -1417,9 +1419,12 @@ LIBGRPC_SRC = \ src/core/iomgr/socket_utils_common_posix.c \ src/core/iomgr/socket_utils_linux.c \ src/core/iomgr/socket_utils_posix.c \ + src/core/iomgr/socket_windows.c \ src/core/iomgr/tcp_client_posix.c \ + src/core/iomgr/tcp_client_windows.c \ src/core/iomgr/tcp_posix.c \ src/core/iomgr/tcp_server_posix.c \ + src/core/iomgr/tcp_windows.c \ src/core/iomgr/time_averaged_stats.c \ src/core/iomgr/wakeup_fd_eventfd.c \ src/core/iomgr/wakeup_fd_nospecial.c \ @@ -1534,6 +1539,7 @@ src/core/iomgr/endpoint_pair_posix.c: $(OPENSSL_DEP) src/core/iomgr/fd_posix.c: $(OPENSSL_DEP) src/core/iomgr/iomgr.c: $(OPENSSL_DEP) src/core/iomgr/iomgr_posix.c: $(OPENSSL_DEP) +src/core/iomgr/iomgr_windows.c: $(OPENSSL_DEP) src/core/iomgr/pollset_kick.c: $(OPENSSL_DEP) src/core/iomgr/pollset_multipoller_with_poll_posix.c: $(OPENSSL_DEP) src/core/iomgr/pollset_posix.c: $(OPENSSL_DEP) @@ -1543,9 +1549,12 @@ src/core/iomgr/sockaddr_utils.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_common_posix.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_linux.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_posix.c: $(OPENSSL_DEP) +src/core/iomgr/socket_windows.c: $(OPENSSL_DEP) src/core/iomgr/tcp_client_posix.c: $(OPENSSL_DEP) +src/core/iomgr/tcp_client_windows.c: $(OPENSSL_DEP) src/core/iomgr/tcp_posix.c: $(OPENSSL_DEP) src/core/iomgr/tcp_server_posix.c: $(OPENSSL_DEP) +src/core/iomgr/tcp_windows.c: $(OPENSSL_DEP) src/core/iomgr/time_averaged_stats.c: $(OPENSSL_DEP) src/core/iomgr/wakeup_fd_eventfd.c: $(OPENSSL_DEP) src/core/iomgr/wakeup_fd_nospecial.c: $(OPENSSL_DEP) @@ -1682,6 +1691,7 @@ objs/$(CONFIG)/src/core/iomgr/endpoint_pair_posix.o: objs/$(CONFIG)/src/core/iomgr/fd_posix.o: objs/$(CONFIG)/src/core/iomgr/iomgr.o: objs/$(CONFIG)/src/core/iomgr/iomgr_posix.o: +objs/$(CONFIG)/src/core/iomgr/iomgr_windows.o: objs/$(CONFIG)/src/core/iomgr/pollset_kick.o: objs/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o: objs/$(CONFIG)/src/core/iomgr/pollset_posix.o: @@ -1691,9 +1701,12 @@ objs/$(CONFIG)/src/core/iomgr/sockaddr_utils.o: objs/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o: objs/$(CONFIG)/src/core/iomgr/socket_utils_linux.o: objs/$(CONFIG)/src/core/iomgr/socket_utils_posix.o: +objs/$(CONFIG)/src/core/iomgr/socket_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_client_posix.o: +objs/$(CONFIG)/src/core/iomgr/tcp_client_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_posix.o: objs/$(CONFIG)/src/core/iomgr/tcp_server_posix.o: +objs/$(CONFIG)/src/core/iomgr/tcp_windows.o: objs/$(CONFIG)/src/core/iomgr/time_averaged_stats.o: objs/$(CONFIG)/src/core/iomgr/wakeup_fd_eventfd.o: objs/$(CONFIG)/src/core/iomgr/wakeup_fd_nospecial.o: @@ -1849,6 +1862,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/iomgr/fd_posix.c \ src/core/iomgr/iomgr.c \ src/core/iomgr/iomgr_posix.c \ + src/core/iomgr/iomgr_windows.c \ src/core/iomgr/pollset_kick.c \ src/core/iomgr/pollset_multipoller_with_poll_posix.c \ src/core/iomgr/pollset_posix.c \ @@ -1858,9 +1872,12 @@ LIBGRPC_UNSECURE_SRC = \ src/core/iomgr/socket_utils_common_posix.c \ src/core/iomgr/socket_utils_linux.c \ src/core/iomgr/socket_utils_posix.c \ + src/core/iomgr/socket_windows.c \ src/core/iomgr/tcp_client_posix.c \ + src/core/iomgr/tcp_client_windows.c \ src/core/iomgr/tcp_posix.c \ src/core/iomgr/tcp_server_posix.c \ + src/core/iomgr/tcp_windows.c \ src/core/iomgr/time_averaged_stats.c \ src/core/iomgr/wakeup_fd_eventfd.c \ src/core/iomgr/wakeup_fd_nospecial.c \ @@ -1980,6 +1997,7 @@ objs/$(CONFIG)/src/core/iomgr/endpoint_pair_posix.o: objs/$(CONFIG)/src/core/iomgr/fd_posix.o: objs/$(CONFIG)/src/core/iomgr/iomgr.o: objs/$(CONFIG)/src/core/iomgr/iomgr_posix.o: +objs/$(CONFIG)/src/core/iomgr/iomgr_windows.o: objs/$(CONFIG)/src/core/iomgr/pollset_kick.o: objs/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o: objs/$(CONFIG)/src/core/iomgr/pollset_posix.o: @@ -1989,9 +2007,12 @@ objs/$(CONFIG)/src/core/iomgr/sockaddr_utils.o: objs/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o: objs/$(CONFIG)/src/core/iomgr/socket_utils_linux.o: objs/$(CONFIG)/src/core/iomgr/socket_utils_posix.o: +objs/$(CONFIG)/src/core/iomgr/socket_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_client_posix.o: +objs/$(CONFIG)/src/core/iomgr/tcp_client_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_posix.o: objs/$(CONFIG)/src/core/iomgr/tcp_server_posix.o: +objs/$(CONFIG)/src/core/iomgr/tcp_windows.o: objs/$(CONFIG)/src/core/iomgr/time_averaged_stats.o: objs/$(CONFIG)/src/core/iomgr/wakeup_fd_eventfd.o: objs/$(CONFIG)/src/core/iomgr/wakeup_fd_nospecial.o: diff --git a/build.json b/build.json index 6e20d617e3a..28019c2bf27 100644 --- a/build.json +++ b/build.json @@ -45,6 +45,7 @@ "src/core/iomgr/iomgr.h", "src/core/iomgr/iomgr_internal.h", "src/core/iomgr/iomgr_posix.h", + "src/core/iomgr/iomgr_windows.h", "src/core/iomgr/pollset.h", "src/core/iomgr/pollset_kick.h", "src/core/iomgr/pollset_kick_posix.h", @@ -57,9 +58,11 @@ "src/core/iomgr/sockaddr_utils.h", "src/core/iomgr/sockaddr_win32.h", "src/core/iomgr/socket_utils_posix.h", + "src/core/iomgr/socket_windows.h", "src/core/iomgr/tcp_client.h", "src/core/iomgr/tcp_posix.h", "src/core/iomgr/tcp_server.h", + "src/core/iomgr/tcp_windows.h", "src/core/iomgr/time_averaged_stats.h", "src/core/iomgr/wakeup_fd_pipe.h", "src/core/iomgr/wakeup_fd_posix.h", @@ -131,6 +134,7 @@ "src/core/iomgr/fd_posix.c", "src/core/iomgr/iomgr.c", "src/core/iomgr/iomgr_posix.c", + "src/core/iomgr/iomgr_windows.c", "src/core/iomgr/pollset_kick.c", "src/core/iomgr/pollset_multipoller_with_poll_posix.c", "src/core/iomgr/pollset_posix.c", @@ -140,9 +144,12 @@ "src/core/iomgr/socket_utils_common_posix.c", "src/core/iomgr/socket_utils_linux.c", "src/core/iomgr/socket_utils_posix.c", + "src/core/iomgr/socket_windows.c", "src/core/iomgr/tcp_client_posix.c", + "src/core/iomgr/tcp_client_windows.c", "src/core/iomgr/tcp_posix.c", "src/core/iomgr/tcp_server_posix.c", + "src/core/iomgr/tcp_windows.c", "src/core/iomgr/time_averaged_stats.c", "src/core/iomgr/wakeup_fd_eventfd.c", "src/core/iomgr/wakeup_fd_nospecial.c", @@ -212,6 +219,7 @@ "include/grpc/support/histogram.h", "include/grpc/support/host_port.h", "include/grpc/support/log.h", + "include/grpc/support/log_win32.h", "include/grpc/support/port_platform.h", "include/grpc/support/slice.h", "include/grpc/support/slice_buffer.h", diff --git a/include/grpc/support/log_win32.h b/include/grpc/support/log_win32.h new file mode 100644 index 00000000000..7abd5df3941 --- /dev/null +++ b/include/grpc/support/log_win32.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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. + * + */ + +#ifndef __GRPC_SUPPORT_LOG_WIN32_H__ +#define __GRPC_SUPPORT_LOG_WIN32_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns a string allocated with gpr_malloc that contains a UTF-8 + * formatted error message, corresponding to the error messageid. + * Use in cunjunction with GetLastError() et al. + */ +char *gpr_format_message(DWORD messageid); + +#ifdef __cplusplus +} +#endif + +#endif /* __GRPC_SUPPORT_LOG_H__ */ diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h index 2bf53483157..672dd736fb4 100644 --- a/include/grpc/support/port_platform.h +++ b/include/grpc/support/port_platform.h @@ -46,10 +46,12 @@ #define GPR_WIN32 1 #define GPR_ARCH_64 1 #define GPR_GETPID_IN_PROCESS_H 1 +#define GPR_WINSOCK_SOCKET 1 #elif defined(_WIN32) || defined(WIN32) #define GPR_ARCH_32 1 #define GPR_WIN32 1 #define GPR_GETPID_IN_PROCESS_H 1 +#define GPR_WINSOCK_SOCKET 1 #elif defined(ANDROID) || defined(__ANDROID__) #define GPR_ANDROID 1 #define GPR_ARCH_32 1 diff --git a/include/grpc/support/time_win32.h b/include/grpc/support/time_win32.h index e62ad64b8f5..1f7b6844500 100644 --- a/include/grpc/support/time_win32.h +++ b/include/grpc/support/time_win32.h @@ -35,7 +35,7 @@ #define __GRPC_SUPPORT_TIME_WIN32_H__ /* Win32 variant of gpr_time_platform.h */ -#include +#include #include typedef struct gpr_timespec { diff --git a/src/core/iomgr/iomgr_posix.c b/src/core/iomgr/iomgr_posix.c index 9297f08e99a..22ca74314cb 100644 --- a/src/core/iomgr/iomgr_posix.c +++ b/src/core/iomgr/iomgr_posix.c @@ -31,6 +31,10 @@ * */ +#include + +#ifdef GPR_POSIX_SOCKET + #include "src/core/iomgr/iomgr_posix.h" #include "src/core/iomgr/fd_posix.h" @@ -43,3 +47,5 @@ void grpc_iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); grpc_fd_global_shutdown(); } + +#endif /* GRPC_IOMGRP_POSIX */ diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c new file mode 100644 index 00000000000..9cdf224ad77 --- /dev/null +++ b/src/core/iomgr/iomgr_windows.c @@ -0,0 +1,67 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr_win32.h" + +#include + +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/iomgr/iomgr_windows.h" + +static void winsock_init(void) { + WSADATA wsaData; + int status = WSAStartup(MAKEWORD(2, 0), &wsaData); + GPR_ASSERT(status == 0); +} + +static void winsock_shutdown(void) { + int status = WSACleanup(); + GPR_ASSERT(status == 0); +} + +void grpc_iomgr_platform_init(void) { + winsock_init(); + grpc_pollset_global_init(); +} + +void grpc_iomgr_platform_shutdown(void) { + grpc_pollset_global_shutdown(); + winsock_shutdown(); +} + +#endif /* GRPC_IOMGRP_POSIX */ diff --git a/src/core/iomgr/iomgr_windows.h b/src/core/iomgr/iomgr_windows.h new file mode 100644 index 00000000000..2d9449c1f62 --- /dev/null +++ b/src/core/iomgr/iomgr_windows.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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. + * + */ + +#ifndef __GRPC_INTERNAL_IOMGR_IOMGR_WINDOWS_H_ +#define __GRPC_INTERNAL_IOMGR_IOMGR_WINDOWS_H_ + +#include "src/core/iomgr/socket_windows.h" + +void grpc_pollset_global_init(void); +void grpc_pollset_global_shutdown(void); + +#endif /* __GRPC_INTERNAL_IOMGR_IOMGR_WINDOWS_H_ */ diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c index 3fb39918b35..fdebede4828 100644 --- a/src/core/iomgr/pollset_windows.c +++ b/src/core/iomgr/pollset_windows.c @@ -33,6 +33,187 @@ #include -#ifdef GPR_WIN32 +#ifdef GPR_WINSOCK_SOCKET -#endif /* GPR_WIN32 */ +#include + +#include +#include + +#include "src/core/iomgr/alarm_internal.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/pollset_windows.h" + +static grpc_pollset g_global_pollset; +static ULONG g_pollset_kick_token; +static OVERLAPPED g_pollset_custom_overlap; + +static gpr_event g_shutdown_global_poller; +static gpr_event g_global_poller_done; + +void grpc_pollset_init(grpc_pollset *pollset) { + pollset->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, + (ULONG_PTR)NULL, 0); + GPR_ASSERT(pollset->iocp); +} + +void grpc_pollset_destroy(grpc_pollset *pollset) { + BOOL status; + status = CloseHandle(pollset->iocp); + GPR_ASSERT(status); +} + +static int pollset_poll(grpc_pollset *pollset, + gpr_timespec deadline, gpr_timespec now) { + BOOL success; + DWORD bytes = 0; + DWORD flags = 0; + ULONG_PTR completion_key; + LPOVERLAPPED overlapped; + gpr_timespec wait_time = gpr_time_sub(deadline, now); + grpc_winsocket *socket; + grpc_winsocket_callback_info *info; + void(*f)(void *, int) = NULL; + void *opaque = NULL; + success = GetQueuedCompletionStatus(pollset->iocp, &bytes, + &completion_key, &overlapped, + gpr_time_to_millis(wait_time)); + + if (!success && !overlapped) { + /* The deadline got attained. */ + return 0; + } + GPR_ASSERT(completion_key && overlapped); + if (overlapped == &g_pollset_custom_overlap) { + if (completion_key == (ULONG_PTR) &g_pollset_kick_token) { + /* We were awoken from a kick. */ + gpr_log(GPR_DEBUG, "pollset_poll - got a kick"); + return 1; + } + gpr_log(GPR_ERROR, "Unknown custom completion key."); + abort(); + } + + socket = (grpc_winsocket*) completion_key; + if (overlapped == &socket->write_info.overlapped) { + gpr_log(GPR_DEBUG, "pollset_poll - got write packet"); + info = &socket->write_info; + } else if (overlapped == &socket->read_info.overlapped) { + gpr_log(GPR_DEBUG, "pollset_poll - got read packet"); + info = &socket->read_info; + } else { + gpr_log(GPR_ERROR, "Unknown IOCP operation"); + abort(); + } + success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, + FALSE, &flags); + gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s", bytes, flags, + success ? "succeeded" : "failed"); + info->bytes_transfered = bytes; + info->wsa_error = success ? 0 : WSAGetLastError(); + GPR_ASSERT(overlapped == &info->overlapped); + gpr_mu_lock(&socket->state_mu); + GPR_ASSERT(!info->has_pending_iocp); + if (info->cb) { + f = info->cb; + opaque = info->opaque; + info->cb = NULL; + } else { + info->has_pending_iocp = 1; + } + gpr_mu_unlock(&socket->state_mu); + if (f) f(opaque, 1); + + return 1; +} + +int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { + gpr_timespec now; + now = gpr_now(); + if (gpr_time_cmp(now, deadline) > 0) { + return 0; + } + if (grpc_maybe_call_delayed_callbacks(NULL, 1)) { + return 1; + } + if (grpc_alarm_check(NULL, now, &deadline)) { + return 1; + } + return pollset_poll(pollset, deadline, now); +} + +void grpc_pollset_kick(grpc_pollset *pollset) { + BOOL status; + status = PostQueuedCompletionStatus(pollset->iocp, 0, + (ULONG_PTR) &g_pollset_kick_token, + &g_pollset_custom_overlap); + GPR_ASSERT(status); +} + +static void global_poller(void *p) { + while (!gpr_event_get(&g_shutdown_global_poller)) { + grpc_pollset_work(&g_global_pollset, gpr_inf_future); + } + + gpr_event_set(&g_global_poller_done, (void *) 1); +} + +void grpc_pollset_global_init(void) { + gpr_thd_id id; + + grpc_pollset_init(&g_global_pollset); + gpr_event_init(&g_global_poller_done); + gpr_event_init(&g_shutdown_global_poller); + gpr_thd_new(&id, global_poller, NULL, NULL); +} + +void grpc_pollset_global_shutdown(void) { + gpr_event_set(&g_shutdown_global_poller, (void *) 1); + grpc_pollset_kick(&g_global_pollset); + gpr_event_wait(&g_global_poller_done, gpr_inf_future); + grpc_pollset_destroy(&g_global_pollset); +} + +void grpc_pollset_add_handle(grpc_pollset *pollset, grpc_winsocket *socket) { + HANDLE ret = CreateIoCompletionPort((HANDLE) socket->socket, pollset->iocp, + (gpr_uintptr) socket, 0); + GPR_ASSERT(ret == pollset->iocp); +} + +static void handle_notify_on_iocp(grpc_winsocket *socket, + void(*cb)(void *, int), void *opaque, + grpc_winsocket_callback_info *info) { + int run_now = 0; + GPR_ASSERT(!info->cb); + gpr_mu_lock(&socket->state_mu); + if (info->has_pending_iocp) { + run_now = 1; + info->has_pending_iocp = 0; + gpr_log(GPR_DEBUG, "handle_notify_on_iocp - runs now"); + } else { + info->cb = cb; + info->opaque = opaque; + gpr_log(GPR_DEBUG, "handle_notify_on_iocp - queued"); + } + gpr_mu_unlock(&socket->state_mu); + if (run_now) cb(opaque, 1); +} + +void grpc_handle_notify_on_write(grpc_winsocket *socket, + void(*cb)(void *, int), void *opaque) { + gpr_log(GPR_DEBUG, "grpc_handle_notify_on_write"); + handle_notify_on_iocp(socket, cb, opaque, &socket->write_info); +} + +void grpc_handle_notify_on_read(grpc_winsocket *socket, + void(*cb)(void *, int), void *opaque) { + gpr_log(GPR_DEBUG, "grpc_handle_notify_on_read"); + handle_notify_on_iocp(socket, cb, opaque, &socket->read_info); +} + +grpc_pollset *grpc_global_pollset(void) { + return &g_global_pollset; +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h index 9214b04b170..036f3910a01 100644 --- a/src/core/iomgr/pollset_windows.h +++ b/src/core/iomgr/pollset_windows.h @@ -34,9 +34,11 @@ #ifndef __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_ #define __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_ +#include #include #include "src/core/iomgr/pollset_kick.h" +#include "src/core/iomgr/socket_windows.h" /* forward declare only in this file to avoid leaking impl details via pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not @@ -44,11 +46,20 @@ struct grpc_fd; typedef struct grpc_pollset { - gpr_mu mu; - gpr_cv cv; + HANDLE iocp; } grpc_pollset; -#define GRPC_POLLSET_MU(pollset) (&(pollset)->mu) -#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv) +#define GRPC_POLLSET_MU(pollset) (NULL) +#define GRPC_POLLSET_CV(pollset) (NULL) + +void grpc_pollset_add_handle(grpc_pollset *, grpc_winsocket *); + +grpc_pollset *grpc_global_pollset(void); + +void grpc_handle_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success), + void *opaque); + +void grpc_handle_notify_on_read(grpc_winsocket *, void(*cb)(void *, int success), + void *opaque); #endif /* __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_ */ diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h index cdea33fec07..350f5fa33e1 100644 --- a/src/core/iomgr/sockaddr_win32.h +++ b/src/core/iomgr/sockaddr_win32.h @@ -35,5 +35,7 @@ #define __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_ #include +#include +#include #endif // __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_ diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c new file mode 100644 index 00000000000..7d1d59c3187 --- /dev/null +++ b/src/core/iomgr/socket_windows.c @@ -0,0 +1,76 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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 +#include + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/iomgr.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/pollset_windows.h" + +grpc_winsocket *grpc_winsocket_create(SOCKET socket) { + grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket)); + gpr_log(GPR_DEBUG, "grpc_winsocket_create"); + memset(r, 0, sizeof(grpc_winsocket)); + r->socket = socket; + gpr_mu_init(&r->state_mu); + grpc_iomgr_ref(); + grpc_pollset_add_handle(grpc_global_pollset(), r); + return r; +} + +void shutdown_op(grpc_winsocket_callback_info *info) { + if (!info->cb) return; + info->cb(info->opaque, 0); +} + +void grpc_winsocket_shutdown(grpc_winsocket *socket) { + gpr_log(GPR_DEBUG, "grpc_winsocket_shutdown"); + shutdown_op(&socket->read_info); + shutdown_op(&socket->write_info); +} + +void grpc_winsocket_orphan(grpc_winsocket *socket) { + gpr_log(GPR_DEBUG, "grpc_winsocket_orphan"); + grpc_iomgr_unref(); + closesocket(socket->socket); + gpr_mu_destroy(&socket->state_mu); + gpr_free(socket); +} + +#endif diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h new file mode 100644 index 00000000000..ca85ea54cbf --- /dev/null +++ b/src/core/iomgr/socket_windows.h @@ -0,0 +1,73 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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. + * + */ + +#ifndef __GRPC_INTERNAL_IOMGR_HANDLE_WINDOWS_H__ +#define __GRPC_INTERNAL_IOMGR_HANDLE_WINDOWS_H__ + +#include + +#include +#include + +typedef struct grpc_winsocket_callback_info { + /* I hate Microsoft so much. This is supposed to be a WSAOVERLAPPED, + * but in order to get that definition, we need to include ws2tcpip.h, + * which needs to be included from the top, otherwise it'll clash with + * a previous inclusion of windows.h that in turns includes winsock.h. + * If anyone knows a way to do it properly, feel free to send a patch. + */ + OVERLAPPED overlapped; + void(*cb)(void *opaque, int success); + void *opaque; + int has_pending_iocp; + DWORD bytes_transfered; + int wsa_error; +} grpc_winsocket_callback_info; + +typedef struct grpc_winsocket { + SOCKET socket; + + grpc_winsocket_callback_info write_info; + grpc_winsocket_callback_info read_info; + + gpr_mu state_mu; +} grpc_winsocket; + +/* Create a wrapped windows handle. +This takes ownership of closing it. */ +grpc_winsocket *grpc_winsocket_create(SOCKET socket); + +void grpc_winsocket_shutdown(grpc_winsocket *socket); +void grpc_winsocket_orphan(grpc_winsocket *socket); + +#endif /* __GRPC_INTERNAL_IOMGR_FD_POSIX_H_ */ diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c new file mode 100644 index 00000000000..465fc75295d --- /dev/null +++ b/src/core/iomgr/tcp_client_windows.c @@ -0,0 +1,219 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr_win32.h" + +#include +#include +#include +#include +#include + +#include "src/core/iomgr/tcp_client.h" +#include "src/core/iomgr/tcp_windows.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/alarm.h" +#include "src/core/iomgr/sockaddr.h" +#include "src/core/iomgr/sockaddr_utils.h" + +typedef struct { + void(*cb)(void *arg, grpc_endpoint *tcp); + void *cb_arg; + gpr_mu mu; + grpc_winsocket *socket; + gpr_timespec deadline; + grpc_alarm alarm; + int refs; +} async_connect; + +static void async_connect_cleanup(async_connect *ac) { + int done = (--ac->refs == 0); + gpr_mu_unlock(&ac->mu); + if (done) { + gpr_mu_destroy(&ac->mu); + gpr_free(ac); + } +} + +static void on_alarm(void *acp, int success) { + async_connect *ac = acp; + gpr_mu_lock(&ac->mu); + if (ac->socket != NULL && success) { + grpc_winsocket_shutdown(ac->socket); + } + async_connect_cleanup(ac); +} + +static void on_connect(void *acp, int success) { + async_connect *ac = acp; + SOCKET sock = ac->socket->socket; + grpc_endpoint *ep = NULL; + grpc_winsocket_callback_info *info = &ac->socket->write_info; + void(*cb)(void *arg, grpc_endpoint *tcp) = ac->cb; + void *cb_arg = ac->cb_arg; + + grpc_alarm_cancel(&ac->alarm); + + if (success) { + DWORD transfered_bytes = 0; + DWORD flags; + BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, + &transfered_bytes, FALSE, + &flags); + GPR_ASSERT(transfered_bytes == 0); + if (!wsa_success) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); + gpr_free(utf8_message); + goto finish; + } else { + gpr_log(GPR_DEBUG, "on_connect: connection established"); + ep = grpc_tcp_create(ac->socket); + goto finish; + } + } else { + __debugbreak(); + abort(); + gpr_log(GPR_ERROR, "on_writable failed during connect"); + goto finish; + } + + abort(); + +finish: + gpr_mu_lock(&ac->mu); + if (!ep) { + grpc_winsocket_orphan(ac->socket); + } + async_connect_cleanup(ac); + cb(cb_arg, ep); +} + +void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp), + void *arg, const struct sockaddr *addr, + int addr_len, gpr_timespec deadline) { + SOCKET sock = INVALID_SOCKET; + BOOL success; + int status; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in6 local_address; + async_connect *ac; + grpc_winsocket *socket = NULL; + LPFN_CONNECTEX ConnectEx; + GUID guid = WSAID_CONNECTEX; + DWORD ioctl_num_bytes; + const char *message = NULL; + char *utf8_message; + grpc_winsocket_callback_info *info; + + /* Use dualstack sockets where available. */ + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + message = "Unable to create socket: %s"; + goto failure; + } + + if (!grpc_tcp_prepare_socket(sock)) { + message = "Unable to set socket options: %s"; + goto failure; + } + + status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), + &ioctl_num_bytes, NULL, NULL); + + if (status != 0) { + message = "Unable to retreive ConnectEx pointer: %s"; + goto failure; + } + + memset(&local_address, 0, sizeof(local_address)); + memcpy(&local_address.sin6_addr, &in6addr_any, sizeof(in6addr_any)); + local_address.sin6_family = AF_INET6; + + status = bind(sock, (struct sockaddr *) &local_address, + sizeof(local_address)); + if (status != 0) { + message = "Unable to bind socket: %s"; + goto failure; + } + + socket = grpc_winsocket_create(sock); + info = &socket->write_info; + success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped); + + if (success) { + gpr_log(GPR_DEBUG, "connected immediately - but we still go to sleep"); + } else { + int error = WSAGetLastError(); + if (error != ERROR_IO_PENDING) { + message = "ConnectEx failed: %s"; + goto failure; + } + } + + gpr_log(GPR_DEBUG, "grpc_tcp_client_connect: connection pending"); + ac = gpr_malloc(sizeof(async_connect)); + ac->cb = cb; + ac->cb_arg = arg; + ac->socket = socket; + gpr_mu_init(&ac->mu); + ac->refs = 2; + + grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now()); + grpc_handle_notify_on_write(socket, on_connect, ac); + return; + +failure: + utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, message, utf8_message); + gpr_free(utf8_message); + if (socket) { + grpc_winsocket_orphan(socket); + } else if (sock != INVALID_SOCKET) { + closesocket(sock); + } + cb(arg, NULL); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c new file mode 100644 index 00000000000..0eb6663dd48 --- /dev/null +++ b/src/core/iomgr/tcp_windows.c @@ -0,0 +1,357 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr_win32.h" + +#include +#include +#include +#include +#include + +#include "src/core/iomgr/tcp_client.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/alarm.h" +#include "src/core/iomgr/sockaddr.h" +#include "src/core/iomgr/sockaddr_utils.h" + +static int set_non_block(SOCKET sock) { + int status; + unsigned long param = 1; + DWORD ret; + status = WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, + NULL, NULL); + return status == 0; +} + +int grpc_tcp_prepare_socket(SOCKET sock) { + if (!set_non_block(sock)) + return 0; + return 1; +} + +typedef struct grpc_tcp { + grpc_endpoint base; + grpc_winsocket *socket; + gpr_refcount refcount; + + grpc_endpoint_read_cb read_cb; + void *read_user_data; + gpr_slice read_slice; + int outstanding_read; + + grpc_endpoint_write_cb write_cb; + void *write_user_data; + gpr_slice_buffer write_slices; + int outstanding_write; + +} grpc_tcp; + +static void tcp_ref(grpc_tcp *tcp) { + gpr_log(GPR_DEBUG, "tcp_ref"); + gpr_ref(&tcp->refcount); +} + +static void tcp_unref(grpc_tcp *tcp) { + gpr_log(GPR_DEBUG, "tcp_unref"); + if (gpr_unref(&tcp->refcount)) { + gpr_log(GPR_DEBUG, "tcp_unref: destroying"); + gpr_slice_buffer_destroy(&tcp->write_slices); + grpc_winsocket_orphan(tcp->socket); + gpr_free(tcp); + } +} + +static void on_read(void *tcpp, int success) { + grpc_tcp *tcp = (grpc_tcp *) tcpp; + grpc_winsocket *socket = tcp->socket; + gpr_slice sub; + gpr_slice *slice = NULL; + size_t nslices = 0; + grpc_endpoint_cb_status status; + grpc_endpoint_read_cb cb = tcp->read_cb; + grpc_winsocket_callback_info *info = &socket->read_info; + void *opaque = tcp->read_user_data; + + GPR_ASSERT(tcp->outstanding_read); + + if (!success) { + __debugbreak(); + abort(); + } + + gpr_log(GPR_DEBUG, "on_read"); + tcp->outstanding_read = 0; + + if (socket->read_info.wsa_error != 0) { + char *utf8_message = gpr_format_message(info->wsa_error); + __debugbreak(); + gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message); + gpr_free(utf8_message); + status = GRPC_ENDPOINT_CB_ERROR; + } else { + if (info->bytes_transfered != 0) { + sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered); + gpr_log(GPR_DEBUG, "on_read: calling callback"); + status = GRPC_ENDPOINT_CB_OK; + slice = ⊂ + nslices = 1; + } else { + gpr_log(GPR_DEBUG, "on_read: closed socket"); + gpr_slice_unref(tcp->read_slice); + status = GRPC_ENDPOINT_CB_EOF; + } + } + tcp_unref(tcp); + cb(opaque, slice, nslices, status); +} + +static void win_notify_on_read(grpc_endpoint *ep, + grpc_endpoint_read_cb cb, void *arg) { + grpc_tcp *tcp = (grpc_tcp *) ep; + grpc_winsocket *handle = tcp->socket; + grpc_winsocket_callback_info *info = &handle->read_info; + int status; + DWORD bytes_read = 0; + DWORD flags = 0; + int error; + WSABUF buffer; + + GPR_ASSERT(!tcp->outstanding_read); + tcp_ref(tcp); + tcp->outstanding_read = 1; + tcp->read_cb = cb; + tcp->read_user_data = arg; + + tcp->read_slice = gpr_slice_malloc(8192); + + buffer.len = GPR_SLICE_LENGTH(tcp->read_slice); + buffer.buf = GPR_SLICE_START_PTR(tcp->read_slice); + + gpr_log(GPR_DEBUG, "win_notify_on_read: calling WSARecv without overlap"); + + status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, + NULL, NULL); + info->wsa_error = status == 0 ? 0 : WSAGetLastError(); + + if (info->wsa_error != WSAEWOULDBLOCK) { + gpr_log(GPR_DEBUG, "got response immediately, calling on_read"); + info->bytes_transfered = bytes_read; + /* This might heavily recurse. */ + on_read(tcp, 1); + return; + } + + gpr_log(GPR_DEBUG, "got WSAEWOULDBLOCK - calling WSARecv with overlap"); + + memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); + status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, + &info->overlapped, NULL); + + if (status == 0) { + gpr_log(GPR_DEBUG, "got response immediately, but we're goint to sleep"); + grpc_handle_notify_on_read(tcp->socket, on_read, tcp); + return; + } + + error = WSAGetLastError(); + + if (error != WSA_IO_PENDING) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + __debugbreak(); + gpr_log(GPR_ERROR, "WSARecv error: %s", utf8_message); + gpr_free(utf8_message); + /* would the IO completion port be called anyway... ? Let's assume not. */ + tcp->outstanding_read = 0; + tcp_unref(tcp); + cb(arg, NULL, 0, GRPC_ENDPOINT_CB_ERROR); + return; + } + + gpr_log(GPR_DEBUG, "waiting on the IO completion port now"); + grpc_handle_notify_on_read(tcp->socket, on_read, tcp); +} + +static void on_write(void *tcpp, int success) { + grpc_tcp *tcp = (grpc_tcp *) tcpp; + grpc_winsocket *handle = tcp->socket; + grpc_winsocket_callback_info *info = &handle->write_info; + grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK; + grpc_endpoint_write_cb cb = tcp->write_cb; + void *opaque = tcp->write_user_data; + + GPR_ASSERT(tcp->outstanding_write); + + gpr_log(GPR_DEBUG, "on_write"); + + if (!success) { + __debugbreak(); + abort(); + } + + if (info->wsa_error != 0) { + char *utf8_message = gpr_format_message(info->wsa_error); + gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message); + gpr_free(utf8_message); + status = GRPC_ENDPOINT_CB_ERROR; + } else { + GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length); + } + + gpr_slice_buffer_reset_and_unref(&tcp->write_slices); + tcp->outstanding_write = 0; + + tcp_unref(tcp); + cb(opaque, status); +} + +static grpc_endpoint_write_status win_write(grpc_endpoint *ep, + gpr_slice *slices, size_t nslices, + grpc_endpoint_write_cb cb, + void *arg) { + grpc_tcp *tcp = (grpc_tcp *) ep; + grpc_winsocket *socket = tcp->socket; + grpc_winsocket_callback_info *info = &socket->write_info; + unsigned i; + DWORD bytes_sent; + int status; + WSABUF local_buffers[16]; + WSABUF *allocated = NULL; + WSABUF *buffers = local_buffers; + + GPR_ASSERT(nslices != 0); + GPR_ASSERT(GPR_SLICE_LENGTH(slices[0]) != 0); + GPR_ASSERT(!tcp->outstanding_write); + tcp_ref(tcp); + + gpr_log(GPR_DEBUG, "win_write"); + + tcp->outstanding_write = 1; + tcp->write_cb = cb; + tcp->write_user_data = arg; + gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices); + + if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) { + buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count); + allocated = buffers; + } + + for (i = 0; i < tcp->write_slices.count; i++) { + buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]); + buffers[i].buf = GPR_SLICE_START_PTR(tcp->write_slices.slices[i]); + } + + gpr_log(GPR_DEBUG, "win_write: calling WSASend without overlap"); + status = WSASend(socket->socket, buffers, tcp->write_slices.count, + &bytes_sent, 0, NULL, NULL); + info->wsa_error = status == 0 ? 0 : WSAGetLastError(); + + if (info->wsa_error != WSAEWOULDBLOCK) { + grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR; + gpr_log(GPR_DEBUG, "got response immediately, cleaning up and leaving"); + if (status == 0) { + ret = GRPC_ENDPOINT_WRITE_DONE; + GPR_ASSERT(bytes_sent == tcp->write_slices.length); + } + if (allocated) gpr_free(allocated); + gpr_slice_buffer_reset_and_unref(&tcp->write_slices); + tcp->outstanding_write = 0; + tcp_unref(tcp); + return ret; + } + + gpr_log(GPR_DEBUG, "got WSAEWOULDBLOCK - calling WSASend with overlap"); + + memset(&socket->write_info, 0, sizeof(OVERLAPPED)); + status = WSASend(socket->socket, buffers, tcp->write_slices.count, + &bytes_sent, 0, &socket->write_info.overlapped, NULL); + if (allocated) gpr_free(allocated); + + if (status != 0) { + int error = WSAGetLastError(); + if (error != WSA_IO_PENDING) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + __debugbreak(); + gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message); + gpr_free(utf8_message); + /* would the IO completion port be called anyway ? Let's assume not. */ + tcp->outstanding_write = 0; + tcp_unref(tcp); + return GRPC_ENDPOINT_WRITE_ERROR; + } + gpr_log(GPR_DEBUG, "win_write: got pending op"); + } else { + gpr_log(GPR_DEBUG, "wrote data immediately - but we're going to sleep"); + } + + grpc_handle_notify_on_write(socket, on_write, tcp); + return GRPC_ENDPOINT_WRITE_PENDING; +} + +static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { + grpc_tcp *tcp = (grpc_tcp *) ep; + gpr_log(GPR_DEBUG, "win_add_to_pollset"); + grpc_pollset_add_handle(pollset, tcp->socket); +} + +static void win_shutdown(grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *) ep; + gpr_log(GPR_DEBUG, "win_shutdown"); + grpc_winsocket_shutdown(tcp->socket); +} + +static void win_destroy(grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *) ep; + gpr_log(GPR_DEBUG, "win_destroy"); + tcp_unref(tcp); +} + +static grpc_endpoint_vtable vtable = { + win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy +}; + +grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) { + grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp)); + memset(tcp, 0, sizeof(grpc_tcp)); + tcp->base.vtable = &vtable; + tcp->socket = socket; + gpr_slice_buffer_init(&tcp->write_slices); + gpr_ref_init(&tcp->refcount, 1); + return &tcp->base; +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_windows.h b/src/core/iomgr/tcp_windows.h new file mode 100644 index 00000000000..cbe60801b49 --- /dev/null +++ b/src/core/iomgr/tcp_windows.h @@ -0,0 +1,57 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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. + * + */ + +#ifndef __GRPC_INTERNAL_IOMGR_TCP_WINDOWS_H__ +#define __GRPC_INTERNAL_IOMGR_TCP_WINDOWS_H__ +/* + Low level TCP "bottom half" implementation, for use by transports built on + top of a TCP connection. + + Note that this file does not (yet) include APIs for creating the socket in + the first place. + + All calls passing slice transfer ownership of a slice refcount unless + otherwise specified. +*/ + +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/socket_windows.h" + +/* Create a tcp endpoint given a winsock handle. + * Takes ownership of the handle. + */ +grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket); + +int grpc_tcp_prepare_socket(SOCKET sock); + +#endif /* __GRPC_INTERNAL_IOMGR_TCP_WINDOWS_H__ */ diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c index dc8c1d0785a..e1cf6fb10a4 100644 --- a/src/core/support/log_win32.c +++ b/src/core/support/log_win32.c @@ -35,6 +35,7 @@ #ifdef GPR_WIN32 +#include #include #include #include @@ -74,8 +75,42 @@ void gpr_log(const char *file, int line, gpr_log_severity severity, /* Simple starter implementation */ void gpr_default_log(gpr_log_func_args *args) { - fprintf(stderr, "%s %s:%d: %s\n", gpr_log_severity_string(args->severity), + fprintf(stderr, "%s.%u %s:%d: %s\n", + gpr_log_severity_string(args->severity), GetCurrentThreadId(), args->file, args->line, args->message); } +/* Arguable, this could become a public function. But hardly + * anything beside the Windows implementation should use + * it, so, never mind...*/ +#if defined UNICODE || defined _UNICODE +static char *tchar_to_char(LPWSTR input) { + char *ret; + int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); + if (needed == 0) return NULL; + ret = gpr_malloc(needed + 1); + WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); + ret[needed] = 0; + return ret; +} +#else +static char *tchar_to_char(LPSTR input) { + return gpr_strdup(input); +} #endif + +char *gpr_format_message(DWORD messageid) { + LPTSTR tmessage; + char *message; + DWORD status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, messageid, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)(&tmessage), 0, NULL); + message = tchar_to_char(tmessage); + LocalFree(tmessage); + return message; +} + +#endif /* GPR_WIN32 */ diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c index 287f83eebca..cf3455ca6b6 100644 --- a/test/core/end2end/cq_verifier.c +++ b/test/core/end2end/cq_verifier.c @@ -31,13 +31,6 @@ * */ -/* Disable sprintf warnings on Windows (it's fine to do that for test code). - Also, cases where sprintf is called are crash sites anyway. - TODO(jtattermusch): b/18636890 */ -#ifdef _MSC_VER -#define _CRT_SECURE_NO_WARNINGS -#endif - #include "test/core/end2end/cq_verifier.h" #include diff --git a/vsprojects/vs2013/global.props b/vsprojects/vs2013/global.props index 6a9050e3d2b..27efc13b247 100644 --- a/vsprojects/vs2013/global.props +++ b/vsprojects/vs2013/global.props @@ -1,12 +1,14 @@ - - - - - - - - $(SolutionDir)\..\..;$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\third_party\zlib;$(SolutionDir)\..\third_party;$(SolutionDir)\..\..\third_party\openssl\inc32 - - - + + + + + + + + $(SolutionDir)\..\..;$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\third_party\zlib;$(SolutionDir)\..\third_party;$(SolutionDir)\..\..\third_party\openssl\inc32 + _CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions) + EnableAllWarnings + + + \ No newline at end of file diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj index f71b586aff4..0a11b617c5d 100644 --- a/vsprojects/vs2013/gpr.vcxproj +++ b/vsprojects/vs2013/gpr.vcxproj @@ -83,6 +83,7 @@ + diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters index 013ed4b3c99..2a8eb1d9a4f 100644 --- a/vsprojects/vs2013/gpr.vcxproj.filters +++ b/vsprojects/vs2013/gpr.vcxproj.filters @@ -111,6 +111,9 @@ include\grpc\support + + include\grpc\support + include\grpc\support diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj index 21a1f06f6d6..10c8472b7e3 100644 --- a/vsprojects/vs2013/grpc.vcxproj +++ b/vsprojects/vs2013/grpc.vcxproj @@ -118,6 +118,7 @@ + @@ -130,9 +131,11 @@ + + @@ -256,6 +259,8 @@ + + @@ -274,12 +279,18 @@ + + + + + + diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters index 3af681a4666..53f3a1161ac 100644 --- a/vsprojects/vs2013/grpc.vcxproj.filters +++ b/vsprojects/vs2013/grpc.vcxproj.filters @@ -118,6 +118,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -145,15 +148,24 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr + + src\core\iomgr + src\core\iomgr src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -437,6 +449,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -473,6 +488,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -482,6 +500,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj index 21a1f06f6d6..10c8472b7e3 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj @@ -118,6 +118,7 @@ + @@ -130,9 +131,11 @@ + + @@ -256,6 +259,8 @@ + + @@ -274,12 +279,18 @@ + + + + + + diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters index 4dadb611921..7b37c6d2472 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters @@ -79,6 +79,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -106,15 +109,24 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr + + src\core\iomgr + src\core\iomgr src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -362,6 +374,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -398,6 +413,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -407,6 +425,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr From ee0c96c7fc4bdcf908969eedb96b248e33db1cbb Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 4 Feb 2015 23:35:41 +0100 Subject: [PATCH 2/7] Second draft of the win32 implementation. -) Client code is now threadsafe. -) The echo_client code runs and succeeds. --- include/grpc/support/log_win32.h | 2 +- src/core/iomgr/iomgr_posix.c | 2 +- src/core/iomgr/iomgr_windows.c | 2 +- src/core/iomgr/pollset_windows.c | 30 ++++++++++++++++++++++++++---- src/core/iomgr/pollset_windows.h | 6 ++++-- src/core/iomgr/sockaddr_win32.h | 2 +- src/core/iomgr/socket_windows.c | 4 ++-- src/core/iomgr/socket_windows.h | 4 +++- src/core/iomgr/tcp_windows.c | 26 ++++++++++++++++++++------ src/core/support/log_win32.c | 17 +++++++++++++++-- 10 files changed, 74 insertions(+), 21 deletions(-) diff --git a/include/grpc/support/log_win32.h b/include/grpc/support/log_win32.h index 7abd5df3941..0350056d26e 100644 --- a/include/grpc/support/log_win32.h +++ b/include/grpc/support/log_win32.h @@ -42,7 +42,7 @@ extern "C" { /* Returns a string allocated with gpr_malloc that contains a UTF-8 * formatted error message, corresponding to the error messageid. - * Use in cunjunction with GetLastError() et al. + * Use in conjunction with GetLastError() et al. */ char *gpr_format_message(DWORD messageid); diff --git a/src/core/iomgr/iomgr_posix.c b/src/core/iomgr/iomgr_posix.c index 22ca74314cb..bbf8cfc4190 100644 --- a/src/core/iomgr/iomgr_posix.c +++ b/src/core/iomgr/iomgr_posix.c @@ -48,4 +48,4 @@ void grpc_iomgr_platform_shutdown(void) { grpc_fd_global_shutdown(); } -#endif /* GRPC_IOMGRP_POSIX */ +#endif /* GRPC_POSIX_SOCKET */ diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c index 9cdf224ad77..5c8382e1c01 100644 --- a/src/core/iomgr/iomgr_windows.c +++ b/src/core/iomgr/iomgr_windows.c @@ -64,4 +64,4 @@ void grpc_iomgr_platform_shutdown(void) { winsock_shutdown(); } -#endif /* GRPC_IOMGRP_POSIX */ +#endif /* GRPC_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c index fdebede4828..134e6f45e21 100644 --- a/src/core/iomgr/pollset_windows.c +++ b/src/core/iomgr/pollset_windows.c @@ -38,6 +38,8 @@ #include #include +#include +#include #include #include "src/core/iomgr/alarm_internal.h" @@ -53,6 +55,8 @@ static gpr_event g_shutdown_global_poller; static gpr_event g_global_poller_done; void grpc_pollset_init(grpc_pollset *pollset) { + gpr_mu_init(&pollset->mu); + gpr_cv_init(&pollset->cv); pollset->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); GPR_ASSERT(pollset->iocp); @@ -60,6 +64,8 @@ void grpc_pollset_init(grpc_pollset *pollset) { void grpc_pollset_destroy(grpc_pollset *pollset) { BOOL status; + gpr_mu_destroy(&pollset->mu); + gpr_cv_destroy(&pollset->cv); status = CloseHandle(pollset->iocp); GPR_ASSERT(status); } @@ -76,10 +82,11 @@ static int pollset_poll(grpc_pollset *pollset, grpc_winsocket_callback_info *info; void(*f)(void *, int) = NULL; void *opaque = NULL; + gpr_mu_unlock(&pollset->mu); success = GetQueuedCompletionStatus(pollset->iocp, &bytes, &completion_key, &overlapped, gpr_time_to_millis(wait_time)); - + gpr_mu_lock(&pollset->mu); if (!success && !overlapped) { /* The deadline got attained. */ return 0; @@ -95,6 +102,8 @@ static int pollset_poll(grpc_pollset *pollset, abort(); } + GPR_ASSERT(pollset == &g_global_pollset); + socket = (grpc_winsocket*) completion_key; if (overlapped == &socket->write_info.overlapped) { gpr_log(GPR_DEBUG, "pollset_poll - got write packet"); @@ -153,7 +162,9 @@ void grpc_pollset_kick(grpc_pollset *pollset) { static void global_poller(void *p) { while (!gpr_event_get(&g_shutdown_global_poller)) { + gpr_mu_lock(&g_global_pollset.mu); grpc_pollset_work(&g_global_pollset, gpr_inf_future); + gpr_mu_unlock(&g_global_pollset.mu); } gpr_event_set(&g_global_poller_done, (void *) 1); @@ -176,9 +187,20 @@ void grpc_pollset_global_shutdown(void) { } void grpc_pollset_add_handle(grpc_pollset *pollset, grpc_winsocket *socket) { - HANDLE ret = CreateIoCompletionPort((HANDLE) socket->socket, pollset->iocp, - (gpr_uintptr) socket, 0); - GPR_ASSERT(ret == pollset->iocp); + HANDLE ret; + if (socket->added_to_iocp) return; + ret = CreateIoCompletionPort((HANDLE)socket->socket, + g_global_pollset.iocp, + (gpr_uintptr) socket, 0); + if (!ret) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); + gpr_free(utf8_message); + __debugbreak(); + abort(); + } + socket->added_to_iocp = 1; + GPR_ASSERT(ret == g_global_pollset.iocp); } static void handle_notify_on_iocp(grpc_winsocket *socket, diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h index 036f3910a01..919af5d7b73 100644 --- a/src/core/iomgr/pollset_windows.h +++ b/src/core/iomgr/pollset_windows.h @@ -46,11 +46,13 @@ struct grpc_fd; typedef struct grpc_pollset { + gpr_mu mu; + gpr_cv cv; HANDLE iocp; } grpc_pollset; -#define GRPC_POLLSET_MU(pollset) (NULL) -#define GRPC_POLLSET_CV(pollset) (NULL) +#define GRPC_POLLSET_MU(pollset) (&(pollset)->mu) +#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv) void grpc_pollset_add_handle(grpc_pollset *, grpc_winsocket *); diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h index 350f5fa33e1..08be0e54f8e 100644 --- a/src/core/iomgr/sockaddr_win32.h +++ b/src/core/iomgr/sockaddr_win32.h @@ -38,4 +38,4 @@ #include #include -#endif // __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_ +#endif /* __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_ */ diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c index 7d1d59c3187..805e96a0d15 100644 --- a/src/core/iomgr/socket_windows.c +++ b/src/core/iomgr/socket_windows.c @@ -56,7 +56,7 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket) { void shutdown_op(grpc_winsocket_callback_info *info) { if (!info->cb) return; - info->cb(info->opaque, 0); + grpc_iomgr_add_delayed_callback(info->cb, info->opaque, 0); } void grpc_winsocket_shutdown(grpc_winsocket *socket) { @@ -73,4 +73,4 @@ void grpc_winsocket_orphan(grpc_winsocket *socket) { gpr_free(socket); } -#endif +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h index ca85ea54cbf..19822ac085c 100644 --- a/src/core/iomgr/socket_windows.h +++ b/src/core/iomgr/socket_windows.h @@ -57,6 +57,8 @@ typedef struct grpc_winsocket_callback_info { typedef struct grpc_winsocket { SOCKET socket; + int added_to_iocp; + grpc_winsocket_callback_info write_info; grpc_winsocket_callback_info read_info; @@ -70,4 +72,4 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket); void grpc_winsocket_shutdown(grpc_winsocket *socket); void grpc_winsocket_orphan(grpc_winsocket *socket); -#endif /* __GRPC_INTERNAL_IOMGR_FD_POSIX_H_ */ +#endif /* __GRPC_INTERNAL_IOMGR_HANDLE_WINDOWS_H__ */ diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c index 0eb6663dd48..967177fdb1c 100644 --- a/src/core/iomgr/tcp_windows.c +++ b/src/core/iomgr/tcp_windows.c @@ -58,9 +58,18 @@ static int set_non_block(SOCKET sock) { return status == 0; } +static int set_dualstack(SOCKET sock) { + int status; + unsigned long param = 0; + status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ¶m, sizeof(param)); + return status == 0; +} + int grpc_tcp_prepare_socket(SOCKET sock) { if (!set_non_block(sock)) return 0; + if (!set_dualstack(sock)) + return 0; return 1; } @@ -110,8 +119,9 @@ static void on_read(void *tcpp, int success) { GPR_ASSERT(tcp->outstanding_read); if (!success) { - __debugbreak(); - abort(); + tcp_unref(tcp); + cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + return; } gpr_log(GPR_DEBUG, "on_read"); @@ -163,7 +173,6 @@ static void win_notify_on_read(grpc_endpoint *ep, buffer.buf = GPR_SLICE_START_PTR(tcp->read_slice); gpr_log(GPR_DEBUG, "win_notify_on_read: calling WSARecv without overlap"); - status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); @@ -183,7 +192,7 @@ static void win_notify_on_read(grpc_endpoint *ep, &info->overlapped, NULL); if (status == 0) { - gpr_log(GPR_DEBUG, "got response immediately, but we're goint to sleep"); + gpr_log(GPR_DEBUG, "got response immediately, but we're going to sleep"); grpc_handle_notify_on_read(tcp->socket, on_read, tcp); return; } @@ -219,8 +228,9 @@ static void on_write(void *tcpp, int success) { gpr_log(GPR_DEBUG, "on_write"); if (!success) { - __debugbreak(); - abort(); + tcp_unref(tcp); + cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + return; } if (info->wsa_error != 0) { @@ -286,6 +296,10 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep, if (status == 0) { ret = GRPC_ENDPOINT_WRITE_DONE; GPR_ASSERT(bytes_sent == tcp->write_slices.length); + } else { + char *utf8_message = gpr_format_message(info->wsa_error); + gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message); + gpr_free(utf8_message); } if (allocated) gpr_free(allocated); gpr_slice_buffer_reset_and_unref(&tcp->write_slices); diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c index e1cf6fb10a4..4c0a866048f 100644 --- a/src/core/support/log_win32.c +++ b/src/core/support/log_win32.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -75,8 +76,20 @@ void gpr_log(const char *file, int line, gpr_log_severity severity, /* Simple starter implementation */ void gpr_default_log(gpr_log_func_args *args) { - fprintf(stderr, "%s.%u %s:%d: %s\n", - gpr_log_severity_string(args->severity), GetCurrentThreadId(), + char time_buffer[64]; + gpr_timespec now = gpr_now(); + struct tm tm; + + if (localtime_s(&tm, &now.tv_sec)) { + strcpy(time_buffer, "error:localtime"); + } else if (0 == + strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { + strcpy(time_buffer, "error:strftime"); + } + + fprintf(stderr, "%s%s.%09u %5u %s:%d: %s\n", + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), GetCurrentThreadId(), args->file, args->line, args->message); } From ba410fabdf476ba61fef22a1f3205bc6d8f96a4b Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 5 Feb 2015 00:54:15 +0100 Subject: [PATCH 3/7] Fixing bad copy/paste. --- src/core/iomgr/tcp_windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c index 967177fdb1c..734628dd8ee 100644 --- a/src/core/iomgr/tcp_windows.c +++ b/src/core/iomgr/tcp_windows.c @@ -229,7 +229,7 @@ static void on_write(void *tcpp, int success) { if (!success) { tcp_unref(tcp); - cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN); return; } From 0f3ec822380081670edd0e9e1d7e40c1122bda21 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 5 Feb 2015 19:40:38 +0100 Subject: [PATCH 4/7] Adding Windows tcp server code. --- Makefile | 5 + build.json | 1 + src/core/iomgr/sockaddr_utils.c | 19 +- src/core/iomgr/sockaddr_utils.h | 6 + src/core/iomgr/tcp_client_windows.c | 8 +- src/core/iomgr/tcp_server_windows.c | 372 ++++++++++++++++++ src/core/iomgr/tcp_windows.c | 5 +- vsprojects/vs2013/grpc.vcxproj | 2 + vsprojects/vs2013/grpc.vcxproj.filters | 3 + vsprojects/vs2013/grpc_unsecure.vcxproj | 2 + .../vs2013/grpc_unsecure.vcxproj.filters | 3 + 11 files changed, 412 insertions(+), 14 deletions(-) create mode 100644 src/core/iomgr/tcp_server_windows.c diff --git a/Makefile b/Makefile index 2dd70a5a333..7a4ca9303eb 100644 --- a/Makefile +++ b/Makefile @@ -1437,6 +1437,7 @@ LIBGRPC_SRC = \ src/core/iomgr/tcp_client_windows.c \ src/core/iomgr/tcp_posix.c \ src/core/iomgr/tcp_server_posix.c \ + src/core/iomgr/tcp_server_windows.c \ src/core/iomgr/tcp_windows.c \ src/core/iomgr/time_averaged_stats.c \ src/core/iomgr/wakeup_fd_eventfd.c \ @@ -1567,6 +1568,7 @@ src/core/iomgr/tcp_client_posix.c: $(OPENSSL_DEP) src/core/iomgr/tcp_client_windows.c: $(OPENSSL_DEP) src/core/iomgr/tcp_posix.c: $(OPENSSL_DEP) src/core/iomgr/tcp_server_posix.c: $(OPENSSL_DEP) +src/core/iomgr/tcp_server_windows.c: $(OPENSSL_DEP) src/core/iomgr/tcp_windows.c: $(OPENSSL_DEP) src/core/iomgr/time_averaged_stats.c: $(OPENSSL_DEP) src/core/iomgr/wakeup_fd_eventfd.c: $(OPENSSL_DEP) @@ -1719,6 +1721,7 @@ objs/$(CONFIG)/src/core/iomgr/tcp_client_posix.o: objs/$(CONFIG)/src/core/iomgr/tcp_client_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_posix.o: objs/$(CONFIG)/src/core/iomgr/tcp_server_posix.o: +objs/$(CONFIG)/src/core/iomgr/tcp_server_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_windows.o: objs/$(CONFIG)/src/core/iomgr/time_averaged_stats.o: objs/$(CONFIG)/src/core/iomgr/wakeup_fd_eventfd.o: @@ -1890,6 +1893,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/iomgr/tcp_client_windows.c \ src/core/iomgr/tcp_posix.c \ src/core/iomgr/tcp_server_posix.c \ + src/core/iomgr/tcp_server_windows.c \ src/core/iomgr/tcp_windows.c \ src/core/iomgr/time_averaged_stats.c \ src/core/iomgr/wakeup_fd_eventfd.c \ @@ -2025,6 +2029,7 @@ objs/$(CONFIG)/src/core/iomgr/tcp_client_posix.o: objs/$(CONFIG)/src/core/iomgr/tcp_client_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_posix.o: objs/$(CONFIG)/src/core/iomgr/tcp_server_posix.o: +objs/$(CONFIG)/src/core/iomgr/tcp_server_windows.o: objs/$(CONFIG)/src/core/iomgr/tcp_windows.o: objs/$(CONFIG)/src/core/iomgr/time_averaged_stats.o: objs/$(CONFIG)/src/core/iomgr/wakeup_fd_eventfd.o: diff --git a/build.json b/build.json index 98377cddad5..4a23f245d2d 100644 --- a/build.json +++ b/build.json @@ -149,6 +149,7 @@ "src/core/iomgr/tcp_client_windows.c", "src/core/iomgr/tcp_posix.c", "src/core/iomgr/tcp_server_posix.c", + "src/core/iomgr/tcp_server_windows.c", "src/core/iomgr/tcp_windows.c", "src/core/iomgr/time_averaged_stats.c", "src/core/iomgr/wakeup_fd_eventfd.c", diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c index 07bf7b3a35c..8dcfca74c68 100644 --- a/src/core/iomgr/sockaddr_utils.c +++ b/src/core/iomgr/sockaddr_utils.c @@ -111,13 +111,20 @@ int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) { void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, struct sockaddr_in6 *wild6_out) { - memset(wild4_out, 0, sizeof(*wild4_out)); - wild4_out->sin_family = AF_INET; - wild4_out->sin_port = htons(port); + grpc_sockaddr_make_wildcard4(port, wild4_out); + grpc_sockaddr_make_wildcard6(port, wild6_out); +} + +void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) { + memset(wild_out, 0, sizeof(*wild_out)); + wild_out->sin_family = AF_INET; + wild_out->sin_port = htons(port); +} - memset(wild6_out, 0, sizeof(*wild6_out)); - wild6_out->sin6_family = AF_INET6; - wild6_out->sin6_port = htons(port); +void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) { + memset(wild_out, 0, sizeof(*wild_out)); + wild_out->sin6_family = AF_INET6; + wild_out->sin6_port = htons(port); } int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, diff --git a/src/core/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h index 3f5b770e865..b49cc50491c 100644 --- a/src/core/iomgr/sockaddr_utils.h +++ b/src/core/iomgr/sockaddr_utils.h @@ -57,6 +57,12 @@ int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out); void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, struct sockaddr_in6 *wild6_out); +/* Writes 0.0.0.0:port. */ +void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out); + +/* Writes [::]:port. */ +void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out); + /* Return the IP port number of a sockaddr */ int grpc_sockaddr_get_port(const struct sockaddr *addr); diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c index 465fc75295d..37e6b125522 100644 --- a/src/core/iomgr/tcp_client_windows.c +++ b/src/core/iomgr/tcp_client_windows.c @@ -106,9 +106,7 @@ static void on_connect(void *acp, int success) { goto finish; } } else { - __debugbreak(); - abort(); - gpr_log(GPR_ERROR, "on_writable failed during connect"); + gpr_log(GPR_ERROR, "on_connect is shutting down"); goto finish; } @@ -167,9 +165,7 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp), goto failure; } - memset(&local_address, 0, sizeof(local_address)); - memcpy(&local_address.sin6_addr, &in6addr_any, sizeof(in6addr_any)); - local_address.sin6_family = AF_INET6; + grpc_sockaddr_make_wildcard6(0, &local_address); status = bind(sock, (struct sockaddr *) &local_address, sizeof(local_address)); diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c new file mode 100644 index 00000000000..21901958d1c --- /dev/null +++ b/src/core/iomgr/tcp_server_windows.c @@ -0,0 +1,372 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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 + +#ifdef GPR_WINSOCK_SOCKET + +#define _GNU_SOURCE +#include "src/core/iomgr/sockaddr_utils.h" + +#include "src/core/iomgr/pollset_windows.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_server.h" +#include "src/core/iomgr/tcp_windows.h" +#include +#include +#include +#include +#include + +#define INIT_PORT_CAP 2 +#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 + +static gpr_once s_init_max_accept_queue_size; +static int s_max_accept_queue_size; + +/* one listening port */ +typedef struct server_port { + gpr_uint8 addresses[sizeof(struct sockaddr_in6) * 2 + 32]; + SOCKET new_socket; + grpc_winsocket *socket; + grpc_tcp_server *server; + LPFN_ACCEPTEX AcceptEx; +} server_port; + +/* the overall server */ +struct grpc_tcp_server { + grpc_tcp_server_cb cb; + void *cb_arg; + + gpr_mu mu; + gpr_cv cv; + + /* active port count: how many ports are actually still listening */ + int active_ports; + + /* all listening ports */ + server_port *ports; + size_t nports; + size_t port_capacity; +}; + +grpc_tcp_server *grpc_tcp_server_create(void) { + grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); + gpr_mu_init(&s->mu); + gpr_cv_init(&s->cv); + s->active_ports = 0; + s->cb = NULL; + s->cb_arg = NULL; + s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); + s->nports = 0; + s->port_capacity = INIT_PORT_CAP; + return s; +} + +void grpc_tcp_server_destroy(grpc_tcp_server *s) { + size_t i; + gpr_mu_lock(&s->mu); + /* shutdown all fd's */ + for (i = 0; i < s->nports; i++) { + grpc_winsocket_shutdown(s->ports[i].socket); + } + /* wait while that happens */ + while (s->active_ports) { + gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future); + } + gpr_mu_unlock(&s->mu); + + /* delete ALL the things */ + for (i = 0; i < s->nports; i++) { + server_port *sp = &s->ports[i]; + grpc_winsocket_orphan(sp->socket); + } + gpr_free(s->ports); + gpr_free(s); +} + +/* Prepare a recently-created socket for listening. */ +static int prepare_socket(SOCKET sock, + const struct sockaddr *addr, int addr_len) { + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + + if (sock == INVALID_SOCKET) goto error; + + if (!grpc_tcp_prepare_socket(sock)) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message); + gpr_free(utf8_message); + goto error; + } + + if (bind(sock, addr, addr_len) == SOCKET_ERROR) { + char *addr_str; + char *utf8_message = gpr_format_message(WSAGetLastError()); + grpc_sockaddr_to_string(&addr_str, addr, 0); + gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message); + gpr_free(utf8_message); + gpr_free(addr_str); + goto error; + } + + if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "listen: %s", utf8_message); + gpr_free(utf8_message); + goto error; + } + + sockname_len = sizeof(sockname_temp); + if (getsockname(sock, (struct sockaddr *) &sockname_temp, &sockname_len) + == SOCKET_ERROR) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "getsockname: %s", utf8_message); + gpr_free(utf8_message); + goto error; + } + + return grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp); + +error: + if (sock != INVALID_SOCKET) closesocket(sock); + return -1; +} + +static void on_accept(void *arg, int success); + +static void start_accept(server_port *port) { + SOCKET sock = INVALID_SOCKET; + char *message; + char *utf8_message; + BOOL success; + DWORD addrlen = sizeof(struct sockaddr_in6) + 16; + DWORD bytes_received = 0; + + sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + + if (sock == INVALID_SOCKET) { + message = "Unable to create socket: %s"; + goto failure; + } + + if (!grpc_tcp_prepare_socket(sock)) { + message = "Unable to prepare socket: %s"; + goto failure; + } + + success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0, + addrlen, addrlen, &bytes_received, + &port->socket->read_info.overlapped); + + if (success) { + gpr_log(GPR_DEBUG, "accepted immediately - but we still go to sleep"); + } else { + int error = WSAGetLastError(); + if (error != ERROR_IO_PENDING) { + message = "AcceptEx failed: %s"; + goto failure; + } + } + + port->new_socket = sock; + grpc_handle_notify_on_read(port->socket, on_accept, port); + return; + +failure: + utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, message, utf8_message); + gpr_free(utf8_message); + if (sock != INVALID_SOCKET) closesocket(sock); +} + +/* event manager callback when reads are ready */ +static void on_accept(void *arg, int success) { + server_port *sp = arg; + SOCKET sock = sp->new_socket; + grpc_winsocket_callback_info *info = &sp->socket->read_info; + grpc_endpoint *ep = NULL; + + if (success) { + DWORD transfered_bytes = 0; + DWORD flags; + BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, + &transfered_bytes, FALSE, + &flags); + if (!wsa_success) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message); + gpr_free(utf8_message); + closesocket(sock); + } else { + gpr_log(GPR_DEBUG, "on_accept: accepted connection"); + ep = grpc_tcp_create(grpc_winsocket_create(sock)); + } + } else { + gpr_log(GPR_DEBUG, "on_accept: shutting down"); + closesocket(sock); + gpr_mu_lock(&sp->server->mu); + if (0 == --sp->server->active_ports) { + gpr_cv_broadcast(&sp->server->cv); + } + gpr_mu_unlock(&sp->server->mu); + } + + if (ep) sp->server->cb(sp->server->cb_arg, ep); + start_accept(sp); +} + +static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock, + const struct sockaddr *addr, int addr_len) { + server_port *sp; + int port; + int status; + GUID guid = WSAID_ACCEPTEX; + DWORD ioctl_num_bytes; + LPFN_ACCEPTEX AcceptEx; + + if (sock == INVALID_SOCKET) return -1; + + status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, sizeof(guid), &AcceptEx, sizeof(AcceptEx), + &ioctl_num_bytes, NULL, NULL); + + if (status != 0) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); + gpr_free(utf8_message); + closesocket(sock); + return -1; + } + + port = prepare_socket(sock, addr, addr_len); + if (port >= 0) { + gpr_mu_lock(&s->mu); + GPR_ASSERT(!s->cb && "must add ports before starting server"); + /* append it to the list under a lock */ + if (s->nports == s->port_capacity) { + s->port_capacity *= 2; + s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); + } + sp = &s->ports[s->nports++]; + sp->server = s; + sp->socket = grpc_winsocket_create(sock); + sp->AcceptEx = AcceptEx; + GPR_ASSERT(sp->socket); + gpr_mu_unlock(&s->mu); + } + + return port; +} + +int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, + int addr_len) { + int allocated_port = -1; + unsigned i; + SOCKET sock; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in6 wildcard; + struct sockaddr *allocated_addr = NULL; + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + int port; + + /* Check if this is a wildcard port, and if so, try to keep the port the same + as some previously created listener. */ + if (grpc_sockaddr_get_port(addr) == 0) { + for (i = 0; i < s->nports; i++) { + sockname_len = sizeof(sockname_temp); + if (0 == getsockname(s->ports[i].socket->socket, + (struct sockaddr *) &sockname_temp, + &sockname_len)) { + port = grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp); + if (port > 0) { + allocated_addr = malloc(addr_len); + memcpy(allocated_addr, addr, addr_len); + grpc_sockaddr_set_port(allocated_addr, port); + addr = allocated_addr; + break; + } + } + } + } + + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ + if (grpc_sockaddr_is_wildcard(addr, &port)) { + grpc_sockaddr_make_wildcard6(port, &wildcard); + + addr = (struct sockaddr *) &wildcard; + addr_len = sizeof(wildcard); + } + + sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message); + gpr_free(utf8_message); + } + + allocated_port = add_socket_to_server(s, sock, addr, addr_len); + gpr_free(allocated_addr); + + return allocated_port; +} + +SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) { + return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET; +} + +void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset *pollset, + grpc_tcp_server_cb cb, void *cb_arg) { + size_t i; + GPR_ASSERT(cb); + gpr_mu_lock(&s->mu); + GPR_ASSERT(!s->cb); + GPR_ASSERT(s->active_ports == 0); + s->cb = cb; + s->cb_arg = cb_arg; + for (i = 0; i < s->nports; i++) { + start_accept(s->ports + i); + s->active_ports++; + } + gpr_mu_unlock(&s->mu); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c index 734628dd8ee..bd0b2dd869b 100644 --- a/src/core/iomgr/tcp_windows.c +++ b/src/core/iomgr/tcp_windows.c @@ -61,7 +61,8 @@ static int set_non_block(SOCKET sock) { static int set_dualstack(SOCKET sock) { int status; unsigned long param = 0; - status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ¶m, sizeof(param)); + status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (const char *) ¶m, sizeof(param)); return status == 0; } @@ -120,7 +121,7 @@ static void on_read(void *tcpp, int success) { if (!success) { tcp_unref(tcp); - cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN); return; } diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj index 10c8472b7e3..6d791789e47 100644 --- a/vsprojects/vs2013/grpc.vcxproj +++ b/vsprojects/vs2013/grpc.vcxproj @@ -289,6 +289,8 @@ + + diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters index 53f3a1161ac..55f0108a4ba 100644 --- a/vsprojects/vs2013/grpc.vcxproj.filters +++ b/vsprojects/vs2013/grpc.vcxproj.filters @@ -163,6 +163,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj index 10c8472b7e3..6d791789e47 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj @@ -289,6 +289,8 @@ + + diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters index 7b37c6d2472..23daa46e3d3 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters @@ -124,6 +124,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr From 45e67a37ae63b14d22eab7ee4bea9b912baa7010 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Mon, 9 Feb 2015 16:20:49 -0800 Subject: [PATCH 5/7] Addressing comments. --- Makefile | 5 + build.json | 3 +- src/core/iomgr/iocp_windows.c | 200 ++++++++++++++++++ .../iomgr/{iomgr_windows.h => iocp_windows.h} | 20 +- src/core/iomgr/iomgr_windows.c | 6 +- src/core/iomgr/pollset_windows.c | 174 +-------------- src/core/iomgr/pollset_windows.h | 11 - src/core/iomgr/socket_windows.c | 3 +- src/core/iomgr/tcp_client_windows.c | 2 +- src/core/iomgr/tcp_server_windows.c | 2 +- src/core/iomgr/tcp_windows.c | 15 +- vsprojects/vs2013/grpc.vcxproj | 4 +- vsprojects/vs2013/grpc.vcxproj.filters | 9 +- vsprojects/vs2013/grpc_unsecure.vcxproj | 4 +- .../vs2013/grpc_unsecure.vcxproj.filters | 9 +- 15 files changed, 257 insertions(+), 210 deletions(-) create mode 100644 src/core/iomgr/iocp_windows.c rename src/core/iomgr/{iomgr_windows.h => iocp_windows.h} (74%) diff --git a/Makefile b/Makefile index 7a4ca9303eb..8ca21b7e97a 100644 --- a/Makefile +++ b/Makefile @@ -1420,6 +1420,7 @@ LIBGRPC_SRC = \ src/core/iomgr/endpoint.c \ src/core/iomgr/endpoint_pair_posix.c \ src/core/iomgr/fd_posix.c \ + src/core/iomgr/iocp_windows.c \ src/core/iomgr/iomgr.c \ src/core/iomgr/iomgr_posix.c \ src/core/iomgr/iomgr_windows.c \ @@ -1551,6 +1552,7 @@ src/core/iomgr/alarm_heap.c: $(OPENSSL_DEP) src/core/iomgr/endpoint.c: $(OPENSSL_DEP) src/core/iomgr/endpoint_pair_posix.c: $(OPENSSL_DEP) src/core/iomgr/fd_posix.c: $(OPENSSL_DEP) +src/core/iomgr/iocp_windows.c: $(OPENSSL_DEP) src/core/iomgr/iomgr.c: $(OPENSSL_DEP) src/core/iomgr/iomgr_posix.c: $(OPENSSL_DEP) src/core/iomgr/iomgr_windows.c: $(OPENSSL_DEP) @@ -1704,6 +1706,7 @@ objs/$(CONFIG)/src/core/iomgr/alarm_heap.o: objs/$(CONFIG)/src/core/iomgr/endpoint.o: objs/$(CONFIG)/src/core/iomgr/endpoint_pair_posix.o: objs/$(CONFIG)/src/core/iomgr/fd_posix.o: +objs/$(CONFIG)/src/core/iomgr/iocp_windows.o: objs/$(CONFIG)/src/core/iomgr/iomgr.o: objs/$(CONFIG)/src/core/iomgr/iomgr_posix.o: objs/$(CONFIG)/src/core/iomgr/iomgr_windows.o: @@ -1876,6 +1879,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/iomgr/endpoint.c \ src/core/iomgr/endpoint_pair_posix.c \ src/core/iomgr/fd_posix.c \ + src/core/iomgr/iocp_windows.c \ src/core/iomgr/iomgr.c \ src/core/iomgr/iomgr_posix.c \ src/core/iomgr/iomgr_windows.c \ @@ -2012,6 +2016,7 @@ objs/$(CONFIG)/src/core/iomgr/alarm_heap.o: objs/$(CONFIG)/src/core/iomgr/endpoint.o: objs/$(CONFIG)/src/core/iomgr/endpoint_pair_posix.o: objs/$(CONFIG)/src/core/iomgr/fd_posix.o: +objs/$(CONFIG)/src/core/iomgr/iocp_windows.o: objs/$(CONFIG)/src/core/iomgr/iomgr.o: objs/$(CONFIG)/src/core/iomgr/iomgr_posix.o: objs/$(CONFIG)/src/core/iomgr/iomgr_windows.o: diff --git a/build.json b/build.json index 4a23f245d2d..d2ce51022b6 100644 --- a/build.json +++ b/build.json @@ -42,10 +42,10 @@ "src/core/iomgr/endpoint.h", "src/core/iomgr/endpoint_pair.h", "src/core/iomgr/fd_posix.h", + "src/core/iomgr/iocp_windows.h", "src/core/iomgr/iomgr.h", "src/core/iomgr/iomgr_internal.h", "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/iomgr_windows.h", "src/core/iomgr/pollset.h", "src/core/iomgr/pollset_kick.h", "src/core/iomgr/pollset_kick_posix.h", @@ -132,6 +132,7 @@ "src/core/iomgr/endpoint.c", "src/core/iomgr/endpoint_pair_posix.c", "src/core/iomgr/fd_posix.c", + "src/core/iomgr/iocp_windows.c", "src/core/iomgr/iomgr.c", "src/core/iomgr/iomgr_posix.c", "src/core/iomgr/iomgr_windows.c", diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c new file mode 100644 index 00000000000..729b11b78dc --- /dev/null +++ b/src/core/iomgr/iocp_windows.c @@ -0,0 +1,200 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * 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. + * * Neither the name of Google Inc. 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 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 + * OWNER 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 + +#ifdef GPR_WINSOCK_SOCKET + +#include + +#include +#include +#include +#include + +#include "src/core/iomgr/alarm_internal.h" +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/socket_windows.h" + +static ULONG g_iocp_kick_token; +static OVERLAPPED g_iocp_custom_overlap; + +static gpr_event g_shutdown_iocp; +static gpr_event g_iocp_done; + +static HANDLE g_iocp; + +static int do_iocp_work() { + BOOL success; + DWORD bytes = 0; + DWORD flags = 0; + ULONG_PTR completion_key; + LPOVERLAPPED overlapped; + gpr_timespec wait_time = gpr_inf_future; + grpc_winsocket *socket; + grpc_winsocket_callback_info *info; + void(*f)(void *, int) = NULL; + void *opaque = NULL; + success = GetQueuedCompletionStatus(g_iocp, &bytes, + &completion_key, &overlapped, + gpr_time_to_millis(wait_time)); + if (!success && !overlapped) { + /* The deadline got attained. */ + return 0; + } + GPR_ASSERT(completion_key && overlapped); + if (overlapped == &g_iocp_custom_overlap) { + if (completion_key == (ULONG_PTR) &g_iocp_kick_token) { + /* We were awoken from a kick. */ + gpr_log(GPR_DEBUG, "do_iocp_work - got a kick"); + return 1; + } + gpr_log(GPR_ERROR, "Unknown custom completion key."); + abort(); + } + + socket = (grpc_winsocket*) completion_key; + if (overlapped == &socket->write_info.overlapped) { + gpr_log(GPR_DEBUG, "do_iocp_work - got write packet"); + info = &socket->write_info; + } else if (overlapped == &socket->read_info.overlapped) { + gpr_log(GPR_DEBUG, "do_iocp_work - got read packet"); + info = &socket->read_info; + } else { + gpr_log(GPR_ERROR, "Unknown IOCP operation"); + abort(); + } + success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, + FALSE, &flags); + gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s", bytes, flags, + success ? "succeeded" : "failed"); + info->bytes_transfered = bytes; + info->wsa_error = success ? 0 : WSAGetLastError(); + GPR_ASSERT(overlapped == &info->overlapped); + gpr_mu_lock(&socket->state_mu); + GPR_ASSERT(!info->has_pending_iocp); + if (info->cb) { + f = info->cb; + opaque = info->opaque; + info->cb = NULL; + } else { + info->has_pending_iocp = 1; + } + gpr_mu_unlock(&socket->state_mu); + if (f) f(opaque, 1); + + return 1; +} + +static void iocp_loop(void *p) { + while (!gpr_event_get(&g_shutdown_iocp)) { + grpc_maybe_call_delayed_callbacks(NULL, 1); + do_iocp_work(); + } + + gpr_event_set(&g_iocp_done, (void *)1); +} + +void grpc_iocp_init(void) { + gpr_thd_id id; + + g_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, + (ULONG_PTR)NULL, 0); + GPR_ASSERT(g_iocp); + + gpr_event_init(&g_iocp_done); + gpr_event_init(&g_shutdown_iocp); + gpr_thd_new(&id, iocp_loop, NULL, NULL); +} + +void grpc_iocp_shutdown(void) { + BOOL success; + gpr_event_set(&g_shutdown_iocp, (void *)1); + success = PostQueuedCompletionStatus(g_iocp, 0, + (ULONG_PTR) &g_iocp_kick_token, + &g_iocp_custom_overlap); + GPR_ASSERT(success); + gpr_event_wait(&g_iocp_done, gpr_inf_future); + success = CloseHandle(g_iocp); + GPR_ASSERT(success); +} + +void grpc_iocp_add_socket(grpc_winsocket *socket) { + HANDLE ret; + if (socket->added_to_iocp) return; + ret = CreateIoCompletionPort((HANDLE)socket->socket, + g_iocp, (gpr_uintptr) socket, 0); + if (!ret) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); + gpr_free(utf8_message); + __debugbreak(); + abort(); + } + socket->added_to_iocp = 1; + GPR_ASSERT(ret == g_iocp); +} + +static void socket_notify_on_iocp(grpc_winsocket *socket, + void(*cb)(void *, int), void *opaque, + grpc_winsocket_callback_info *info) { + int run_now = 0; + GPR_ASSERT(!info->cb); + gpr_mu_lock(&socket->state_mu); + if (info->has_pending_iocp) { + run_now = 1; + info->has_pending_iocp = 0; + gpr_log(GPR_DEBUG, "socket_notify_on_iocp - runs now"); + } else { + info->cb = cb; + info->opaque = opaque; + gpr_log(GPR_DEBUG, "socket_notify_on_iocp - queued"); + } + gpr_mu_unlock(&socket->state_mu); + if (run_now) cb(opaque, 1); +} + +void grpc_socket_notify_on_write(grpc_winsocket *socket, + void(*cb)(void *, int), void *opaque) { + gpr_log(GPR_DEBUG, "grpc_socket_notify_on_write"); + socket_notify_on_iocp(socket, cb, opaque, &socket->write_info); +} + +void grpc_socket_notify_on_read(grpc_winsocket *socket, + void(*cb)(void *, int), void *opaque) { + gpr_log(GPR_DEBUG, "grpc_socket_notify_on_read"); + socket_notify_on_iocp(socket, cb, opaque, &socket->read_info); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/iomgr_windows.h b/src/core/iomgr/iocp_windows.h similarity index 74% rename from src/core/iomgr/iomgr_windows.h rename to src/core/iomgr/iocp_windows.h index 2d9449c1f62..bf5b90978ef 100644 --- a/src/core/iomgr/iomgr_windows.h +++ b/src/core/iomgr/iocp_windows.h @@ -31,12 +31,22 @@ * */ -#ifndef __GRPC_INTERNAL_IOMGR_IOMGR_WINDOWS_H_ -#define __GRPC_INTERNAL_IOMGR_IOMGR_WINDOWS_H_ +#ifndef __GRPC_INTERNAL_IOMGR_IOCP_WINDOWS_H_ +#define __GRPC_INTERNAL_IOMGR_IOCP_WINDOWS_H_ + +#include +#include #include "src/core/iomgr/socket_windows.h" -void grpc_pollset_global_init(void); -void grpc_pollset_global_shutdown(void); +void grpc_iocp_init(void); +void grpc_iocp_shutdown(void); +void grpc_iocp_add_socket(grpc_winsocket *); + +void grpc_socket_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success), + void *opaque); + +void grpc_socket_notify_on_read(grpc_winsocket *, void(*cb)(void *, int success), + void *opaque); -#endif /* __GRPC_INTERNAL_IOMGR_IOMGR_WINDOWS_H_ */ +#endif /* __GRPC_INTERNAL_IOMGR_IOCP_WINDOWS_H_ */ diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c index 5c8382e1c01..a3a255eaed2 100644 --- a/src/core/iomgr/iomgr_windows.c +++ b/src/core/iomgr/iomgr_windows.c @@ -40,8 +40,8 @@ #include #include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/iomgr.h" -#include "src/core/iomgr/iomgr_windows.h" static void winsock_init(void) { WSADATA wsaData; @@ -56,11 +56,11 @@ static void winsock_shutdown(void) { void grpc_iomgr_platform_init(void) { winsock_init(); - grpc_pollset_global_init(); + grpc_iocp_init(); } void grpc_iomgr_platform_shutdown(void) { - grpc_pollset_global_shutdown(); + grpc_iocp_shutdown(); winsock_shutdown(); } diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c index 134e6f45e21..b81d23e57c2 100644 --- a/src/core/iomgr/pollset_windows.c +++ b/src/core/iomgr/pollset_windows.c @@ -35,106 +35,20 @@ #ifdef GPR_WINSOCK_SOCKET -#include - -#include -#include -#include #include #include "src/core/iomgr/alarm_internal.h" -#include "src/core/iomgr/socket_windows.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/pollset_windows.h" -static grpc_pollset g_global_pollset; -static ULONG g_pollset_kick_token; -static OVERLAPPED g_pollset_custom_overlap; - -static gpr_event g_shutdown_global_poller; -static gpr_event g_global_poller_done; - void grpc_pollset_init(grpc_pollset *pollset) { gpr_mu_init(&pollset->mu); gpr_cv_init(&pollset->cv); - pollset->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, - (ULONG_PTR)NULL, 0); - GPR_ASSERT(pollset->iocp); } void grpc_pollset_destroy(grpc_pollset *pollset) { - BOOL status; gpr_mu_destroy(&pollset->mu); gpr_cv_destroy(&pollset->cv); - status = CloseHandle(pollset->iocp); - GPR_ASSERT(status); -} - -static int pollset_poll(grpc_pollset *pollset, - gpr_timespec deadline, gpr_timespec now) { - BOOL success; - DWORD bytes = 0; - DWORD flags = 0; - ULONG_PTR completion_key; - LPOVERLAPPED overlapped; - gpr_timespec wait_time = gpr_time_sub(deadline, now); - grpc_winsocket *socket; - grpc_winsocket_callback_info *info; - void(*f)(void *, int) = NULL; - void *opaque = NULL; - gpr_mu_unlock(&pollset->mu); - success = GetQueuedCompletionStatus(pollset->iocp, &bytes, - &completion_key, &overlapped, - gpr_time_to_millis(wait_time)); - gpr_mu_lock(&pollset->mu); - if (!success && !overlapped) { - /* The deadline got attained. */ - return 0; - } - GPR_ASSERT(completion_key && overlapped); - if (overlapped == &g_pollset_custom_overlap) { - if (completion_key == (ULONG_PTR) &g_pollset_kick_token) { - /* We were awoken from a kick. */ - gpr_log(GPR_DEBUG, "pollset_poll - got a kick"); - return 1; - } - gpr_log(GPR_ERROR, "Unknown custom completion key."); - abort(); - } - - GPR_ASSERT(pollset == &g_global_pollset); - - socket = (grpc_winsocket*) completion_key; - if (overlapped == &socket->write_info.overlapped) { - gpr_log(GPR_DEBUG, "pollset_poll - got write packet"); - info = &socket->write_info; - } else if (overlapped == &socket->read_info.overlapped) { - gpr_log(GPR_DEBUG, "pollset_poll - got read packet"); - info = &socket->read_info; - } else { - gpr_log(GPR_ERROR, "Unknown IOCP operation"); - abort(); - } - success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, - FALSE, &flags); - gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s", bytes, flags, - success ? "succeeded" : "failed"); - info->bytes_transfered = bytes; - info->wsa_error = success ? 0 : WSAGetLastError(); - GPR_ASSERT(overlapped == &info->overlapped); - gpr_mu_lock(&socket->state_mu); - GPR_ASSERT(!info->has_pending_iocp); - if (info->cb) { - f = info->cb; - opaque = info->opaque; - info->cb = NULL; - } else { - info->has_pending_iocp = 1; - } - gpr_mu_unlock(&socket->state_mu); - if (f) f(opaque, 1); - - return 1; } int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { @@ -149,93 +63,9 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { if (grpc_alarm_check(NULL, now, &deadline)) { return 1; } - return pollset_poll(pollset, deadline, now); + return 0; } -void grpc_pollset_kick(grpc_pollset *pollset) { - BOOL status; - status = PostQueuedCompletionStatus(pollset->iocp, 0, - (ULONG_PTR) &g_pollset_kick_token, - &g_pollset_custom_overlap); - GPR_ASSERT(status); -} - -static void global_poller(void *p) { - while (!gpr_event_get(&g_shutdown_global_poller)) { - gpr_mu_lock(&g_global_pollset.mu); - grpc_pollset_work(&g_global_pollset, gpr_inf_future); - gpr_mu_unlock(&g_global_pollset.mu); - } - - gpr_event_set(&g_global_poller_done, (void *) 1); -} - -void grpc_pollset_global_init(void) { - gpr_thd_id id; - - grpc_pollset_init(&g_global_pollset); - gpr_event_init(&g_global_poller_done); - gpr_event_init(&g_shutdown_global_poller); - gpr_thd_new(&id, global_poller, NULL, NULL); -} - -void grpc_pollset_global_shutdown(void) { - gpr_event_set(&g_shutdown_global_poller, (void *) 1); - grpc_pollset_kick(&g_global_pollset); - gpr_event_wait(&g_global_poller_done, gpr_inf_future); - grpc_pollset_destroy(&g_global_pollset); -} - -void grpc_pollset_add_handle(grpc_pollset *pollset, grpc_winsocket *socket) { - HANDLE ret; - if (socket->added_to_iocp) return; - ret = CreateIoCompletionPort((HANDLE)socket->socket, - g_global_pollset.iocp, - (gpr_uintptr) socket, 0); - if (!ret) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); - gpr_free(utf8_message); - __debugbreak(); - abort(); - } - socket->added_to_iocp = 1; - GPR_ASSERT(ret == g_global_pollset.iocp); -} - -static void handle_notify_on_iocp(grpc_winsocket *socket, - void(*cb)(void *, int), void *opaque, - grpc_winsocket_callback_info *info) { - int run_now = 0; - GPR_ASSERT(!info->cb); - gpr_mu_lock(&socket->state_mu); - if (info->has_pending_iocp) { - run_now = 1; - info->has_pending_iocp = 0; - gpr_log(GPR_DEBUG, "handle_notify_on_iocp - runs now"); - } else { - info->cb = cb; - info->opaque = opaque; - gpr_log(GPR_DEBUG, "handle_notify_on_iocp - queued"); - } - gpr_mu_unlock(&socket->state_mu); - if (run_now) cb(opaque, 1); -} - -void grpc_handle_notify_on_write(grpc_winsocket *socket, - void(*cb)(void *, int), void *opaque) { - gpr_log(GPR_DEBUG, "grpc_handle_notify_on_write"); - handle_notify_on_iocp(socket, cb, opaque, &socket->write_info); -} - -void grpc_handle_notify_on_read(grpc_winsocket *socket, - void(*cb)(void *, int), void *opaque) { - gpr_log(GPR_DEBUG, "grpc_handle_notify_on_read"); - handle_notify_on_iocp(socket, cb, opaque, &socket->read_info); -} - -grpc_pollset *grpc_global_pollset(void) { - return &g_global_pollset; -} +void grpc_pollset_kick(grpc_pollset *p) { } #endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h index 919af5d7b73..1a5e31f627b 100644 --- a/src/core/iomgr/pollset_windows.h +++ b/src/core/iomgr/pollset_windows.h @@ -48,20 +48,9 @@ struct grpc_fd; typedef struct grpc_pollset { gpr_mu mu; gpr_cv cv; - HANDLE iocp; } grpc_pollset; #define GRPC_POLLSET_MU(pollset) (&(pollset)->mu) #define GRPC_POLLSET_CV(pollset) (&(pollset)->cv) -void grpc_pollset_add_handle(grpc_pollset *, grpc_winsocket *); - -grpc_pollset *grpc_global_pollset(void); - -void grpc_handle_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success), - void *opaque); - -void grpc_handle_notify_on_read(grpc_winsocket *, void(*cb)(void *, int success), - void *opaque); - #endif /* __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_ */ diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c index 805e96a0d15..3639798dbcd 100644 --- a/src/core/iomgr/socket_windows.c +++ b/src/core/iomgr/socket_windows.c @@ -37,6 +37,7 @@ #ifdef GPR_WINSOCK_SOCKET +#include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/socket_windows.h" @@ -50,7 +51,7 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket) { r->socket = socket; gpr_mu_init(&r->state_mu); grpc_iomgr_ref(); - grpc_pollset_add_handle(grpc_global_pollset(), r); + grpc_iocp_add_socket(r); return r; } diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c index 37e6b125522..2ed5f39b390 100644 --- a/src/core/iomgr/tcp_client_windows.c +++ b/src/core/iomgr/tcp_client_windows.c @@ -197,7 +197,7 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp), ac->refs = 2; grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now()); - grpc_handle_notify_on_write(socket, on_connect, ac); + grpc_socket_notify_on_write(socket, on_connect, ac); return; failure: diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index 21901958d1c..97f8fe41ea9 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -201,7 +201,7 @@ static void start_accept(server_port *port) { } port->new_socket = sock; - grpc_handle_notify_on_read(port->socket, on_accept, port); + grpc_socket_notify_on_read(port->socket, on_accept, port); return; failure: diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c index bd0b2dd869b..94d84f92b59 100644 --- a/src/core/iomgr/tcp_windows.c +++ b/src/core/iomgr/tcp_windows.c @@ -43,11 +43,12 @@ #include #include -#include "src/core/iomgr/tcp_client.h" -#include "src/core/iomgr/socket_windows.h" #include "src/core/iomgr/alarm.h" +#include "src/core/iomgr/iocp_windows.h" #include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_client.h" static int set_non_block(SOCKET sock) { int status; @@ -121,7 +122,7 @@ static void on_read(void *tcpp, int success) { if (!success) { tcp_unref(tcp); - cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN); + cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); return; } @@ -194,7 +195,7 @@ static void win_notify_on_read(grpc_endpoint *ep, if (status == 0) { gpr_log(GPR_DEBUG, "got response immediately, but we're going to sleep"); - grpc_handle_notify_on_read(tcp->socket, on_read, tcp); + grpc_socket_notify_on_read(tcp->socket, on_read, tcp); return; } @@ -213,7 +214,7 @@ static void win_notify_on_read(grpc_endpoint *ep, } gpr_log(GPR_DEBUG, "waiting on the IO completion port now"); - grpc_handle_notify_on_read(tcp->socket, on_read, tcp); + grpc_socket_notify_on_read(tcp->socket, on_read, tcp); } static void on_write(void *tcpp, int success) { @@ -333,14 +334,14 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep, gpr_log(GPR_DEBUG, "wrote data immediately - but we're going to sleep"); } - grpc_handle_notify_on_write(socket, on_write, tcp); + grpc_socket_notify_on_write(socket, on_write, tcp); return GRPC_ENDPOINT_WRITE_PENDING; } static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { grpc_tcp *tcp = (grpc_tcp *) ep; gpr_log(GPR_DEBUG, "win_add_to_pollset"); - grpc_pollset_add_handle(pollset, tcp->socket); + grpc_iocp_add_socket(tcp->socket); } static void win_shutdown(grpc_endpoint *ep) { diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj index 6d791789e47..9db23091e4f 100644 --- a/vsprojects/vs2013/grpc.vcxproj +++ b/vsprojects/vs2013/grpc.vcxproj @@ -115,10 +115,10 @@ + - @@ -255,6 +255,8 @@ + + diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters index 55f0108a4ba..5059e572bdb 100644 --- a/vsprojects/vs2013/grpc.vcxproj.filters +++ b/vsprojects/vs2013/grpc.vcxproj.filters @@ -112,6 +112,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -443,6 +446,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -452,9 +458,6 @@ src\core\iomgr - - src\core\iomgr - src\core\iomgr diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj index 6d791789e47..9db23091e4f 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj @@ -115,10 +115,10 @@ + - @@ -255,6 +255,8 @@ + + diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters index 23daa46e3d3..29afb528b3d 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters @@ -73,6 +73,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -368,6 +371,9 @@ src\core\iomgr + + src\core\iomgr + src\core\iomgr @@ -377,9 +383,6 @@ src\core\iomgr - - src\core\iomgr - src\core\iomgr From d72ba6a4ffe695a38600719cee96d39c1a307623 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Mon, 9 Feb 2015 16:30:35 -0800 Subject: [PATCH 6/7] Merge cleanup. --- src/core/iomgr/tcp_server_windows.c | 10 ++++++---- src/core/support/log_win32.c | 30 +++++++---------------------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index 97f8fe41ea9..e6161eb1e86 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -38,16 +38,18 @@ #define _GNU_SOURCE #include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/pollset_windows.h" -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/tcp_server.h" -#include "src/core/iomgr/tcp_windows.h" #include #include #include #include #include +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/pollset_windows.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_server.h" +#include "src/core/iomgr/tcp_windows.h" + #define INIT_PORT_CAP 2 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c index 4c0a866048f..840f24f68aa 100644 --- a/src/core/support/log_win32.c +++ b/src/core/support/log_win32.c @@ -35,12 +35,15 @@ #ifdef GPR_WIN32 +#include +#include + +#include #include #include -#include #include -#include -#include + +#include "src/core/support/string_win32.h" void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format, ...) { @@ -93,25 +96,6 @@ void gpr_default_log(gpr_log_func_args *args) { args->file, args->line, args->message); } -/* Arguable, this could become a public function. But hardly - * anything beside the Windows implementation should use - * it, so, never mind...*/ -#if defined UNICODE || defined _UNICODE -static char *tchar_to_char(LPWSTR input) { - char *ret; - int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); - if (needed == 0) return NULL; - ret = gpr_malloc(needed + 1); - WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); - ret[needed] = 0; - return ret; -} -#else -static char *tchar_to_char(LPSTR input) { - return gpr_strdup(input); -} -#endif - char *gpr_format_message(DWORD messageid) { LPTSTR tmessage; char *message; @@ -121,7 +105,7 @@ char *gpr_format_message(DWORD messageid) { NULL, messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)(&tmessage), 0, NULL); - message = tchar_to_char(tmessage); + message = gpr_tchar_to_char(tmessage); LocalFree(tmessage); return message; } From 3d8e34d4096efeee1bf4b43dad9214a1176c250a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 10 Feb 2015 11:05:48 +0100 Subject: [PATCH 7/7] Rewording comment :-) --- src/core/iomgr/socket_windows.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h index 19822ac085c..990b520c6da 100644 --- a/src/core/iomgr/socket_windows.h +++ b/src/core/iomgr/socket_windows.h @@ -40,11 +40,11 @@ #include typedef struct grpc_winsocket_callback_info { - /* I hate Microsoft so much. This is supposed to be a WSAOVERLAPPED, - * but in order to get that definition, we need to include ws2tcpip.h, - * which needs to be included from the top, otherwise it'll clash with - * a previous inclusion of windows.h that in turns includes winsock.h. - * If anyone knows a way to do it properly, feel free to send a patch. + /* This is supposed to be a WSAOVERLAPPED, but in order to get that + * definition, we need to include ws2tcpip.h, which needs to be included + * from the top, otherwise it'll clash with a previous inclusion of + * windows.h that in turns includes winsock.h. If anyone knows a way + * to do it properly, feel free to send a patch. */ OVERLAPPED overlapped; void(*cb)(void *opaque, int success);