blob: 3341f558a3deca18db8d68b4c93c61a437dd4821 [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>
44#include <grpc/support/useful.h>
45
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010046#include "src/core/iomgr/alarm.h"
Nicolas Noble45e67a32015-02-09 16:20:49 -080047#include "src/core/iomgr/iocp_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010048#include "src/core/iomgr/sockaddr.h"
49#include "src/core/iomgr/sockaddr_utils.h"
Nicolas Noble45e67a32015-02-09 16:20:49 -080050#include "src/core/iomgr/socket_windows.h"
51#include "src/core/iomgr/tcp_client.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010052
53static int set_non_block(SOCKET sock) {
54 int status;
55 unsigned long param = 1;
56 DWORD ret;
57 status = WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret,
58 NULL, NULL);
59 return status == 0;
60}
61
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010062static int set_dualstack(SOCKET sock) {
63 int status;
64 unsigned long param = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010065 status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
66 (const char *) &param, sizeof(param));
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010067 return status == 0;
68}
69
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010070int grpc_tcp_prepare_socket(SOCKET sock) {
71 if (!set_non_block(sock))
72 return 0;
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010073 if (!set_dualstack(sock))
74 return 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010075 return 1;
76}
77
78typedef struct grpc_tcp {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020079 /* This is our C++ class derivation emulation. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010080 grpc_endpoint base;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020081 /* The one socket this endpoint is using. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010082 grpc_winsocket *socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020083 /* Refcounting how many operations are in progress. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010084 gpr_refcount refcount;
85
86 grpc_endpoint_read_cb read_cb;
87 void *read_user_data;
88 gpr_slice read_slice;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010089
90 grpc_endpoint_write_cb write_cb;
91 void *write_user_data;
92 gpr_slice_buffer write_slices;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010093
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020094 /* The IO Completion Port runs from another thread. We need some mechanism
95 to protect ourselves when requesting a shutdown. */
96 gpr_mu mu;
97 int shutting_down;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010098} grpc_tcp;
99
100static void tcp_ref(grpc_tcp *tcp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100101 gpr_ref(&tcp->refcount);
102}
103
104static void tcp_unref(grpc_tcp *tcp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100105 if (gpr_unref(&tcp->refcount)) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100106 gpr_slice_buffer_destroy(&tcp->write_slices);
107 grpc_winsocket_orphan(tcp->socket);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200108 gpr_mu_destroy(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100109 gpr_free(tcp);
110 }
111}
112
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200113/* Asynchronous callback from the IOCP, or the background thread. */
114static void on_read(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100115 grpc_tcp *tcp = (grpc_tcp *) tcpp;
116 grpc_winsocket *socket = tcp->socket;
117 gpr_slice sub;
118 gpr_slice *slice = NULL;
119 size_t nslices = 0;
120 grpc_endpoint_cb_status status;
Nicolas Noblee1445362015-05-11 17:40:26 -0700121 grpc_endpoint_read_cb cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100122 grpc_winsocket_callback_info *info = &socket->read_info;
123 void *opaque = tcp->read_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200124 int do_abort = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100125
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200126 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700127 cb = tcp->read_cb;
128 tcp->read_cb = NULL;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200129 if (!from_iocp || tcp->shutting_down) {
130 /* If we are here with from_iocp set to true, it means we got raced to
131 shutting down the endpoint. No actual abort callback will happen
132 though, so we're going to do it from here. */
133 do_abort = 1;
134 }
135 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100136
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200137 if (do_abort) {
Nicolas Noblee1445362015-05-11 17:40:26 -0700138 if (from_iocp) {
139 tcp->socket->read_info.outstanding = 0;
140 gpr_slice_unref(tcp->read_slice);
141 }
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100142 tcp_unref(tcp);
Nicolas Noblee1445362015-05-11 17:40:26 -0700143 if (cb) cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100144 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100145 }
146
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200147 GPR_ASSERT(tcp->socket->read_info.outstanding);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100148
149 if (socket->read_info.wsa_error != 0) {
150 char *utf8_message = gpr_format_message(info->wsa_error);
Jan Tattermusch638c1ee2015-04-21 17:14:44 -0700151 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100152 gpr_free(utf8_message);
153 status = GRPC_ENDPOINT_CB_ERROR;
154 } else {
155 if (info->bytes_transfered != 0) {
156 sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100157 status = GRPC_ENDPOINT_CB_OK;
158 slice = &sub;
159 nslices = 1;
160 } else {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100161 gpr_slice_unref(tcp->read_slice);
162 status = GRPC_ENDPOINT_CB_EOF;
163 }
164 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200165
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200166 tcp->socket->read_info.outstanding = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200167
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100168 tcp_unref(tcp);
169 cb(opaque, slice, nslices, status);
170}
171
172static void win_notify_on_read(grpc_endpoint *ep,
173 grpc_endpoint_read_cb cb, void *arg) {
174 grpc_tcp *tcp = (grpc_tcp *) ep;
175 grpc_winsocket *handle = tcp->socket;
176 grpc_winsocket_callback_info *info = &handle->read_info;
177 int status;
178 DWORD bytes_read = 0;
179 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100180 WSABUF buffer;
181
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200182 GPR_ASSERT(!tcp->socket->read_info.outstanding);
183 if (tcp->shutting_down) {
184 cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
185 return;
186 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100187 tcp_ref(tcp);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200188 tcp->socket->read_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100189 tcp->read_cb = cb;
190 tcp->read_user_data = arg;
191
192 tcp->read_slice = gpr_slice_malloc(8192);
193
194 buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700195 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100196
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200197 /* First let's try a synchronous, non-blocking read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100198 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
199 NULL, NULL);
200 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
201
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200202 /* Did we get data immediately ? Yay. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100203 if (info->wsa_error != WSAEWOULDBLOCK) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100204 info->bytes_transfered = bytes_read;
205 /* This might heavily recurse. */
206 on_read(tcp, 1);
207 return;
208 }
209
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200210 /* Otherwise, let's retry, by queuing a read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100211 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
212 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
213 &info->overlapped, NULL);
214
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200215 if (status != 0) {
216 int wsa_error = WSAGetLastError();
217 if (wsa_error != WSA_IO_PENDING) {
218 info->wsa_error = wsa_error;
219 on_read(tcp, 1);
220 return;
221 }
222 }
223
Nicolas Noble45e67a32015-02-09 16:20:49 -0800224 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100225}
226
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200227/* Asynchronous callback from the IOCP, or the background thread. */
228static void on_write(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100229 grpc_tcp *tcp = (grpc_tcp *) tcpp;
230 grpc_winsocket *handle = tcp->socket;
231 grpc_winsocket_callback_info *info = &handle->write_info;
232 grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
Nicolas Noblee1445362015-05-11 17:40:26 -0700233 grpc_endpoint_write_cb cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100234 void *opaque = tcp->write_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200235 int do_abort = 0;
236
237 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700238 cb = tcp->write_cb;
239 tcp->write_cb = NULL;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200240 if (!from_iocp || tcp->shutting_down) {
241 /* If we are here with from_iocp set to true, it means we got raced to
242 shutting down the endpoint. No actual abort callback will happen
243 though, so we're going to do it from here. */
244 do_abort = 1;
245 }
246 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100247
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200248 if (do_abort) {
Nicolas Noblee1445362015-05-11 17:40:26 -0700249 if (from_iocp) {
250 tcp->socket->write_info.outstanding = 0;
251 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
252 }
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100253 tcp_unref(tcp);
Nicolas Noblee1445362015-05-11 17:40:26 -0700254 if (cb) cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100255 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100256 }
257
Nicolas Noblee1445362015-05-11 17:40:26 -0700258 GPR_ASSERT(tcp->socket->write_info.outstanding);
259
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100260 if (info->wsa_error != 0) {
261 char *utf8_message = gpr_format_message(info->wsa_error);
262 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
263 gpr_free(utf8_message);
264 status = GRPC_ENDPOINT_CB_ERROR;
265 } else {
266 GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
267 }
268
269 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200270 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100271
272 tcp_unref(tcp);
273 cb(opaque, status);
274}
275
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200276/* Initiates a write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100277static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
278 gpr_slice *slices, size_t nslices,
279 grpc_endpoint_write_cb cb,
280 void *arg) {
281 grpc_tcp *tcp = (grpc_tcp *) ep;
282 grpc_winsocket *socket = tcp->socket;
283 grpc_winsocket_callback_info *info = &socket->write_info;
284 unsigned i;
285 DWORD bytes_sent;
286 int status;
287 WSABUF local_buffers[16];
288 WSABUF *allocated = NULL;
289 WSABUF *buffers = local_buffers;
290
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200291 GPR_ASSERT(!tcp->socket->write_info.outstanding);
292 if (tcp->shutting_down) {
293 return GRPC_ENDPOINT_WRITE_ERROR;
294 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100295 tcp_ref(tcp);
296
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200297 tcp->socket->write_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100298 tcp->write_cb = cb;
299 tcp->write_user_data = arg;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200300
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100301 gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
302
303 if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
304 buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
305 allocated = buffers;
306 }
307
308 for (i = 0; i < tcp->write_slices.count; i++) {
309 buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700310 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100311 }
312
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200313 /* First, let's try a synchronous, non-blocking write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100314 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
315 &bytes_sent, 0, NULL, NULL);
316 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
317
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200318 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
319 connection that has its send queue filled up. But if we don't, then we can
320 avoid doing an async write operation at all. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100321 if (info->wsa_error != WSAEWOULDBLOCK) {
322 grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100323 if (status == 0) {
324 ret = GRPC_ENDPOINT_WRITE_DONE;
325 GPR_ASSERT(bytes_sent == tcp->write_slices.length);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100326 } else {
327 char *utf8_message = gpr_format_message(info->wsa_error);
328 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
329 gpr_free(utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100330 }
331 if (allocated) gpr_free(allocated);
332 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200333 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100334 tcp_unref(tcp);
335 return ret;
336 }
337
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200338 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
339 operation, this time asynchronously. */
zeliard3874ad02015-04-30 16:05:45 +0900340 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100341 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
342 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
343 if (allocated) gpr_free(allocated);
344
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200345 if (status != 0) {
346 int wsa_error = WSAGetLastError();
347 if (wsa_error != WSA_IO_PENDING) {
348 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
349 tcp->socket->write_info.outstanding = 0;
350 tcp_unref(tcp);
351 return GRPC_ENDPOINT_WRITE_ERROR;
352 }
353 }
354
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200355 /* As all is now setup, we can now ask for the IOCP notification. It may
356 trigger the callback immediately however, but no matter. */
Nicolas Noble45e67a32015-02-09 16:20:49 -0800357 grpc_socket_notify_on_write(socket, on_write, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100358 return GRPC_ENDPOINT_WRITE_PENDING;
359}
360
361static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
362 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800363 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100364}
365
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200366/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
367 for the potential read and write operations. It is up to the caller to
368 guarantee this isn't called in parallel to a read or write request, so
369 we're not going to protect against these. However the IO Completion Port
370 callback will happen from another thread, so we need to protect against
371 concurrent access of the data structure in that regard. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100372static void win_shutdown(grpc_endpoint *ep) {
373 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noblee1445362015-05-11 17:40:26 -0700374 int extra_refs = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200375 gpr_mu_lock(&tcp->mu);
376 /* At that point, what may happen is that we're already inside the IOCP
377 callback. See the comments in on_read and on_write. */
378 tcp->shutting_down = 1;
Nicolas Noblee1445362015-05-11 17:40:26 -0700379 extra_refs = grpc_winsocket_shutdown(tcp->socket);
380 while (extra_refs--) tcp_ref(tcp);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200381 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100382}
383
384static void win_destroy(grpc_endpoint *ep) {
385 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100386 tcp_unref(tcp);
387}
388
389static grpc_endpoint_vtable vtable = {
390 win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
391};
392
393grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
394 grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
395 memset(tcp, 0, sizeof(grpc_tcp));
396 tcp->base.vtable = &vtable;
397 tcp->socket = socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200398 gpr_mu_init(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100399 gpr_slice_buffer_init(&tcp->write_slices);
400 gpr_ref_init(&tcp->refcount, 1);
401 return &tcp->base;
402}
403
Craig Tiller190d3602015-02-18 09:23:38 -0800404#endif /* GPR_WINSOCK_SOCKET */