blob: c8483bd891cbe73aac0a1faa9e0fe6fe04413b51 [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;
89 int outstanding_read;
90
91 grpc_endpoint_write_cb write_cb;
92 void *write_user_data;
93 gpr_slice_buffer write_slices;
94 int outstanding_write;
95
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020096 /* The IO Completion Port runs from another thread. We need some mechanism
97 to protect ourselves when requesting a shutdown. */
98 gpr_mu mu;
99 int shutting_down;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100100} grpc_tcp;
101
102static void tcp_ref(grpc_tcp *tcp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100103 gpr_ref(&tcp->refcount);
104}
105
106static void tcp_unref(grpc_tcp *tcp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100107 if (gpr_unref(&tcp->refcount)) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100108 gpr_slice_buffer_destroy(&tcp->write_slices);
109 grpc_winsocket_orphan(tcp->socket);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200110 gpr_mu_destroy(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100111 gpr_free(tcp);
112 }
113}
114
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200115/* Asynchronous callback from the IOCP, or the background thread. */
116static void on_read(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100117 grpc_tcp *tcp = (grpc_tcp *) tcpp;
118 grpc_winsocket *socket = tcp->socket;
119 gpr_slice sub;
120 gpr_slice *slice = NULL;
121 size_t nslices = 0;
122 grpc_endpoint_cb_status status;
123 grpc_endpoint_read_cb cb = tcp->read_cb;
124 grpc_winsocket_callback_info *info = &socket->read_info;
125 void *opaque = tcp->read_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200126 int do_abort = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100127
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200128 gpr_mu_lock(&tcp->mu);
129 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) {
138 if (from_iocp) gpr_slice_unref(tcp->read_slice);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100139 tcp_unref(tcp);
Nicolas Noble45e67a32015-02-09 16:20:49 -0800140 cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100141 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100142 }
143
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200144 GPR_ASSERT(tcp->outstanding_read);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100145
146 if (socket->read_info.wsa_error != 0) {
147 char *utf8_message = gpr_format_message(info->wsa_error);
Jan Tattermusch638c1ee2015-04-21 17:14:44 -0700148 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100149 gpr_free(utf8_message);
150 status = GRPC_ENDPOINT_CB_ERROR;
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700151 socket->closed_early = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100152 } else {
153 if (info->bytes_transfered != 0) {
154 sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100155 status = GRPC_ENDPOINT_CB_OK;
156 slice = &sub;
157 nslices = 1;
158 } else {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100159 gpr_slice_unref(tcp->read_slice);
160 status = GRPC_ENDPOINT_CB_EOF;
161 }
162 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200163
164 tcp->outstanding_read = 0;
165
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100166 tcp_unref(tcp);
167 cb(opaque, slice, nslices, status);
168}
169
170static void win_notify_on_read(grpc_endpoint *ep,
171 grpc_endpoint_read_cb cb, void *arg) {
172 grpc_tcp *tcp = (grpc_tcp *) ep;
173 grpc_winsocket *handle = tcp->socket;
174 grpc_winsocket_callback_info *info = &handle->read_info;
175 int status;
176 DWORD bytes_read = 0;
177 DWORD flags = 0;
178 int error;
179 WSABUF buffer;
180
181 GPR_ASSERT(!tcp->outstanding_read);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200182 GPR_ASSERT(!tcp->shutting_down);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100183 tcp_ref(tcp);
184 tcp->outstanding_read = 1;
185 tcp->read_cb = cb;
186 tcp->read_user_data = arg;
187
188 tcp->read_slice = gpr_slice_malloc(8192);
189
190 buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700191 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100192
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200193 /* First let's try a synchronous, non-blocking read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100194 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
195 NULL, NULL);
196 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
197
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200198 /* Did we get data immediately ? Yay. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100199 if (info->wsa_error != WSAEWOULDBLOCK) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100200 info->bytes_transfered = bytes_read;
201 /* This might heavily recurse. */
202 on_read(tcp, 1);
203 return;
204 }
205
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200206 /* Otherwise, let's retry, by queuing a read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100207 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
208 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
209 &info->overlapped, NULL);
210
211 if (status == 0) {
Nicolas Noble45e67a32015-02-09 16:20:49 -0800212 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100213 return;
214 }
215
216 error = WSAGetLastError();
217
218 if (error != WSA_IO_PENDING) {
219 char *utf8_message = gpr_format_message(WSAGetLastError());
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200220 gpr_log(GPR_ERROR, "WSARecv error: %s - this means we're going to leak.",
221 utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100222 gpr_free(utf8_message);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200223 /* I'm pretty sure this is a very bad situation there. Hence the log.
224 What will happen now is that the socket will neither wait for read
225 or write, unless the caller retry, which is unlikely, but I am not
226 sure if that's guaranteed. And there might also be a write pending.
227 This means that the future orphanage of that socket will be in limbo,
228 and we're going to leak it. I have no idea what could cause this
229 specific case however, aside from a parameter error from our call.
230 Normal read errors would actually happen during the overlapped
231 operation, which is the supported way to go for that. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100232 tcp->outstanding_read = 0;
233 tcp_unref(tcp);
234 cb(arg, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200235 /* Per the comment above, I'm going to treat that case as a hard failure
236 for now, and leave the option to catch that and debug. */
237 __debugbreak();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100238 return;
239 }
240
Nicolas Noble45e67a32015-02-09 16:20:49 -0800241 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100242}
243
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200244/* Asynchronous callback from the IOCP, or the background thread. */
245static void on_write(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100246 grpc_tcp *tcp = (grpc_tcp *) tcpp;
247 grpc_winsocket *handle = tcp->socket;
248 grpc_winsocket_callback_info *info = &handle->write_info;
249 grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
250 grpc_endpoint_write_cb cb = tcp->write_cb;
251 void *opaque = tcp->write_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200252 int do_abort = 0;
253
254 gpr_mu_lock(&tcp->mu);
255 if (!from_iocp || tcp->shutting_down) {
256 /* If we are here with from_iocp set to true, it means we got raced to
257 shutting down the endpoint. No actual abort callback will happen
258 though, so we're going to do it from here. */
259 do_abort = 1;
260 }
261 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100262
263 GPR_ASSERT(tcp->outstanding_write);
264
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200265 if (do_abort) {
266 if (from_iocp) gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100267 tcp_unref(tcp);
Nicolas "Pixel" Nobleba410fa2015-02-05 00:54:15 +0100268 cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100269 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100270 }
271
272 if (info->wsa_error != 0) {
273 char *utf8_message = gpr_format_message(info->wsa_error);
274 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
275 gpr_free(utf8_message);
276 status = GRPC_ENDPOINT_CB_ERROR;
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700277 tcp->socket->closed_early = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100278 } else {
279 GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
280 }
281
282 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
283 tcp->outstanding_write = 0;
284
285 tcp_unref(tcp);
286 cb(opaque, status);
287}
288
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200289/* Initiates a write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100290static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
291 gpr_slice *slices, size_t nslices,
292 grpc_endpoint_write_cb cb,
293 void *arg) {
294 grpc_tcp *tcp = (grpc_tcp *) ep;
295 grpc_winsocket *socket = tcp->socket;
296 grpc_winsocket_callback_info *info = &socket->write_info;
297 unsigned i;
298 DWORD bytes_sent;
299 int status;
300 WSABUF local_buffers[16];
301 WSABUF *allocated = NULL;
302 WSABUF *buffers = local_buffers;
303
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100304 GPR_ASSERT(!tcp->outstanding_write);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200305 GPR_ASSERT(!tcp->shutting_down);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100306 tcp_ref(tcp);
307
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100308 tcp->outstanding_write = 1;
309 tcp->write_cb = cb;
310 tcp->write_user_data = arg;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200311
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100312 gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
313
314 if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
315 buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
316 allocated = buffers;
317 }
318
319 for (i = 0; i < tcp->write_slices.count; i++) {
320 buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700321 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100322 }
323
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200324 /* First, let's try a synchronous, non-blocking write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100325 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
326 &bytes_sent, 0, NULL, NULL);
327 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
328
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200329 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
330 connection that has its send queue filled up. But if we don't, then we can
331 avoid doing an async write operation at all. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100332 if (info->wsa_error != WSAEWOULDBLOCK) {
333 grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100334 if (status == 0) {
335 ret = GRPC_ENDPOINT_WRITE_DONE;
336 GPR_ASSERT(bytes_sent == tcp->write_slices.length);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100337 } else {
338 char *utf8_message = gpr_format_message(info->wsa_error);
339 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
340 gpr_free(utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100341 }
342 if (allocated) gpr_free(allocated);
343 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
344 tcp->outstanding_write = 0;
345 tcp_unref(tcp);
346 return ret;
347 }
348
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200349 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
350 operation, this time asynchronously. */
zeliard3874ad02015-04-30 16:05:45 +0900351 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100352 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
353 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
354 if (allocated) gpr_free(allocated);
355
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200356 /* It is possible the operation completed then. But we'd still get an IOCP
357 notification. So let's ignore it and wait for the IOCP. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100358 if (status != 0) {
359 int error = WSAGetLastError();
360 if (error != WSA_IO_PENDING) {
361 char *utf8_message = gpr_format_message(WSAGetLastError());
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200362 gpr_log(GPR_ERROR, "WSASend error: %s - this means we're going to leak.",
363 utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100364 gpr_free(utf8_message);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200365 /* I'm pretty sure this is a very bad situation there. Hence the log.
366 What will happen now is that the socket will neither wait for read
367 or write, unless the caller retry, which is unlikely, but I am not
368 sure if that's guaranteed. And there might also be a read pending.
369 This means that the future orphanage of that socket will be in limbo,
370 and we're going to leak it. I have no idea what could cause this
371 specific case however, aside from a parameter error from our call.
372 Normal read errors would actually happen during the overlapped
373 operation, which is the supported way to go for that. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100374 tcp->outstanding_write = 0;
375 tcp_unref(tcp);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200376 /* Per the comment above, I'm going to treat that case as a hard failure
377 for now, and leave the option to catch that and debug. */
378 __debugbreak();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100379 return GRPC_ENDPOINT_WRITE_ERROR;
380 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100381 }
382
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200383 /* As all is now setup, we can now ask for the IOCP notification. It may
384 trigger the callback immediately however, but no matter. */
Nicolas Noble45e67a32015-02-09 16:20:49 -0800385 grpc_socket_notify_on_write(socket, on_write, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100386 return GRPC_ENDPOINT_WRITE_PENDING;
387}
388
389static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
390 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800391 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100392}
393
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200394/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
395 for the potential read and write operations. It is up to the caller to
396 guarantee this isn't called in parallel to a read or write request, so
397 we're not going to protect against these. However the IO Completion Port
398 callback will happen from another thread, so we need to protect against
399 concurrent access of the data structure in that regard. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100400static void win_shutdown(grpc_endpoint *ep) {
401 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200402 gpr_mu_lock(&tcp->mu);
403 /* At that point, what may happen is that we're already inside the IOCP
404 callback. See the comments in on_read and on_write. */
405 tcp->shutting_down = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100406 grpc_winsocket_shutdown(tcp->socket);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200407 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100408}
409
410static void win_destroy(grpc_endpoint *ep) {
411 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100412 tcp_unref(tcp);
413}
414
415static grpc_endpoint_vtable vtable = {
416 win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
417};
418
419grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
420 grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
421 memset(tcp, 0, sizeof(grpc_tcp));
422 tcp->base.vtable = &vtable;
423 tcp->socket = socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200424 gpr_mu_init(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100425 gpr_slice_buffer_init(&tcp->write_slices);
426 gpr_ref_init(&tcp->refcount, 1);
427 return &tcp->base;
428}
429
Craig Tiller190d3602015-02-18 09:23:38 -0800430#endif /* GPR_WINSOCK_SOCKET */