blob: e9d0cedce558f4c1f0b0586ac9474ba17968f824 [file] [log] [blame]
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
murgatroid9954070892016-08-08 17:01:18 -070034#include "src/core/lib/iomgr/port.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010035
36#ifdef GPR_WINSOCK_SOCKET
37
Craig Tillerf40df232016-03-25 13:38:14 -070038#include <winsock2.h>
Nicolas Noble77ccdb92015-09-03 17:35:26 -070039
Craig Tiller534ce4e2016-03-21 14:41:29 -070040// must be included after winsock2.h
41#include <mswsock.h>
42
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -070043#include <grpc/support/alloc.h>
44#include <grpc/support/log.h>
Yuchen Zeng12dfdc32016-04-26 22:05:41 -070045#include <grpc/support/log_windows.h>
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +020046#include <grpc/support/string_util.h>
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -070047
Craig Tiller9533d042016-03-25 17:11:06 -070048#include "src/core/lib/iomgr/iocp_windows.h"
49#include "src/core/lib/iomgr/iomgr_internal.h"
50#include "src/core/lib/iomgr/pollset.h"
51#include "src/core/lib/iomgr/pollset_windows.h"
52#include "src/core/lib/iomgr/socket_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010053
Craig Tillera82950e2015-09-22 12:33:20 -070054grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) {
Jan Tattermusch7913dea2015-07-09 20:37:17 -070055 char *final_name;
Craig Tillera82950e2015-09-22 12:33:20 -070056 grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket));
57 memset(r, 0, sizeof(grpc_winsocket));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010058 r->socket = socket;
Craig Tillera82950e2015-09-22 12:33:20 -070059 gpr_mu_init(&r->state_mu);
60 gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
61 grpc_iomgr_register_object(&r->iomgr_object, final_name);
62 gpr_free(final_name);
63 grpc_iocp_add_socket(r);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010064 return r;
65}
66
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020067/* Schedule a shutdown of the socket operations. Will call the pending
68 operations to abort them. We need to do that this way because of the
69 various callsites of that function, which happens to be in various
70 mutex hold states, and that'd be unsafe to call them directly. */
Craig Tillera82950e2015-09-22 12:33:20 -070071void grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
Nicolas Noble77ccdb92015-09-03 17:35:26 -070072 /* Grab the function pointer for DisconnectEx for that specific socket.
73 It may change depending on the interface. */
74 int status;
75 GUID guid = WSAID_DISCONNECTEX;
76 LPFN_DISCONNECTEX DisconnectEx;
77 DWORD ioctl_num_bytes;
78
Craig Tillera82950e2015-09-22 12:33:20 -070079 status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
80 &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
81 &ioctl_num_bytes, NULL, NULL);
Nicolas Noble77ccdb92015-09-03 17:35:26 -070082
Craig Tillera82950e2015-09-22 12:33:20 -070083 if (status == 0) {
84 DisconnectEx(winsocket->socket, NULL, 0, 0);
85 } else {
86 char *utf8_message = gpr_format_message(WSAGetLastError());
87 gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s",
88 utf8_message);
89 gpr_free(utf8_message);
90 }
91 closesocket(winsocket->socket);
Nicolas Noble8703f4d2015-03-23 13:52:18 -070092}
93
Craig Tiller5352ff12016-05-18 10:44:38 -070094static void destroy(grpc_winsocket *winsocket) {
Craig Tillera82950e2015-09-22 12:33:20 -070095 grpc_iomgr_unregister_object(&winsocket->iomgr_object);
96 gpr_mu_destroy(&winsocket->state_mu);
97 gpr_free(winsocket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010098}
99
Craig Tiller5352ff12016-05-18 10:44:38 -0700100static bool check_destroyable(grpc_winsocket *winsocket) {
Craig Tiller95b90642016-05-18 12:12:44 -0700101 return winsocket->destroy_called == true &&
102 winsocket->write_info.closure == NULL &&
103 winsocket->read_info.closure == NULL;
Craig Tiller5352ff12016-05-18 10:44:38 -0700104}
105
106void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
107 gpr_mu_lock(&winsocket->state_mu);
108 GPR_ASSERT(!winsocket->destroy_called);
109 winsocket->destroy_called = true;
110 bool should_destroy = check_destroyable(winsocket);
111 gpr_mu_unlock(&winsocket->state_mu);
112 if (should_destroy) destroy(winsocket);
113}
114
115/* Calling notify_on_read or write means either of two things:
116-) The IOCP already completed in the background, and we need to call
117the callback now.
118-) The IOCP hasn't completed yet, and we're queuing it for later. */
119static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx,
120 grpc_winsocket *socket, grpc_closure *closure,
121 grpc_winsocket_callback_info *info) {
122 GPR_ASSERT(info->closure == NULL);
123 gpr_mu_lock(&socket->state_mu);
124 if (info->has_pending_iocp) {
125 info->has_pending_iocp = 0;
Craig Tiller332f1b32016-05-24 13:21:21 -0700126 grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
Craig Tiller5352ff12016-05-18 10:44:38 -0700127 } else {
128 info->closure = closure;
129 }
130 gpr_mu_unlock(&socket->state_mu);
131}
132
133void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
134 grpc_winsocket *socket,
135 grpc_closure *closure) {
136 socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info);
137}
138
139void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
140 grpc_closure *closure) {
141 socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info);
142}
143
Craig Tiller95b90642016-05-18 12:12:44 -0700144void grpc_socket_become_ready(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
145 grpc_winsocket_callback_info *info) {
Craig Tiller5352ff12016-05-18 10:44:38 -0700146 GPR_ASSERT(!info->has_pending_iocp);
147 gpr_mu_lock(&socket->state_mu);
148 if (info->closure) {
Craig Tiller332f1b32016-05-24 13:21:21 -0700149 grpc_exec_ctx_sched(exec_ctx, info->closure, GRPC_ERROR_NONE, NULL);
Craig Tiller5352ff12016-05-18 10:44:38 -0700150 info->closure = NULL;
151 } else {
152 info->has_pending_iocp = 1;
153 }
154 bool should_destroy = check_destroyable(socket);
155 gpr_mu_unlock(&socket->state_mu);
156 if (should_destroy) destroy(socket);
157}
158
Craig Tillerd6c98df2015-08-18 09:33:44 -0700159#endif /* GPR_WINSOCK_SOCKET */