mirror of https://github.com/grpc/grpc.git
commit
187994e0fd
28 changed files with 1788 additions and 31 deletions
@ -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 <windows.h> |
||||
|
||||
#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 conjunction with GetLastError() et al. |
||||
*/ |
||||
char *gpr_format_message(DWORD messageid); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* __GRPC_SUPPORT_LOG_H__ */ |
@ -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 <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINSOCK_SOCKET |
||||
|
||||
#include <winsock2.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/log_win32.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/thd.h> |
||||
|
||||
#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 */ |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* 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_IOCP_WINDOWS_H_ |
||||
#define __GRPC_INTERNAL_IOMGR_IOCP_WINDOWS_H_ |
||||
|
||||
#include <windows.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include "src/core/iomgr/socket_windows.h" |
||||
|
||||
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_IOCP_WINDOWS_H_ */ |
@ -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 <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINSOCK_SOCKET |
||||
|
||||
#include "src/core/iomgr/sockaddr_win32.h" |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/iomgr/socket_windows.h" |
||||
#include "src/core/iomgr/iocp_windows.h" |
||||
#include "src/core/iomgr/iomgr.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_iocp_init(); |
||||
} |
||||
|
||||
void grpc_iomgr_platform_shutdown(void) { |
||||
grpc_iocp_shutdown(); |
||||
winsock_shutdown(); |
||||
} |
||||
|
||||
#endif /* GRPC_WINSOCK_SOCKET */ |
@ -0,0 +1,77 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpc/support/port_platform.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#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" |
||||
#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_iocp_add_socket(r); |
||||
return r; |
||||
} |
||||
|
||||
void shutdown_op(grpc_winsocket_callback_info *info) { |
||||
if (!info->cb) return; |
||||
grpc_iomgr_add_delayed_callback(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 /* GPR_WINSOCK_SOCKET */ |
@ -0,0 +1,75 @@ |
||||
/*
|
||||
* |
||||
* 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 <windows.h> |
||||
|
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/atm.h> |
||||
|
||||
typedef struct grpc_winsocket_callback_info { |
||||
/* 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; |
||||
|
||||
int added_to_iocp; |
||||
|
||||
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_HANDLE_WINDOWS_H__ */ |
@ -0,0 +1,215 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINSOCK_SOCKET |
||||
|
||||
#include "src/core/iomgr/sockaddr_win32.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/log_win32.h> |
||||
#include <grpc/support/slice_buffer.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
#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 { |
||||
gpr_log(GPR_ERROR, "on_connect is shutting down"); |
||||
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; |
||||
} |
||||
|
||||
grpc_sockaddr_make_wildcard6(0, &local_address); |
||||
|
||||
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_socket_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 */ |
@ -0,0 +1,374 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINSOCK_SOCKET |
||||
|
||||
#define _GNU_SOURCE |
||||
#include "src/core/iomgr/sockaddr_utils.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/log_win32.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
#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 |
||||
|
||||
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_socket_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 */ |
@ -0,0 +1,373 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WINSOCK_SOCKET |
||||
|
||||
#include "src/core/iomgr/sockaddr_win32.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/log_win32.h> |
||||
#include <grpc/support/slice_buffer.h> |
||||
#include <grpc/support/useful.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; |
||||
unsigned long param = 1; |
||||
DWORD ret; |
||||
status = WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, |
||||
NULL, NULL); |
||||
return status == 0; |
||||
} |
||||
|
||||
static int set_dualstack(SOCKET sock) { |
||||
int status; |
||||
unsigned long param = 0; |
||||
status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, |
||||
(const char *) ¶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; |
||||
} |
||||
|
||||
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) { |
||||
tcp_unref(tcp); |
||||
cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); |
||||
return; |
||||
} |
||||
|
||||
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 going to sleep"); |
||||
grpc_socket_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_socket_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) { |
||||
tcp_unref(tcp); |
||||
cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN); |
||||
return; |
||||
} |
||||
|
||||
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); |
||||
} 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); |
||||
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_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_iocp_add_socket(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 */ |
@ -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__ */ |
Loading…
Reference in new issue