blob: 551149e1a62cd4d6b324811aa6648c8f6d563634 [file] [log] [blame]
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +01001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * 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
Nicolas "Pixel" Noblec4b18a52016-04-15 04:53:54 +020038#include <limits.h>
39
Craig Tiller9533d042016-03-25 17:11:06 -070040#include "src/core/lib/iomgr/sockaddr_win32.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010041
42#include <grpc/support/alloc.h>
43#include <grpc/support/log.h>
44#include <grpc/support/log_win32.h>
45#include <grpc/support/slice_buffer.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070046#include <grpc/support/string_util.h>
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010047#include <grpc/support/useful.h>
48
Craig Tiller9533d042016-03-25 17:11:06 -070049#include "src/core/lib/iomgr/iocp_windows.h"
50#include "src/core/lib/iomgr/sockaddr.h"
51#include "src/core/lib/iomgr/sockaddr_utils.h"
52#include "src/core/lib/iomgr/socket_windows.h"
53#include "src/core/lib/iomgr/tcp_client.h"
54#include "src/core/lib/iomgr/timer.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010055
Nicolas "Pixel" Noblec4b18a52016-04-15 04:53:54 +020056#if defined(__MSYS__) && defined(GPR_ARCH_64)
57/* Nasty workaround for nasty bug when using the 64 bits msys compiler
58 in conjunction with Microsoft Windows headers. */
59#define GRPC_FIONBIO _IOW('f', 126, uint32_t)
60#else
61#define GRPC_FIONBIO FIONBIO
62#endif
63
Craig Tillera82950e2015-09-22 12:33:20 -070064static int set_non_block(SOCKET sock) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010065 int status;
Nicolas "Pixel" Noblec4b18a52016-04-15 04:53:54 +020066 uint32_t param = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010067 DWORD ret;
Nicolas "Pixel" Noble344f55b2016-04-15 07:52:25 +020068 status = WSAIoctl(sock, GRPC_FIONBIO, &param, sizeof(param), NULL, 0, &ret,
69 NULL, NULL);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010070 return status == 0;
71}
72
Craig Tillera82950e2015-09-22 12:33:20 -070073static int set_dualstack(SOCKET sock) {
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010074 int status;
75 unsigned long param = 0;
Craig Tillera82950e2015-09-22 12:33:20 -070076 status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
77 sizeof(param));
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010078 return status == 0;
79}
80
Craig Tillera82950e2015-09-22 12:33:20 -070081int grpc_tcp_prepare_socket(SOCKET sock) {
82 if (!set_non_block(sock)) return 0;
83 if (!set_dualstack(sock)) return 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010084 return 1;
85}
86
Craig Tillera82950e2015-09-22 12:33:20 -070087typedef struct grpc_tcp {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020088 /* This is our C++ class derivation emulation. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010089 grpc_endpoint base;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020090 /* The one socket this endpoint is using. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010091 grpc_winsocket *socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020092 /* Refcounting how many operations are in progress. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010093 gpr_refcount refcount;
94
Craig Tiller82f9bd82015-09-23 09:31:51 -070095 grpc_closure on_read;
96 grpc_closure on_write;
97
Craig Tiller33825112015-09-18 07:44:19 -070098 grpc_closure *read_cb;
99 grpc_closure *write_cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100100 gpr_slice read_slice;
Craig Tillerb0298592015-08-27 07:38:01 -0700101 gpr_slice_buffer *write_slices;
102 gpr_slice_buffer *read_slices;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100103
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200104 /* The IO Completion Port runs from another thread. We need some mechanism
105 to protect ourselves when requesting a shutdown. */
106 gpr_mu mu;
107 int shutting_down;
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700108
109 char *peer_string;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100110} grpc_tcp;
111
Craig Tillera82950e2015-09-22 12:33:20 -0700112static void tcp_free(grpc_tcp *tcp) {
113 grpc_winsocket_destroy(tcp->socket);
114 gpr_mu_destroy(&tcp->mu);
115 gpr_free(tcp->peer_string);
116 gpr_free(tcp);
Craig Tillerb0298592015-08-27 07:38:01 -0700117}
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100118
Craig Tillerb0298592015-08-27 07:38:01 -0700119/*#define GRPC_TCP_REFCOUNT_DEBUG*/
120#ifdef GRPC_TCP_REFCOUNT_DEBUG
121#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
122#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
Craig Tillera82950e2015-09-22 12:33:20 -0700123static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
124 int line) {
125 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
126 reason, tcp->refcount.count, tcp->refcount.count - 1);
127 if (gpr_unref(&tcp->refcount)) {
128 tcp_free(tcp);
129 }
Craig Tiller0882a352015-08-26 13:21:14 -0700130}
131
Craig Tillera82950e2015-09-22 12:33:20 -0700132static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
133 int line) {
134 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp,
135 reason, tcp->refcount.count, tcp->refcount.count + 1);
136 gpr_ref(&tcp->refcount);
Craig Tillerb0298592015-08-27 07:38:01 -0700137}
138#else
139#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
140#define TCP_REF(tcp, reason) tcp_ref((tcp))
Craig Tillera82950e2015-09-22 12:33:20 -0700141static void tcp_unref(grpc_tcp *tcp) {
142 if (gpr_unref(&tcp->refcount)) {
143 tcp_free(tcp);
144 }
Craig Tillerb0298592015-08-27 07:38:01 -0700145}
146
Craig Tillera82950e2015-09-22 12:33:20 -0700147static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
Craig Tillerb0298592015-08-27 07:38:01 -0700148#endif
149
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200150/* Asynchronous callback from the IOCP, or the background thread. */
Craig Tillereced8ae2016-01-28 14:13:20 -0800151static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700152 grpc_tcp *tcp = tcpp;
153 grpc_closure *cb = tcp->read_cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100154 grpc_winsocket *socket = tcp->socket;
155 gpr_slice sub;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100156 grpc_winsocket_callback_info *info = &socket->read_info;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100157
Craig Tillera82950e2015-09-22 12:33:20 -0700158 if (success) {
Jan Tattermusch64124792016-03-25 09:16:22 -0700159 if (info->wsa_error != 0 && !tcp->shutting_down) {
160 if (info->wsa_error != WSAECONNRESET) {
Craig Tillera82950e2015-09-22 12:33:20 -0700161 char *utf8_message = gpr_format_message(info->wsa_error);
162 gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
163 gpr_free(utf8_message);
164 }
165 success = 0;
166 gpr_slice_unref(tcp->read_slice);
167 } else {
Nicolas "Pixel" Noble3a26c5b2015-09-22 00:07:14 +0200168 if (info->bytes_transfered != 0 && !tcp->shutting_down) {
Craig Tillera82950e2015-09-22 12:33:20 -0700169 sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
170 gpr_slice_buffer_add(tcp->read_slices, sub);
171 success = 1;
172 } else {
173 gpr_slice_unref(tcp->read_slice);
174 success = 0;
175 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100176 }
Craig Tillera82950e2015-09-22 12:33:20 -0700177 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200178
Craig Tillerb0298592015-08-27 07:38:01 -0700179 tcp->read_cb = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700180 TCP_UNREF(tcp, "read");
181 if (cb) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700182 cb->cb(exec_ctx, cb->cb_arg, success);
Craig Tillera82950e2015-09-22 12:33:20 -0700183 }
Craig Tillerb0298592015-08-27 07:38:01 -0700184}
185
Craig Tiller565b18b2015-09-23 10:09:42 -0700186static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
187 gpr_slice_buffer *read_slices, grpc_closure *cb) {
Craig Tillera82950e2015-09-22 12:33:20 -0700188 grpc_tcp *tcp = (grpc_tcp *)ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100189 grpc_winsocket *handle = tcp->socket;
190 grpc_winsocket_callback_info *info = &handle->read_info;
191 int status;
192 DWORD bytes_read = 0;
193 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100194 WSABUF buffer;
195
Craig Tillera82950e2015-09-22 12:33:20 -0700196 if (tcp->shutting_down) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800197 grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700198 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700199 }
Craig Tillerb0298592015-08-27 07:38:01 -0700200
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100201 tcp->read_cb = cb;
Craig Tillerb0298592015-08-27 07:38:01 -0700202 tcp->read_slices = read_slices;
Craig Tillera82950e2015-09-22 12:33:20 -0700203 gpr_slice_buffer_reset_and_unref(read_slices);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100204
Craig Tillera82950e2015-09-22 12:33:20 -0700205 tcp->read_slice = gpr_slice_malloc(8192);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100206
Craig Tiller620e9652015-12-14 12:02:50 -0800207 buffer.len = (ULONG)GPR_SLICE_LENGTH(
208 tcp->read_slice); // we know slice size fits in 32bit.
Craig Tillera82950e2015-09-22 12:33:20 -0700209 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100210
Craig Tiller82f9bd82015-09-23 09:31:51 -0700211 TCP_REF(tcp, "read");
212
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200213 /* First let's try a synchronous, non-blocking read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700214 status =
215 WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
216 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100217
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200218 /* Did we get data immediately ? Yay. */
Craig Tillera82950e2015-09-22 12:33:20 -0700219 if (info->wsa_error != WSAEWOULDBLOCK) {
Craig Tillera82950e2015-09-22 12:33:20 -0700220 info->bytes_transfered = bytes_read;
Craig Tillereced8ae2016-01-28 14:13:20 -0800221 grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700222 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700223 }
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200224
Craig Tiller45724b32015-09-22 10:42:19 -0700225 /* Otherwise, let's retry, by queuing a read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700226 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
227 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
228 &info->overlapped, NULL);
Craig Tiller45724b32015-09-22 10:42:19 -0700229
Craig Tillera82950e2015-09-22 12:33:20 -0700230 if (status != 0) {
231 int wsa_error = WSAGetLastError();
232 if (wsa_error != WSA_IO_PENDING) {
Craig Tillera82950e2015-09-22 12:33:20 -0700233 info->wsa_error = wsa_error;
Craig Tillereced8ae2016-01-28 14:13:20 -0800234 grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700235 return;
Craig Tiller45724b32015-09-22 10:42:19 -0700236 }
Craig Tillera82950e2015-09-22 12:33:20 -0700237 }
Craig Tiller45724b32015-09-22 10:42:19 -0700238
Craig Tiller82f9bd82015-09-23 09:31:51 -0700239 grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100240}
241
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200242/* Asynchronous callback from the IOCP, or the background thread. */
Craig Tillereced8ae2016-01-28 14:13:20 -0800243static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
Craig Tillera82950e2015-09-22 12:33:20 -0700244 grpc_tcp *tcp = (grpc_tcp *)tcpp;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100245 grpc_winsocket *handle = tcp->socket;
246 grpc_winsocket_callback_info *info = &handle->write_info;
Craig Tiller33825112015-09-18 07:44:19 -0700247 grpc_closure *cb;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200248
Craig Tillera82950e2015-09-22 12:33:20 -0700249 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700250 cb = tcp->write_cb;
251 tcp->write_cb = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700252 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100253
Craig Tillera82950e2015-09-22 12:33:20 -0700254 if (success) {
255 if (info->wsa_error != 0) {
256 if (info->wsa_error != WSAECONNRESET) {
257 char *utf8_message = gpr_format_message(info->wsa_error);
258 gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
259 gpr_free(utf8_message);
260 }
261 success = 0;
262 } else {
263 GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
Nicolas Noblee1445362015-05-11 17:40:26 -0700264 }
Craig Tillera82950e2015-09-22 12:33:20 -0700265 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100266
Craig Tillera82950e2015-09-22 12:33:20 -0700267 TCP_UNREF(tcp, "write");
Craig Tiller82f9bd82015-09-23 09:31:51 -0700268 cb->cb(exec_ctx, cb->cb_arg, success);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100269}
270
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200271/* Initiates a write. */
Craig Tiller565b18b2015-09-23 10:09:42 -0700272static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
273 gpr_slice_buffer *slices, grpc_closure *cb) {
Craig Tillera82950e2015-09-22 12:33:20 -0700274 grpc_tcp *tcp = (grpc_tcp *)ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100275 grpc_winsocket *socket = tcp->socket;
276 grpc_winsocket_callback_info *info = &socket->write_info;
277 unsigned i;
278 DWORD bytes_sent;
279 int status;
280 WSABUF local_buffers[16];
281 WSABUF *allocated = NULL;
282 WSABUF *buffers = local_buffers;
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800283 size_t len;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100284
Craig Tillera82950e2015-09-22 12:33:20 -0700285 if (tcp->shutting_down) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800286 grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700287 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700288 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100289
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100290 tcp->write_cb = cb;
Craig Tillerb0298592015-08-27 07:38:01 -0700291 tcp->write_slices = slices;
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800292 GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
Craig Tillera82950e2015-09-22 12:33:20 -0700293 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 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100297
Craig Tillera82950e2015-09-22 12:33:20 -0700298 for (i = 0; i < tcp->write_slices->count; i++) {
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800299 len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
300 GPR_ASSERT(len <= ULONG_MAX);
Craig Tiller620e9652015-12-14 12:02:50 -0800301 buffers[i].len = (ULONG)len;
Craig Tillera82950e2015-09-22 12:33:20 -0700302 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
303 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100304
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200305 /* First, let's try a synchronous, non-blocking write. */
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -0800306 status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
Craig Tillera82950e2015-09-22 12:33:20 -0700307 &bytes_sent, 0, NULL, NULL);
308 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100309
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200310 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
311 connection that has its send queue filled up. But if we don't, then we can
312 avoid doing an async write operation at all. */
Craig Tillera82950e2015-09-22 12:33:20 -0700313 if (info->wsa_error != WSAEWOULDBLOCK) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800314 bool ok = false;
Craig Tillera82950e2015-09-22 12:33:20 -0700315 if (status == 0) {
Craig Tillereced8ae2016-01-28 14:13:20 -0800316 ok = true;
Craig Tillera82950e2015-09-22 12:33:20 -0700317 GPR_ASSERT(bytes_sent == tcp->write_slices->length);
318 } else {
Jan Tattermusch64124792016-03-25 09:16:22 -0700319 if (info->wsa_error != WSAECONNRESET) {
Craig Tillera82950e2015-09-22 12:33:20 -0700320 char *utf8_message = gpr_format_message(info->wsa_error);
321 gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
322 gpr_free(utf8_message);
323 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100324 }
Craig Tillera82950e2015-09-22 12:33:20 -0700325 if (allocated) gpr_free(allocated);
Craig Tillereced8ae2016-01-28 14:13:20 -0800326 grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700327 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700328 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100329
Craig Tillera82950e2015-09-22 12:33:20 -0700330 TCP_REF(tcp, "write");
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700331
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200332 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
333 operation, this time asynchronously. */
Craig Tillera82950e2015-09-22 12:33:20 -0700334 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -0800335 status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
Craig Tillera82950e2015-09-22 12:33:20 -0700336 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
337 if (allocated) gpr_free(allocated);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100338
Craig Tillera82950e2015-09-22 12:33:20 -0700339 if (status != 0) {
340 int wsa_error = WSAGetLastError();
341 if (wsa_error != WSA_IO_PENDING) {
342 TCP_UNREF(tcp, "write");
Craig Tillereced8ae2016-01-28 14:13:20 -0800343 grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700344 return;
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200345 }
Craig Tillera82950e2015-09-22 12:33:20 -0700346 }
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200347
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200348 /* As all is now setup, we can now ask for the IOCP notification. It may
349 trigger the callback immediately however, but no matter. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700350 grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100351}
352
Craig Tiller565b18b2015-09-23 10:09:42 -0700353static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
354 grpc_pollset *ps) {
Jan Tattermuschdeab29e2015-08-03 12:32:44 -0700355 grpc_tcp *tcp;
Craig Tillera82950e2015-09-22 12:33:20 -0700356 (void)ps;
357 tcp = (grpc_tcp *)ep;
358 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noblef29e9db2015-07-29 06:00:22 +0200359}
360
Craig Tiller565b18b2015-09-23 10:09:42 -0700361static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
362 grpc_pollset_set *pss) {
Jan Tattermuschdeab29e2015-08-03 12:32:44 -0700363 grpc_tcp *tcp;
Craig Tillera82950e2015-09-22 12:33:20 -0700364 (void)pss;
365 tcp = (grpc_tcp *)ep;
366 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100367}
368
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200369/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
370 for the potential read and write operations. It is up to the caller to
371 guarantee this isn't called in parallel to a read or write request, so
372 we're not going to protect against these. However the IO Completion Port
373 callback will happen from another thread, so we need to protect against
374 concurrent access of the data structure in that regard. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700375static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
Craig Tillera82950e2015-09-22 12:33:20 -0700376 grpc_tcp *tcp = (grpc_tcp *)ep;
377 gpr_mu_lock(&tcp->mu);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200378 /* At that point, what may happen is that we're already inside the IOCP
379 callback. See the comments in on_read and on_write. */
380 tcp->shutting_down = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700381 grpc_winsocket_shutdown(tcp->socket);
382 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100383}
384
Craig Tiller82f9bd82015-09-23 09:31:51 -0700385static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
Craig Tillera82950e2015-09-22 12:33:20 -0700386 grpc_tcp *tcp = (grpc_tcp *)ep;
387 TCP_UNREF(tcp, "destroy");
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100388}
389
Craig Tillera82950e2015-09-22 12:33:20 -0700390static char *win_get_peer(grpc_endpoint *ep) {
391 grpc_tcp *tcp = (grpc_tcp *)ep;
392 return gpr_strdup(tcp->peer_string);
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700393}
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100394
Craig Tillerf40df232016-03-25 13:38:14 -0700395static grpc_endpoint_vtable vtable = {
396 win_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
397 win_shutdown, win_destroy, win_get_peer};
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100398
Craig Tillera82950e2015-09-22 12:33:20 -0700399grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
400 grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
401 memset(tcp, 0, sizeof(grpc_tcp));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100402 tcp->base.vtable = &vtable;
403 tcp->socket = socket;
Craig Tillera82950e2015-09-22 12:33:20 -0700404 gpr_mu_init(&tcp->mu);
405 gpr_ref_init(&tcp->refcount, 1);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700406 grpc_closure_init(&tcp->on_read, on_read, tcp);
Craig Tiller258f8de2015-09-23 12:32:40 -0700407 grpc_closure_init(&tcp->on_write, on_write, tcp);
Craig Tillera82950e2015-09-22 12:33:20 -0700408 tcp->peer_string = gpr_strdup(peer_string);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100409 return &tcp->base;
410}
411
Craig Tillerd6c98df2015-08-18 09:33:44 -0700412#endif /* GPR_WINSOCK_SOCKET */