blob: f16b4c1268817ffd45e0841581006d97973ed9c0 [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;
121 grpc_endpoint_read_cb cb = tcp->read_cb;
122 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);
127 if (!from_iocp || tcp->shutting_down) {
128 /* If we are here with from_iocp set to true, it means we got raced to
129 shutting down the endpoint. No actual abort callback will happen
130 though, so we're going to do it from here. */
131 do_abort = 1;
132 }
133 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100134
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200135 if (do_abort) {
136 if (from_iocp) gpr_slice_unref(tcp->read_slice);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100137 tcp_unref(tcp);
Nicolas Noble45e67a32015-02-09 16:20:49 -0800138 cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100139 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100140 }
141
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200142 GPR_ASSERT(tcp->socket->read_info.outstanding);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100143
144 if (socket->read_info.wsa_error != 0) {
145 char *utf8_message = gpr_format_message(info->wsa_error);
Jan Tattermusch638c1ee2015-04-21 17:14:44 -0700146 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100147 gpr_free(utf8_message);
148 status = GRPC_ENDPOINT_CB_ERROR;
149 } else {
150 if (info->bytes_transfered != 0) {
151 sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100152 status = GRPC_ENDPOINT_CB_OK;
153 slice = &sub;
154 nslices = 1;
155 } else {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100156 gpr_slice_unref(tcp->read_slice);
157 status = GRPC_ENDPOINT_CB_EOF;
158 }
159 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200160
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200161 tcp->socket->read_info.outstanding = 0;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200162
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100163 tcp_unref(tcp);
164 cb(opaque, slice, nslices, status);
165}
166
167static void win_notify_on_read(grpc_endpoint *ep,
168 grpc_endpoint_read_cb cb, void *arg) {
169 grpc_tcp *tcp = (grpc_tcp *) ep;
170 grpc_winsocket *handle = tcp->socket;
171 grpc_winsocket_callback_info *info = &handle->read_info;
172 int status;
173 DWORD bytes_read = 0;
174 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100175 WSABUF buffer;
176
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200177 GPR_ASSERT(!tcp->socket->read_info.outstanding);
178 if (tcp->shutting_down) {
179 cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
180 return;
181 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100182 tcp_ref(tcp);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200183 tcp->socket->read_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100184 tcp->read_cb = cb;
185 tcp->read_user_data = arg;
186
187 tcp->read_slice = gpr_slice_malloc(8192);
188
189 buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700190 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100191
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200192 /* First let's try a synchronous, non-blocking read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100193 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
194 NULL, NULL);
195 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
196
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200197 /* Did we get data immediately ? Yay. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100198 if (info->wsa_error != WSAEWOULDBLOCK) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100199 info->bytes_transfered = bytes_read;
200 /* This might heavily recurse. */
201 on_read(tcp, 1);
202 return;
203 }
204
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200205 /* Otherwise, let's retry, by queuing a read. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100206 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
207 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
208 &info->overlapped, NULL);
209
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200210 if (status != 0) {
211 int wsa_error = WSAGetLastError();
212 if (wsa_error != WSA_IO_PENDING) {
213 info->wsa_error = wsa_error;
214 on_read(tcp, 1);
215 return;
216 }
217 }
218
Nicolas Noble45e67a32015-02-09 16:20:49 -0800219 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100220}
221
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200222/* Asynchronous callback from the IOCP, or the background thread. */
223static void on_write(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100224 grpc_tcp *tcp = (grpc_tcp *) tcpp;
225 grpc_winsocket *handle = tcp->socket;
226 grpc_winsocket_callback_info *info = &handle->write_info;
227 grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
228 grpc_endpoint_write_cb cb = tcp->write_cb;
229 void *opaque = tcp->write_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200230 int do_abort = 0;
231
232 gpr_mu_lock(&tcp->mu);
233 if (!from_iocp || tcp->shutting_down) {
234 /* If we are here with from_iocp set to true, it means we got raced to
235 shutting down the endpoint. No actual abort callback will happen
236 though, so we're going to do it from here. */
237 do_abort = 1;
238 }
239 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100240
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200241 GPR_ASSERT(tcp->socket->write_info.outstanding);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100242
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200243 if (do_abort) {
244 if (from_iocp) gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100245 tcp_unref(tcp);
Nicolas "Pixel" Nobleba410fa2015-02-05 00:54:15 +0100246 cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100247 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100248 }
249
250 if (info->wsa_error != 0) {
251 char *utf8_message = gpr_format_message(info->wsa_error);
252 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
253 gpr_free(utf8_message);
254 status = GRPC_ENDPOINT_CB_ERROR;
255 } else {
256 GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
257 }
258
259 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200260 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100261
262 tcp_unref(tcp);
263 cb(opaque, status);
264}
265
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200266/* Initiates a write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100267static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
268 gpr_slice *slices, size_t nslices,
269 grpc_endpoint_write_cb cb,
270 void *arg) {
271 grpc_tcp *tcp = (grpc_tcp *) ep;
272 grpc_winsocket *socket = tcp->socket;
273 grpc_winsocket_callback_info *info = &socket->write_info;
274 unsigned i;
275 DWORD bytes_sent;
276 int status;
277 WSABUF local_buffers[16];
278 WSABUF *allocated = NULL;
279 WSABUF *buffers = local_buffers;
280
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200281 GPR_ASSERT(!tcp->socket->write_info.outstanding);
282 if (tcp->shutting_down) {
283 return GRPC_ENDPOINT_WRITE_ERROR;
284 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100285 tcp_ref(tcp);
286
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200287 tcp->socket->write_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100288 tcp->write_cb = cb;
289 tcp->write_user_data = arg;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200290
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100291 gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
292
293 if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
294 buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
295 allocated = buffers;
296 }
297
298 for (i = 0; i < tcp->write_slices.count; i++) {
299 buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700300 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100301 }
302
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200303 /* First, let's try a synchronous, non-blocking write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100304 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
305 &bytes_sent, 0, NULL, NULL);
306 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
307
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200308 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
309 connection that has its send queue filled up. But if we don't, then we can
310 avoid doing an async write operation at all. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100311 if (info->wsa_error != WSAEWOULDBLOCK) {
312 grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100313 if (status == 0) {
314 ret = GRPC_ENDPOINT_WRITE_DONE;
315 GPR_ASSERT(bytes_sent == tcp->write_slices.length);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100316 } else {
317 char *utf8_message = gpr_format_message(info->wsa_error);
318 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
319 gpr_free(utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100320 }
321 if (allocated) gpr_free(allocated);
322 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200323 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100324 tcp_unref(tcp);
325 return ret;
326 }
327
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200328 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
329 operation, this time asynchronously. */
zeliard3874ad02015-04-30 16:05:45 +0900330 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100331 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
332 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
333 if (allocated) gpr_free(allocated);
334
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200335 if (status != 0) {
336 int wsa_error = WSAGetLastError();
337 if (wsa_error != WSA_IO_PENDING) {
338 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
339 tcp->socket->write_info.outstanding = 0;
340 tcp_unref(tcp);
341 return GRPC_ENDPOINT_WRITE_ERROR;
342 }
343 }
344
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200345 /* As all is now setup, we can now ask for the IOCP notification. It may
346 trigger the callback immediately however, but no matter. */
Nicolas Noble45e67a32015-02-09 16:20:49 -0800347 grpc_socket_notify_on_write(socket, on_write, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100348 return GRPC_ENDPOINT_WRITE_PENDING;
349}
350
351static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
352 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800353 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100354}
355
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200356/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
357 for the potential read and write operations. It is up to the caller to
358 guarantee this isn't called in parallel to a read or write request, so
359 we're not going to protect against these. However the IO Completion Port
360 callback will happen from another thread, so we need to protect against
361 concurrent access of the data structure in that regard. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100362static void win_shutdown(grpc_endpoint *ep) {
363 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200364 gpr_mu_lock(&tcp->mu);
365 /* At that point, what may happen is that we're already inside the IOCP
366 callback. See the comments in on_read and on_write. */
367 tcp->shutting_down = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100368 grpc_winsocket_shutdown(tcp->socket);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200369 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100370}
371
372static void win_destroy(grpc_endpoint *ep) {
373 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100374 tcp_unref(tcp);
375}
376
377static grpc_endpoint_vtable vtable = {
378 win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
379};
380
381grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
382 grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
383 memset(tcp, 0, sizeof(grpc_tcp));
384 tcp->base.vtable = &vtable;
385 tcp->socket = socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200386 gpr_mu_init(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100387 gpr_slice_buffer_init(&tcp->write_slices);
388 gpr_ref_init(&tcp->refcount, 1);
389 return &tcp->base;
390}
391
Craig Tiller190d3602015-02-18 09:23:38 -0800392#endif /* GPR_WINSOCK_SOCKET */