blob: 9b1db5fa7e4480aa375f313408feec07379bb382 [file] [log] [blame]
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01001/*
2 *
Nicolas "Pixel" Noble929523a2016-01-28 09:55:14 +01003 * Copyright 2015-2016, 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 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"
Craig Tillerf40df232016-03-25 13:38:14 -070052#include "src/core/iomgr/timer.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010053
Craig Tillera82950e2015-09-22 12:33:20 -070054static int set_non_block(SOCKET sock) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010055 int status;
56 unsigned long param = 1;
57 DWORD ret;
Craig Tillera82950e2015-09-22 12:33:20 -070058 status =
59 WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret, NULL, NULL);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010060 return status == 0;
61}
62
Craig Tillera82950e2015-09-22 12:33:20 -070063static int set_dualstack(SOCKET sock) {
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010064 int status;
65 unsigned long param = 0;
Craig Tillera82950e2015-09-22 12:33:20 -070066 status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
67 sizeof(param));
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010068 return status == 0;
69}
70
Craig Tillera82950e2015-09-22 12:33:20 -070071int grpc_tcp_prepare_socket(SOCKET sock) {
72 if (!set_non_block(sock)) return 0;
73 if (!set_dualstack(sock)) return 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010074 return 1;
75}
76
Craig Tillera82950e2015-09-22 12:33:20 -070077typedef struct grpc_tcp {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020078 /* This is our C++ class derivation emulation. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010079 grpc_endpoint base;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020080 /* The one socket this endpoint is using. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010081 grpc_winsocket *socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020082 /* Refcounting how many operations are in progress. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010083 gpr_refcount refcount;
84
Craig Tiller82f9bd82015-09-23 09:31:51 -070085 grpc_closure on_read;
86 grpc_closure on_write;
87
Craig Tiller33825112015-09-18 07:44:19 -070088 grpc_closure *read_cb;
89 grpc_closure *write_cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010090 gpr_slice read_slice;
Craig Tillerb0298592015-08-27 07:38:01 -070091 gpr_slice_buffer *write_slices;
92 gpr_slice_buffer *read_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;
Craig Tiller81bcc4c2015-07-20 14:04:18 -070098
99 char *peer_string;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100100} grpc_tcp;
101
Craig Tillera82950e2015-09-22 12:33:20 -0700102static void tcp_free(grpc_tcp *tcp) {
103 grpc_winsocket_destroy(tcp->socket);
104 gpr_mu_destroy(&tcp->mu);
105 gpr_free(tcp->peer_string);
106 gpr_free(tcp);
Craig Tillerb0298592015-08-27 07:38:01 -0700107}
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100108
Craig Tillerb0298592015-08-27 07:38:01 -0700109/*#define GRPC_TCP_REFCOUNT_DEBUG*/
110#ifdef GRPC_TCP_REFCOUNT_DEBUG
111#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
112#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
Craig Tillera82950e2015-09-22 12:33:20 -0700113static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
114 int line) {
115 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
116 reason, tcp->refcount.count, tcp->refcount.count - 1);
117 if (gpr_unref(&tcp->refcount)) {
118 tcp_free(tcp);
119 }
Craig Tiller0882a352015-08-26 13:21:14 -0700120}
121
Craig Tillera82950e2015-09-22 12:33:20 -0700122static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
123 int line) {
124 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp,
125 reason, tcp->refcount.count, tcp->refcount.count + 1);
126 gpr_ref(&tcp->refcount);
Craig Tillerb0298592015-08-27 07:38:01 -0700127}
128#else
129#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
130#define TCP_REF(tcp, reason) tcp_ref((tcp))
Craig Tillera82950e2015-09-22 12:33:20 -0700131static void tcp_unref(grpc_tcp *tcp) {
132 if (gpr_unref(&tcp->refcount)) {
133 tcp_free(tcp);
134 }
Craig Tillerb0298592015-08-27 07:38:01 -0700135}
136
Craig Tillera82950e2015-09-22 12:33:20 -0700137static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
Craig Tillerb0298592015-08-27 07:38:01 -0700138#endif
139
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200140/* Asynchronous callback from the IOCP, or the background thread. */
Craig Tillereced8ae2016-01-28 14:13:20 -0800141static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700142 grpc_tcp *tcp = tcpp;
143 grpc_closure *cb = tcp->read_cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100144 grpc_winsocket *socket = tcp->socket;
145 gpr_slice sub;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100146 grpc_winsocket_callback_info *info = &socket->read_info;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100147
Craig Tillera82950e2015-09-22 12:33:20 -0700148 if (success) {
Jan Tattermusch64124792016-03-25 09:16:22 -0700149 if (info->wsa_error != 0 && !tcp->shutting_down) {
150 if (info->wsa_error != WSAECONNRESET) {
Craig Tillera82950e2015-09-22 12:33:20 -0700151 char *utf8_message = gpr_format_message(info->wsa_error);
152 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
153 gpr_free(utf8_message);
154 }
155 success = 0;
156 gpr_slice_unref(tcp->read_slice);
157 } else {
Nicolas "Pixel" Noble3a26c5b2015-09-22 00:07:14 +0200158 if (info->bytes_transfered != 0 && !tcp->shutting_down) {
Craig Tillera82950e2015-09-22 12:33:20 -0700159 sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
160 gpr_slice_buffer_add(tcp->read_slices, sub);
161 success = 1;
162 } else {
163 gpr_slice_unref(tcp->read_slice);
164 success = 0;
165 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100166 }
Craig Tillera82950e2015-09-22 12:33:20 -0700167 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200168
Craig Tillerb0298592015-08-27 07:38:01 -0700169 tcp->read_cb = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700170 TCP_UNREF(tcp, "read");
171 if (cb) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700172 cb->cb(exec_ctx, cb->cb_arg, success);
Craig Tillera82950e2015-09-22 12:33:20 -0700173 }
Craig Tillerb0298592015-08-27 07:38:01 -0700174}
175
Craig Tiller565b18b2015-09-23 10:09:42 -0700176static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
177 gpr_slice_buffer *read_slices, grpc_closure *cb) {
Craig Tillera82950e2015-09-22 12:33:20 -0700178 grpc_tcp *tcp = (grpc_tcp *)ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100179 grpc_winsocket *handle = tcp->socket;
180 grpc_winsocket_callback_info *info = &handle->read_info;
181 int status;
182 DWORD bytes_read = 0;
183 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100184 WSABUF buffer;
185
Craig Tillera82950e2015-09-22 12:33:20 -0700186 if (tcp->shutting_down) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800187 grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700188 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700189 }
Craig Tillerb0298592015-08-27 07:38:01 -0700190
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100191 tcp->read_cb = cb;
Craig Tillerb0298592015-08-27 07:38:01 -0700192 tcp->read_slices = read_slices;
Craig Tillera82950e2015-09-22 12:33:20 -0700193 gpr_slice_buffer_reset_and_unref(read_slices);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100194
Craig Tillera82950e2015-09-22 12:33:20 -0700195 tcp->read_slice = gpr_slice_malloc(8192);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100196
Craig Tiller620e9652015-12-14 12:02:50 -0800197 buffer.len = (ULONG)GPR_SLICE_LENGTH(
198 tcp->read_slice); // we know slice size fits in 32bit.
Craig Tillera82950e2015-09-22 12:33:20 -0700199 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100200
Craig Tiller82f9bd82015-09-23 09:31:51 -0700201 TCP_REF(tcp, "read");
202
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200203 /* First let's try a synchronous, non-blocking read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700204 status =
205 WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
206 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100207
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200208 /* Did we get data immediately ? Yay. */
Craig Tillera82950e2015-09-22 12:33:20 -0700209 if (info->wsa_error != WSAEWOULDBLOCK) {
Craig Tillera82950e2015-09-22 12:33:20 -0700210 info->bytes_transfered = bytes_read;
Craig Tillereced8ae2016-01-28 14:13:20 -0800211 grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700212 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700213 }
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200214
Craig Tiller45724b32015-09-22 10:42:19 -0700215 /* Otherwise, let's retry, by queuing a read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700216 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
217 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
218 &info->overlapped, NULL);
Craig Tiller45724b32015-09-22 10:42:19 -0700219
Craig Tillera82950e2015-09-22 12:33:20 -0700220 if (status != 0) {
221 int wsa_error = WSAGetLastError();
222 if (wsa_error != WSA_IO_PENDING) {
Craig Tillera82950e2015-09-22 12:33:20 -0700223 info->wsa_error = wsa_error;
Craig Tillereced8ae2016-01-28 14:13:20 -0800224 grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700225 return;
Craig Tiller45724b32015-09-22 10:42:19 -0700226 }
Craig Tillera82950e2015-09-22 12:33:20 -0700227 }
Craig Tiller45724b32015-09-22 10:42:19 -0700228
Craig Tiller82f9bd82015-09-23 09:31:51 -0700229 grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100230}
231
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200232/* Asynchronous callback from the IOCP, or the background thread. */
Craig Tillereced8ae2016-01-28 14:13:20 -0800233static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
Craig Tillera82950e2015-09-22 12:33:20 -0700234 grpc_tcp *tcp = (grpc_tcp *)tcpp;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100235 grpc_winsocket *handle = tcp->socket;
236 grpc_winsocket_callback_info *info = &handle->write_info;
Craig Tiller33825112015-09-18 07:44:19 -0700237 grpc_closure *cb;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200238
Craig Tillera82950e2015-09-22 12:33:20 -0700239 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700240 cb = tcp->write_cb;
241 tcp->write_cb = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700242 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100243
Craig Tillera82950e2015-09-22 12:33:20 -0700244 if (success) {
245 if (info->wsa_error != 0) {
246 if (info->wsa_error != WSAECONNRESET) {
247 char *utf8_message = gpr_format_message(info->wsa_error);
248 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
249 gpr_free(utf8_message);
250 }
251 success = 0;
252 } else {
253 GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
Nicolas Noblee1445362015-05-11 17:40:26 -0700254 }
Craig Tillera82950e2015-09-22 12:33:20 -0700255 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100256
Craig Tillera82950e2015-09-22 12:33:20 -0700257 TCP_UNREF(tcp, "write");
Craig Tiller82f9bd82015-09-23 09:31:51 -0700258 cb->cb(exec_ctx, cb->cb_arg, success);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100259}
260
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200261/* Initiates a write. */
Craig Tiller565b18b2015-09-23 10:09:42 -0700262static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
263 gpr_slice_buffer *slices, grpc_closure *cb) {
Craig Tillera82950e2015-09-22 12:33:20 -0700264 grpc_tcp *tcp = (grpc_tcp *)ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100265 grpc_winsocket *socket = tcp->socket;
266 grpc_winsocket_callback_info *info = &socket->write_info;
267 unsigned i;
268 DWORD bytes_sent;
269 int status;
270 WSABUF local_buffers[16];
271 WSABUF *allocated = NULL;
272 WSABUF *buffers = local_buffers;
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800273 size_t len;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100274
Craig Tillera82950e2015-09-22 12:33:20 -0700275 if (tcp->shutting_down) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800276 grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700277 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700278 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100279
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100280 tcp->write_cb = cb;
Craig Tillerb0298592015-08-27 07:38:01 -0700281 tcp->write_slices = slices;
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800282 GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
Craig Tillera82950e2015-09-22 12:33:20 -0700283 if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) {
284 buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count);
285 allocated = buffers;
286 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100287
Craig Tillera82950e2015-09-22 12:33:20 -0700288 for (i = 0; i < tcp->write_slices->count; i++) {
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800289 len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
290 GPR_ASSERT(len <= ULONG_MAX);
Craig Tiller620e9652015-12-14 12:02:50 -0800291 buffers[i].len = (ULONG)len;
Craig Tillera82950e2015-09-22 12:33:20 -0700292 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
293 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100294
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200295 /* First, let's try a synchronous, non-blocking write. */
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -0800296 status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
Craig Tillera82950e2015-09-22 12:33:20 -0700297 &bytes_sent, 0, NULL, NULL);
298 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100299
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. */
Craig Tillera82950e2015-09-22 12:33:20 -0700303 if (info->wsa_error != WSAEWOULDBLOCK) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800304 bool ok = false;
Craig Tillera82950e2015-09-22 12:33:20 -0700305 if (status == 0) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800306 ok = true;
Craig Tillera82950e2015-09-22 12:33:20 -0700307 GPR_ASSERT(bytes_sent == tcp->write_slices->length);
308 } else {
Jan Tattermusch64124792016-03-25 09:16:22 -0700309 if (info->wsa_error != WSAECONNRESET) {
Craig Tillera82950e2015-09-22 12:33:20 -0700310 char *utf8_message = gpr_format_message(info->wsa_error);
311 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
312 gpr_free(utf8_message);
313 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100314 }
Craig Tillera82950e2015-09-22 12:33:20 -0700315 if (allocated) gpr_free(allocated);
Craig Tillereced8ae2016-01-28 14:13:20 -0800316 grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700317 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700318 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100319
Craig Tillera82950e2015-09-22 12:33:20 -0700320 TCP_REF(tcp, "write");
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700321
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200322 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
323 operation, this time asynchronously. */
Craig Tillera82950e2015-09-22 12:33:20 -0700324 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -0800325 status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
Craig Tillera82950e2015-09-22 12:33:20 -0700326 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
327 if (allocated) gpr_free(allocated);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100328
Craig Tillera82950e2015-09-22 12:33:20 -0700329 if (status != 0) {
330 int wsa_error = WSAGetLastError();
331 if (wsa_error != WSA_IO_PENDING) {
332 TCP_UNREF(tcp, "write");
Craig Tillereced8ae2016-01-28 14:13:20 -0800333 grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700334 return;
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200335 }
Craig Tillera82950e2015-09-22 12:33:20 -0700336 }
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200337
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200338 /* As all is now setup, we can now ask for the IOCP notification. It may
339 trigger the callback immediately however, but no matter. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700340 grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100341}
342
Craig Tiller565b18b2015-09-23 10:09:42 -0700343static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
344 grpc_pollset *ps) {
Jan Tattermuschdeab29e2015-08-03 12:32:44 -0700345 grpc_tcp *tcp;
Craig Tillera82950e2015-09-22 12:33:20 -0700346 (void)ps;
347 tcp = (grpc_tcp *)ep;
348 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noblef29e9db2015-07-29 06:00:22 +0200349}
350
Craig Tiller565b18b2015-09-23 10:09:42 -0700351static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
352 grpc_pollset_set *pss) {
Jan Tattermuschdeab29e2015-08-03 12:32:44 -0700353 grpc_tcp *tcp;
Craig Tillera82950e2015-09-22 12:33:20 -0700354 (void)pss;
355 tcp = (grpc_tcp *)ep;
356 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100357}
358
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200359/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
360 for the potential read and write operations. It is up to the caller to
361 guarantee this isn't called in parallel to a read or write request, so
362 we're not going to protect against these. However the IO Completion Port
363 callback will happen from another thread, so we need to protect against
364 concurrent access of the data structure in that regard. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700365static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
Craig Tillera82950e2015-09-22 12:33:20 -0700366 grpc_tcp *tcp = (grpc_tcp *)ep;
367 gpr_mu_lock(&tcp->mu);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200368 /* At that point, what may happen is that we're already inside the IOCP
369 callback. See the comments in on_read and on_write. */
370 tcp->shutting_down = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700371 grpc_winsocket_shutdown(tcp->socket);
372 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100373}
374
Craig Tiller82f9bd82015-09-23 09:31:51 -0700375static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
Craig Tillera82950e2015-09-22 12:33:20 -0700376 grpc_tcp *tcp = (grpc_tcp *)ep;
377 TCP_UNREF(tcp, "destroy");
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100378}
379
Craig Tillera82950e2015-09-22 12:33:20 -0700380static char *win_get_peer(grpc_endpoint *ep) {
381 grpc_tcp *tcp = (grpc_tcp *)ep;
382 return gpr_strdup(tcp->peer_string);
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700383}
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100384
Craig Tillerf40df232016-03-25 13:38:14 -0700385static grpc_endpoint_vtable vtable = {
386 win_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
387 win_shutdown, win_destroy, win_get_peer};
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100388
Craig Tillera82950e2015-09-22 12:33:20 -0700389grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
390 grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
391 memset(tcp, 0, sizeof(grpc_tcp));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100392 tcp->base.vtable = &vtable;
393 tcp->socket = socket;
Craig Tillera82950e2015-09-22 12:33:20 -0700394 gpr_mu_init(&tcp->mu);
395 gpr_ref_init(&tcp->refcount, 1);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700396 grpc_closure_init(&tcp->on_read, on_read, tcp);
Craig Tiller258f8de2015-09-23 12:32:40 -0700397 grpc_closure_init(&tcp->on_write, on_write, tcp);
Craig Tillera82950e2015-09-22 12:33:20 -0700398 tcp->peer_string = gpr_strdup(peer_string);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100399 return &tcp->base;
400}
401
Craig Tillerd6c98df2015-08-18 09:33:44 -0700402#endif /* GPR_WINSOCK_SOCKET */