blob: 1bf81a73e0c801adaa1044567645dc943ceebeb9 [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) {
Jan Tattermuschd9e79432015-07-12 01:27:30 -0700151 if (socket->read_info.wsa_error != WSAECONNRESET) {
152 char *utf8_message = gpr_format_message(info->wsa_error);
153 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
154 gpr_free(utf8_message);
155 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100156 status = GRPC_ENDPOINT_CB_ERROR;
157 } else {
158 if (info->bytes_transfered != 0) {
Jan Tattermuschb9100952015-06-18 11:35:53 -0700159 sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100160 status = GRPC_ENDPOINT_CB_OK;
161 slice = &sub;
162 nslices = 1;
163 } else {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100164 gpr_slice_unref(tcp->read_slice);
165 status = GRPC_ENDPOINT_CB_EOF;
166 }
167 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200168
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200169 tcp->socket->read_info.outstanding = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200170
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100171 tcp_unref(tcp);
172 cb(opaque, slice, nslices, status);
173}
174
175static void win_notify_on_read(grpc_endpoint *ep,
176 grpc_endpoint_read_cb cb, void *arg) {
177 grpc_tcp *tcp = (grpc_tcp *) ep;
178 grpc_winsocket *handle = tcp->socket;
179 grpc_winsocket_callback_info *info = &handle->read_info;
180 int status;
181 DWORD bytes_read = 0;
182 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100183 WSABUF buffer;
184
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200185 GPR_ASSERT(!tcp->socket->read_info.outstanding);
186 if (tcp->shutting_down) {
187 cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
188 return;
189 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100190 tcp_ref(tcp);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200191 tcp->socket->read_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100192 tcp->read_cb = cb;
193 tcp->read_user_data = arg;
194
195 tcp->read_slice = gpr_slice_malloc(8192);
196
197 buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700198 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100199
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200200 /* First let's try a synchronous, non-blocking read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100201 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
202 NULL, NULL);
203 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
204
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200205 /* Did we get data immediately ? Yay. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100206 if (info->wsa_error != WSAEWOULDBLOCK) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100207 info->bytes_transfered = bytes_read;
208 /* This might heavily recurse. */
209 on_read(tcp, 1);
210 return;
211 }
212
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200213 /* Otherwise, let's retry, by queuing a read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100214 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
215 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
216 &info->overlapped, NULL);
217
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200218 if (status != 0) {
219 int wsa_error = WSAGetLastError();
220 if (wsa_error != WSA_IO_PENDING) {
221 info->wsa_error = wsa_error;
222 on_read(tcp, 1);
223 return;
224 }
225 }
226
Nicolas Noble45e67a32015-02-09 16:20:49 -0800227 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100228}
229
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200230/* Asynchronous callback from the IOCP, or the background thread. */
231static void on_write(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100232 grpc_tcp *tcp = (grpc_tcp *) tcpp;
233 grpc_winsocket *handle = tcp->socket;
234 grpc_winsocket_callback_info *info = &handle->write_info;
235 grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
Nicolas Noblee1445362015-05-11 17:40:26 -0700236 grpc_endpoint_write_cb cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100237 void *opaque = tcp->write_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200238 int do_abort = 0;
239
240 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700241 cb = tcp->write_cb;
242 tcp->write_cb = NULL;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200243 if (!from_iocp || tcp->shutting_down) {
244 /* If we are here with from_iocp set to true, it means we got raced to
245 shutting down the endpoint. No actual abort callback will happen
246 though, so we're going to do it from here. */
247 do_abort = 1;
248 }
249 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100250
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200251 if (do_abort) {
Nicolas Noblee1445362015-05-11 17:40:26 -0700252 if (from_iocp) {
253 tcp->socket->write_info.outstanding = 0;
254 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
255 }
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100256 tcp_unref(tcp);
Nicolas Noblee1445362015-05-11 17:40:26 -0700257 if (cb) cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100258 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100259 }
260
Nicolas Noblee1445362015-05-11 17:40:26 -0700261 GPR_ASSERT(tcp->socket->write_info.outstanding);
262
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100263 if (info->wsa_error != 0) {
Jan Tattermuschd9e79432015-07-12 01:27:30 -0700264 if (info->wsa_error != WSAECONNRESET) {
265 char *utf8_message = gpr_format_message(info->wsa_error);
266 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
267 gpr_free(utf8_message);
268 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100269 status = GRPC_ENDPOINT_CB_ERROR;
270 } else {
271 GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
272 }
273
274 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200275 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100276
277 tcp_unref(tcp);
278 cb(opaque, status);
279}
280
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200281/* Initiates a write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100282static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
283 gpr_slice *slices, size_t nslices,
284 grpc_endpoint_write_cb cb,
285 void *arg) {
286 grpc_tcp *tcp = (grpc_tcp *) ep;
287 grpc_winsocket *socket = tcp->socket;
288 grpc_winsocket_callback_info *info = &socket->write_info;
289 unsigned i;
290 DWORD bytes_sent;
291 int status;
292 WSABUF local_buffers[16];
293 WSABUF *allocated = NULL;
294 WSABUF *buffers = local_buffers;
295
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200296 GPR_ASSERT(!tcp->socket->write_info.outstanding);
297 if (tcp->shutting_down) {
298 return GRPC_ENDPOINT_WRITE_ERROR;
299 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100300 tcp_ref(tcp);
301
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200302 tcp->socket->write_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100303 tcp->write_cb = cb;
304 tcp->write_user_data = arg;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200305
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100306 gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
307
308 if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
309 buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
310 allocated = buffers;
311 }
312
313 for (i = 0; i < tcp->write_slices.count; i++) {
314 buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700315 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100316 }
317
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200318 /* First, let's try a synchronous, non-blocking write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100319 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
320 &bytes_sent, 0, NULL, NULL);
321 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
322
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200323 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
324 connection that has its send queue filled up. But if we don't, then we can
325 avoid doing an async write operation at all. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100326 if (info->wsa_error != WSAEWOULDBLOCK) {
327 grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100328 if (status == 0) {
329 ret = GRPC_ENDPOINT_WRITE_DONE;
330 GPR_ASSERT(bytes_sent == tcp->write_slices.length);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100331 } else {
Jan Tattermuschd9e79432015-07-12 01:27:30 -0700332 if (socket->read_info.wsa_error != WSAECONNRESET) {
333 char *utf8_message = gpr_format_message(info->wsa_error);
334 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
335 gpr_free(utf8_message);
336 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100337 }
338 if (allocated) gpr_free(allocated);
339 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200340 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100341 tcp_unref(tcp);
342 return ret;
343 }
344
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200345 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
346 operation, this time asynchronously. */
zeliard3874ad02015-04-30 16:05:45 +0900347 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100348 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
349 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
350 if (allocated) gpr_free(allocated);
351
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200352 if (status != 0) {
353 int wsa_error = WSAGetLastError();
354 if (wsa_error != WSA_IO_PENDING) {
355 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
356 tcp->socket->write_info.outstanding = 0;
357 tcp_unref(tcp);
358 return GRPC_ENDPOINT_WRITE_ERROR;
359 }
360 }
361
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200362 /* As all is now setup, we can now ask for the IOCP notification. It may
363 trigger the callback immediately however, but no matter. */
Nicolas Noble45e67a32015-02-09 16:20:49 -0800364 grpc_socket_notify_on_write(socket, on_write, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100365 return GRPC_ENDPOINT_WRITE_PENDING;
366}
367
368static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
369 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800370 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100371}
372
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200373/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
374 for the potential read and write operations. It is up to the caller to
375 guarantee this isn't called in parallel to a read or write request, so
376 we're not going to protect against these. However the IO Completion Port
377 callback will happen from another thread, so we need to protect against
378 concurrent access of the data structure in that regard. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100379static void win_shutdown(grpc_endpoint *ep) {
380 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noblee1445362015-05-11 17:40:26 -0700381 int extra_refs = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200382 gpr_mu_lock(&tcp->mu);
383 /* At that point, what may happen is that we're already inside the IOCP
384 callback. See the comments in on_read and on_write. */
385 tcp->shutting_down = 1;
Nicolas Noblee1445362015-05-11 17:40:26 -0700386 extra_refs = grpc_winsocket_shutdown(tcp->socket);
387 while (extra_refs--) tcp_ref(tcp);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200388 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100389}
390
391static void win_destroy(grpc_endpoint *ep) {
392 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100393 tcp_unref(tcp);
394}
395
396static grpc_endpoint_vtable vtable = {
397 win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
398};
399
400grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
401 grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
402 memset(tcp, 0, sizeof(grpc_tcp));
403 tcp->base.vtable = &vtable;
404 tcp->socket = socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200405 gpr_mu_init(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100406 gpr_slice_buffer_init(&tcp->write_slices);
407 gpr_ref_init(&tcp->refcount, 1);
408 return &tcp->base;
409}
410
Craig Tiller190d3602015-02-18 09:23:38 -0800411#endif /* GPR_WINSOCK_SOCKET */