blob: 2c2df000057e3f12c689fb563fcf1bb615062521 [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;
175 int error;
176 WSABUF buffer;
177
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200178 GPR_ASSERT(!tcp->socket->read_info.outstanding);
179 if (tcp->shutting_down) {
180 cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
181 return;
182 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100183 tcp_ref(tcp);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200184 tcp->socket->read_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100185 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
Nicolas Noble45e67a32015-02-09 16:20:49 -0800211 grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100212}
213
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200214/* Asynchronous callback from the IOCP, or the background thread. */
215static void on_write(void *tcpp, int from_iocp) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100216 grpc_tcp *tcp = (grpc_tcp *) tcpp;
217 grpc_winsocket *handle = tcp->socket;
218 grpc_winsocket_callback_info *info = &handle->write_info;
219 grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
220 grpc_endpoint_write_cb cb = tcp->write_cb;
221 void *opaque = tcp->write_user_data;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200222 int do_abort = 0;
223
224 gpr_mu_lock(&tcp->mu);
225 if (!from_iocp || tcp->shutting_down) {
226 /* If we are here with from_iocp set to true, it means we got raced to
227 shutting down the endpoint. No actual abort callback will happen
228 though, so we're going to do it from here. */
229 do_abort = 1;
230 }
231 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100232
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200233 GPR_ASSERT(tcp->socket->write_info.outstanding);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100234
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200235 if (do_abort) {
236 if (from_iocp) gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100237 tcp_unref(tcp);
Nicolas "Pixel" Nobleba410fa2015-02-05 00:54:15 +0100238 cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100239 return;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100240 }
241
242 if (info->wsa_error != 0) {
243 char *utf8_message = gpr_format_message(info->wsa_error);
244 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
245 gpr_free(utf8_message);
246 status = GRPC_ENDPOINT_CB_ERROR;
247 } else {
248 GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
249 }
250
251 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200252 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100253
254 tcp_unref(tcp);
255 cb(opaque, status);
256}
257
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200258/* Initiates a write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100259static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
260 gpr_slice *slices, size_t nslices,
261 grpc_endpoint_write_cb cb,
262 void *arg) {
263 grpc_tcp *tcp = (grpc_tcp *) ep;
264 grpc_winsocket *socket = tcp->socket;
265 grpc_winsocket_callback_info *info = &socket->write_info;
266 unsigned i;
267 DWORD bytes_sent;
268 int status;
269 WSABUF local_buffers[16];
270 WSABUF *allocated = NULL;
271 WSABUF *buffers = local_buffers;
272
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200273 GPR_ASSERT(!tcp->socket->write_info.outstanding);
274 if (tcp->shutting_down) {
275 return GRPC_ENDPOINT_WRITE_ERROR;
276 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100277 tcp_ref(tcp);
278
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200279 tcp->socket->write_info.outstanding = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100280 tcp->write_cb = cb;
281 tcp->write_user_data = arg;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200282
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100283 gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
284
285 if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
286 buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
287 allocated = buffers;
288 }
289
290 for (i = 0; i < tcp->write_slices.count; i++) {
291 buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
Nicolas Noblecfd60732015-03-18 16:27:43 -0700292 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100293 }
294
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200295 /* First, let's try a synchronous, non-blocking write. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100296 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
297 &bytes_sent, 0, NULL, NULL);
298 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
299
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200300 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
301 connection that has its send queue filled up. But if we don't, then we can
302 avoid doing an async write operation at all. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100303 if (info->wsa_error != WSAEWOULDBLOCK) {
304 grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100305 if (status == 0) {
306 ret = GRPC_ENDPOINT_WRITE_DONE;
307 GPR_ASSERT(bytes_sent == tcp->write_slices.length);
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +0100308 } else {
309 char *utf8_message = gpr_format_message(info->wsa_error);
310 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
311 gpr_free(utf8_message);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100312 }
313 if (allocated) gpr_free(allocated);
314 gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
Nicolas "Pixel" Noblee34a45a2015-05-07 18:41:07 +0200315 tcp->socket->write_info.outstanding = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100316 tcp_unref(tcp);
317 return ret;
318 }
319
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200320 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
321 operation, this time asynchronously. */
zeliard3874ad02015-04-30 16:05:45 +0900322 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100323 status = WSASend(socket->socket, buffers, tcp->write_slices.count,
324 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
325 if (allocated) gpr_free(allocated);
326
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200327 /* As all is now setup, we can now ask for the IOCP notification. It may
328 trigger the callback immediately however, but no matter. */
Nicolas Noble45e67a32015-02-09 16:20:49 -0800329 grpc_socket_notify_on_write(socket, on_write, tcp);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100330 return GRPC_ENDPOINT_WRITE_PENDING;
331}
332
333static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
334 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800335 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100336}
337
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200338/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
339 for the potential read and write operations. It is up to the caller to
340 guarantee this isn't called in parallel to a read or write request, so
341 we're not going to protect against these. However the IO Completion Port
342 callback will happen from another thread, so we need to protect against
343 concurrent access of the data structure in that regard. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100344static void win_shutdown(grpc_endpoint *ep) {
345 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200346 gpr_mu_lock(&tcp->mu);
347 /* At that point, what may happen is that we're already inside the IOCP
348 callback. See the comments in on_read and on_write. */
349 tcp->shutting_down = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100350 grpc_winsocket_shutdown(tcp->socket);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200351 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100352}
353
354static void win_destroy(grpc_endpoint *ep) {
355 grpc_tcp *tcp = (grpc_tcp *) ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100356 tcp_unref(tcp);
357}
358
359static grpc_endpoint_vtable vtable = {
360 win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
361};
362
363grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
364 grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
365 memset(tcp, 0, sizeof(grpc_tcp));
366 tcp->base.vtable = &vtable;
367 tcp->socket = socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200368 gpr_mu_init(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100369 gpr_slice_buffer_init(&tcp->write_slices);
370 gpr_ref_init(&tcp->refcount, 1);
371 return &tcp->base;
372}
373
Craig Tiller190d3602015-02-18 09:23:38 -0800374#endif /* GPR_WINSOCK_SOCKET */