blob: 12dac030803294e1736612a0a0a5431dbba7ea96 [file] [log] [blame]
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * 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
34#include <grpc/support/port_platform.h>
35
36#ifdef GPR_WINSOCK_SOCKET
37
38#include "src/core/iomgr/sockaddr_win32.h"
39
40#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42#include <grpc/support/log_win32.h>
43#include <grpc/support/slice_buffer.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070044#include <grpc/support/string_util.h>
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010045#include <grpc/support/useful.h>
46
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010047#include "src/core/iomgr/alarm.h"
Nicolas Noble45e67a32015-02-09 16:20:49 -080048#include "src/core/iomgr/iocp_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010049#include "src/core/iomgr/sockaddr.h"
50#include "src/core/iomgr/sockaddr_utils.h"
Nicolas Noble45e67a32015-02-09 16:20:49 -080051#include "src/core/iomgr/socket_windows.h"
52#include "src/core/iomgr/tcp_client.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010053
54static int set_non_block(SOCKET sock) {
55 int status;
56 unsigned long param = 1;
57 DWORD ret;
58 status = WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret,
59 NULL, NULL);
60 return status == 0;
61}
62
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010063static int set_dualstack(SOCKET sock) {
64 int status;
65 unsigned long param = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010066 status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
67 (const char *) &param, sizeof(param));
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010068 return status == 0;
69}
70
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010071int grpc_tcp_prepare_socket(SOCKET sock) {
72 if (!set_non_block(sock))
73 return 0;
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010074 if (!set_dualstack(sock))
75 return 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010076 return 1;
77}
78
79typedef struct grpc_tcp {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020080 /* This is our C++ class derivation emulation. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010081 grpc_endpoint base;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020082 /* The one socket this endpoint is using. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010083 grpc_winsocket *socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020084 /* Refcounting how many operations are in progress. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010085 gpr_refcount refcount;
86
87 grpc_endpoint_read_cb read_cb;
88 void *read_user_data;
89 gpr_slice read_slice;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010090
91 grpc_endpoint_write_cb write_cb;
92 void *write_user_data;
93 gpr_slice_buffer write_slices;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010094
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020095 /* The IO Completion Port runs from another thread. We need some mechanism
96 to protect ourselves when requesting a shutdown. */
97 gpr_mu mu;
98 int shutting_down;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010099} grpc_tcp;
100
101static void tcp_ref(grpc_tcp *tcp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100102 gpr_ref(&tcp->refcount);
103}
104
105static void tcp_unref(grpc_tcp *tcp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100106 if (gpr_unref(&tcp->refcount)) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100107 gpr_slice_buffer_destroy(&tcp->write_slices);
108 grpc_winsocket_orphan(tcp->socket);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200109 gpr_mu_destroy(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100110 gpr_free(tcp);
111 }
112}
113
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200114/* Asynchronous callback from the IOCP, or the background thread. */
115static void on_read(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100116 grpc_tcp *tcp = (grpc_tcp *) tcpp;
117 grpc_winsocket *socket = tcp->socket;
118 gpr_slice sub;
119 gpr_slice *slice = NULL;
120 size_t nslices = 0;
121 grpc_endpoint_cb_status status;
Nicolas Noblee1445362015-05-11 17:40:26 -0700122 grpc_endpoint_read_cb cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100123 grpc_winsocket_callback_info *info = &socket->read_info;
124 void *opaque = tcp->read_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200125 int do_abort = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100126
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200127 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700128 cb = tcp->read_cb;
129 tcp->read_cb = NULL;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200130 if (!from_iocp || tcp->shutting_down) {
131 /* If we are here with from_iocp set to true, it means we got raced to
132 shutting down the endpoint. No actual abort callback will happen
133 though, so we're going to do it from here. */
134 do_abort = 1;
135 }
136 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100137
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200138 if (do_abort) {
Nicolas Noblee1445362015-05-11 17:40:26 -0700139 if (from_iocp) {
140 tcp->socket->read_info.outstanding = 0;
141 gpr_slice_unref(tcp->read_slice);
142 }
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100143 tcp_unref(tcp);
Nicolas Noblee1445362015-05-11 17:40:26 -0700144 if (cb) cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100145 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100146 }
147
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200148 GPR_ASSERT(tcp->socket->read_info.outstanding);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100149
150 if (socket->read_info.wsa_error != 0) {
151 char *utf8_message = gpr_format_message(info->wsa_error);
Jan Tattermusch638c1ee2015-04-21 17:14:44 -0700152 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100153 gpr_free(utf8_message);
154 status = GRPC_ENDPOINT_CB_ERROR;
155 } else {
156 if (info->bytes_transfered != 0) {
157 sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100158 status = GRPC_ENDPOINT_CB_OK;
159 slice = &sub;
160 nslices = 1;
161 } else {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100162 gpr_slice_unref(tcp->read_slice);
163 status = GRPC_ENDPOINT_CB_EOF;
164 }
165 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200166
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200167 tcp->socket->read_info.outstanding = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200168
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100169 tcp_unref(tcp);
170 cb(opaque, slice, nslices, status);
171}
172
173static void win_notify_on_read(grpc_endpoint *ep,
174 grpc_endpoint_read_cb cb, void *arg) {
175 grpc_tcp *tcp = (grpc_tcp *) ep;
176 grpc_winsocket *handle = tcp->socket;
177 grpc_winsocket_callback_info *info = &handle->read_info;
178 int status;
179 DWORD bytes_read = 0;
180 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100181 WSABUF buffer;
182
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200183 GPR_ASSERT(!tcp->socket->read_info.outstanding);
184 if (tcp->shutting_down) {
185 cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
186 return;
187 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100188 tcp_ref(tcp);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200189 tcp->socket->read_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100190 tcp->read_cb = cb;
191 tcp->read_user_data = arg;
192
193 tcp->read_slice = gpr_slice_malloc(8192);
194
195 buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700196 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100197
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200198 /* First let's try a synchronous, non-blocking read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100199 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
200 NULL, NULL);
201 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
202
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200203 /* Did we get data immediately ? Yay. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100204 if (info->wsa_error != WSAEWOULDBLOCK) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100205 info->bytes_transfered = bytes_read;
206 /* This might heavily recurse. */
207 on_read(tcp, 1);
208 return;
209 }
210
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200211 /* Otherwise, let's retry, by queuing a read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100212 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
213 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
214 &info->overlapped, NULL);
215
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200216 if (status != 0) {
217 int wsa_error = WSAGetLastError();
218 if (wsa_error != WSA_IO_PENDING) {
219 info->wsa_error = wsa_error;
220 on_read(tcp, 1);
221 return;
222 }
223 }
224
Nicolas Noble45e67a32015-02-09 16:20:49 -0800225 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100226}
227
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200228/* Asynchronous callback from the IOCP, or the background thread. */
229static void on_write(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100230 grpc_tcp *tcp = (grpc_tcp *) tcpp;
231 grpc_winsocket *handle = tcp->socket;
232 grpc_winsocket_callback_info *info = &handle->write_info;
233 grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
Nicolas Noblee1445362015-05-11 17:40:26 -0700234 grpc_endpoint_write_cb cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100235 void *opaque = tcp->write_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200236 int do_abort = 0;
237
238 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700239 cb = tcp->write_cb;
240 tcp->write_cb = NULL;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200241 if (!from_iocp || tcp->shutting_down) {
242 /* If we are here with from_iocp set to true, it means we got raced to
243 shutting down the endpoint. No actual abort callback will happen
244 though, so we're going to do it from here. */
245 do_abort = 1;
246 }
247 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100248
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200249 if (do_abort) {
Nicolas Noblee1445362015-05-11 17:40:26 -0700250 if (from_iocp) {
251 tcp->socket->write_info.outstanding = 0;
252 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
253 }
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100254 tcp_unref(tcp);
Nicolas Noblee1445362015-05-11 17:40:26 -0700255 if (cb) cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100256 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100257 }
258
Nicolas Noblee1445362015-05-11 17:40:26 -0700259 GPR_ASSERT(tcp->socket->write_info.outstanding);
260
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100261 if (info->wsa_error != 0) {
262 char *utf8_message = gpr_format_message(info->wsa_error);
263 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
264 gpr_free(utf8_message);
265 status = GRPC_ENDPOINT_CB_ERROR;
266 } else {
267 GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
268 }
269
270 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200271 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100272
273 tcp_unref(tcp);
274 cb(opaque, status);
275}
276
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200277/* Initiates a write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100278static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
279 gpr_slice *slices, size_t nslices,
280 grpc_endpoint_write_cb cb,
281 void *arg) {
282 grpc_tcp *tcp = (grpc_tcp *) ep;
283 grpc_winsocket *socket = tcp->socket;
284 grpc_winsocket_callback_info *info = &socket->write_info;
285 unsigned i;
286 DWORD bytes_sent;
287 int status;
288 WSABUF local_buffers[16];
289 WSABUF *allocated = NULL;
290 WSABUF *buffers = local_buffers;
291
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200292 GPR_ASSERT(!tcp->socket->write_info.outstanding);
293 if (tcp->shutting_down) {
294 return GRPC_ENDPOINT_WRITE_ERROR;
295 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100296 tcp_ref(tcp);
297
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200298 tcp->socket->write_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100299 tcp->write_cb = cb;
300 tcp->write_user_data = arg;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200301
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100302 gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
303
304 if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
305 buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
306 allocated = buffers;
307 }
308
309 for (i = 0; i < tcp->write_slices.count; i++) {
310 buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700311 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100312 }
313
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200314 /* First, let's try a synchronous, non-blocking write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100315 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
316 &bytes_sent, 0, NULL, NULL);
317 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
318
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200319 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
320 connection that has its send queue filled up. But if we don't, then we can
321 avoid doing an async write operation at all. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100322 if (info->wsa_error != WSAEWOULDBLOCK) {
323 grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100324 if (status == 0) {
325 ret = GRPC_ENDPOINT_WRITE_DONE;
326 GPR_ASSERT(bytes_sent == tcp->write_slices.length);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100327 } else {
328 char *utf8_message = gpr_format_message(info->wsa_error);
329 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
330 gpr_free(utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100331 }
332 if (allocated) gpr_free(allocated);
333 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200334 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100335 tcp_unref(tcp);
336 return ret;
337 }
338
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200339 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
340 operation, this time asynchronously. */
zeliard3874ad02015-04-30 16:05:45 +0900341 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100342 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
343 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
344 if (allocated) gpr_free(allocated);
345
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200346 if (status != 0) {
347 int wsa_error = WSAGetLastError();
348 if (wsa_error != WSA_IO_PENDING) {
349 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
350 tcp->socket->write_info.outstanding = 0;
351 tcp_unref(tcp);
352 return GRPC_ENDPOINT_WRITE_ERROR;
353 }
354 }
355
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200356 /* As all is now setup, we can now ask for the IOCP notification. It may
357 trigger the callback immediately however, but no matter. */
Nicolas Noble45e67a32015-02-09 16:20:49 -0800358 grpc_socket_notify_on_write(socket, on_write, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100359 return GRPC_ENDPOINT_WRITE_PENDING;
360}
361
362static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
363 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800364 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100365}
366
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200367/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
368 for the potential read and write operations. It is up to the caller to
369 guarantee this isn't called in parallel to a read or write request, so
370 we're not going to protect against these. However the IO Completion Port
371 callback will happen from another thread, so we need to protect against
372 concurrent access of the data structure in that regard. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100373static void win_shutdown(grpc_endpoint *ep) {
374 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noblee1445362015-05-11 17:40:26 -0700375 int extra_refs = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200376 gpr_mu_lock(&tcp->mu);
377 /* At that point, what may happen is that we're already inside the IOCP
378 callback. See the comments in on_read and on_write. */
379 tcp->shutting_down = 1;
Nicolas Noblee1445362015-05-11 17:40:26 -0700380 extra_refs = grpc_winsocket_shutdown(tcp->socket);
381 while (extra_refs--) tcp_ref(tcp);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200382 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100383}
384
385static void win_destroy(grpc_endpoint *ep) {
386 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100387 tcp_unref(tcp);
388}
389
390static grpc_endpoint_vtable vtable = {
391 win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
392};
393
394grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
395 grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
396 memset(tcp, 0, sizeof(grpc_tcp));
397 tcp->base.vtable = &vtable;
398 tcp->socket = socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200399 gpr_mu_init(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100400 gpr_slice_buffer_init(&tcp->write_slices);
401 gpr_ref_init(&tcp->refcount, 1);
402 return &tcp->base;
403}
404
Craig Tiller190d3602015-02-18 09:23:38 -0800405#endif /* GPR_WINSOCK_SOCKET */