blob: 0eecccb0000db659fe4eedb29ba70652c7a6097b [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
murgatroid9954070892016-08-08 17:01:18 -070034#include "src/core/lib/iomgr/port.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010035
36#ifdef GPR_WINSOCK_SOCKET
37
Nicolas "Pixel" Noblec4b18a52016-04-15 04:53:54 +020038#include <limits.h>
39
Makarand Dharmapurikar0579cfc2016-06-20 15:45:24 -070040#include "src/core/lib/iomgr/network_status_tracker.h"
Yuchen Zeng12dfdc32016-04-26 22:05:41 -070041#include "src/core/lib/iomgr/sockaddr_windows.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010042
43#include <grpc/support/alloc.h>
44#include <grpc/support/log.h>
Yuchen Zeng12dfdc32016-04-26 22:05:41 -070045#include <grpc/support/log_windows.h>
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010046#include <grpc/support/slice_buffer.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070047#include <grpc/support/string_util.h>
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010048#include <grpc/support/useful.h>
49
Craig Tiller9533d042016-03-25 17:11:06 -070050#include "src/core/lib/iomgr/iocp_windows.h"
51#include "src/core/lib/iomgr/sockaddr.h"
52#include "src/core/lib/iomgr/sockaddr_utils.h"
53#include "src/core/lib/iomgr/socket_windows.h"
54#include "src/core/lib/iomgr/tcp_client.h"
55#include "src/core/lib/iomgr/timer.h"
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010056
Nicolas "Pixel" Noblec4b18a52016-04-15 04:53:54 +020057#if defined(__MSYS__) && defined(GPR_ARCH_64)
58/* Nasty workaround for nasty bug when using the 64 bits msys compiler
59 in conjunction with Microsoft Windows headers. */
60#define GRPC_FIONBIO _IOW('f', 126, uint32_t)
61#else
62#define GRPC_FIONBIO FIONBIO
63#endif
64
Craig Tiller3e149f32016-05-17 16:11:04 -070065static grpc_error *set_non_block(SOCKET sock) {
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010066 int status;
Nicolas "Pixel" Noblec4b18a52016-04-15 04:53:54 +020067 uint32_t param = 1;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010068 DWORD ret;
Nicolas "Pixel" Noble344f55b2016-04-15 07:52:25 +020069 status = WSAIoctl(sock, GRPC_FIONBIO, &param, sizeof(param), NULL, 0, &ret,
70 NULL, NULL);
Craig Tiller3e149f32016-05-17 16:11:04 -070071 return status == 0
72 ? GRPC_ERROR_NONE
73 : GRPC_WSA_ERROR(WSAGetLastError(), "WSAIoctl(GRPC_FIONBIO)");
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010074}
75
Craig Tiller3e149f32016-05-17 16:11:04 -070076static grpc_error *set_dualstack(SOCKET sock) {
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010077 int status;
78 unsigned long param = 0;
Craig Tillera82950e2015-09-22 12:33:20 -070079 status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
80 sizeof(param));
Craig Tiller3e149f32016-05-17 16:11:04 -070081 return status == 0
82 ? GRPC_ERROR_NONE
83 : GRPC_WSA_ERROR(WSAGetLastError(), "setsockopt(IPV6_V6ONLY)");
Nicolas "Pixel" Nobleee0c96c2015-02-04 23:35:41 +010084}
85
Craig Tiller3e149f32016-05-17 16:11:04 -070086grpc_error *grpc_tcp_prepare_socket(SOCKET sock) {
87 grpc_error *err;
Craig Tillera41ac572016-05-17 16:08:17 -070088 err = set_non_block(sock);
89 if (err != GRPC_ERROR_NONE) return err;
90 err = set_dualstack(sock);
91 if (err != GRPC_ERROR_NONE) return err;
92 return GRPC_ERROR_NONE;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010093}
94
Craig Tillera82950e2015-09-22 12:33:20 -070095typedef struct grpc_tcp {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020096 /* This is our C++ class derivation emulation. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010097 grpc_endpoint base;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +020098 /* The one socket this endpoint is using. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +010099 grpc_winsocket *socket;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200100 /* Refcounting how many operations are in progress. */
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100101 gpr_refcount refcount;
102
Craig Tiller82f9bd82015-09-23 09:31:51 -0700103 grpc_closure on_read;
104 grpc_closure on_write;
105
Craig Tiller33825112015-09-18 07:44:19 -0700106 grpc_closure *read_cb;
107 grpc_closure *write_cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100108 gpr_slice read_slice;
Craig Tillerb0298592015-08-27 07:38:01 -0700109 gpr_slice_buffer *write_slices;
110 gpr_slice_buffer *read_slices;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100111
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200112 /* The IO Completion Port runs from another thread. We need some mechanism
113 to protect ourselves when requesting a shutdown. */
114 gpr_mu mu;
115 int shutting_down;
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700116
117 char *peer_string;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100118} grpc_tcp;
119
Craig Tillera82950e2015-09-22 12:33:20 -0700120static void tcp_free(grpc_tcp *tcp) {
121 grpc_winsocket_destroy(tcp->socket);
122 gpr_mu_destroy(&tcp->mu);
123 gpr_free(tcp->peer_string);
124 gpr_free(tcp);
Craig Tillerb0298592015-08-27 07:38:01 -0700125}
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100126
Craig Tillerb0298592015-08-27 07:38:01 -0700127/*#define GRPC_TCP_REFCOUNT_DEBUG*/
128#ifdef GRPC_TCP_REFCOUNT_DEBUG
129#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
130#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
Craig Tillera82950e2015-09-22 12:33:20 -0700131static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
132 int line) {
133 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
134 reason, tcp->refcount.count, tcp->refcount.count - 1);
135 if (gpr_unref(&tcp->refcount)) {
136 tcp_free(tcp);
137 }
Craig Tiller0882a352015-08-26 13:21:14 -0700138}
139
Craig Tillera82950e2015-09-22 12:33:20 -0700140static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
141 int line) {
142 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp,
143 reason, tcp->refcount.count, tcp->refcount.count + 1);
144 gpr_ref(&tcp->refcount);
Craig Tillerb0298592015-08-27 07:38:01 -0700145}
146#else
147#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
148#define TCP_REF(tcp, reason) tcp_ref((tcp))
Craig Tillera82950e2015-09-22 12:33:20 -0700149static void tcp_unref(grpc_tcp *tcp) {
150 if (gpr_unref(&tcp->refcount)) {
151 tcp_free(tcp);
152 }
Craig Tillerb0298592015-08-27 07:38:01 -0700153}
154
Craig Tillera82950e2015-09-22 12:33:20 -0700155static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
Craig Tillerb0298592015-08-27 07:38:01 -0700156#endif
157
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200158/* Asynchronous callback from the IOCP, or the background thread. */
Craig Tillera41ac572016-05-17 16:08:17 -0700159static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700160 grpc_tcp *tcp = tcpp;
161 grpc_closure *cb = tcp->read_cb;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100162 grpc_winsocket *socket = tcp->socket;
163 gpr_slice sub;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100164 grpc_winsocket_callback_info *info = &socket->read_info;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100165
Craig Tillera41ac572016-05-17 16:08:17 -0700166 GRPC_ERROR_REF(error);
167
168 if (error == GRPC_ERROR_NONE) {
Jan Tattermusch64124792016-03-25 09:16:22 -0700169 if (info->wsa_error != 0 && !tcp->shutting_down) {
Craig Tillera41ac572016-05-17 16:08:17 -0700170 char *utf8_message = gpr_format_message(info->wsa_error);
Craig Tillera41ac572016-05-17 16:08:17 -0700171 error = GRPC_ERROR_CREATE(utf8_message);
172 gpr_free(utf8_message);
Craig Tillera82950e2015-09-22 12:33:20 -0700173 gpr_slice_unref(tcp->read_slice);
174 } else {
Nicolas "Pixel" Noble3a26c5b2015-09-22 00:07:14 +0200175 if (info->bytes_transfered != 0 && !tcp->shutting_down) {
Craig Tillera82950e2015-09-22 12:33:20 -0700176 sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
177 gpr_slice_buffer_add(tcp->read_slices, sub);
Craig Tillera82950e2015-09-22 12:33:20 -0700178 } else {
179 gpr_slice_unref(tcp->read_slice);
Craig Tillera41ac572016-05-17 16:08:17 -0700180 error = GRPC_ERROR_CREATE("End of TCP stream");
Craig Tillera82950e2015-09-22 12:33:20 -0700181 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100182 }
Craig Tillera82950e2015-09-22 12:33:20 -0700183 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200184
Craig Tillerb0298592015-08-27 07:38:01 -0700185 tcp->read_cb = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700186 TCP_UNREF(tcp, "read");
Craig Tiller332f1b32016-05-24 13:21:21 -0700187 grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
Craig Tillerb0298592015-08-27 07:38:01 -0700188}
189
Craig Tiller565b18b2015-09-23 10:09:42 -0700190static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
191 gpr_slice_buffer *read_slices, grpc_closure *cb) {
Craig Tillera82950e2015-09-22 12:33:20 -0700192 grpc_tcp *tcp = (grpc_tcp *)ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100193 grpc_winsocket *handle = tcp->socket;
194 grpc_winsocket_callback_info *info = &handle->read_info;
195 int status;
196 DWORD bytes_read = 0;
197 DWORD flags = 0;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100198 WSABUF buffer;
199
Craig Tillera82950e2015-09-22 12:33:20 -0700200 if (tcp->shutting_down) {
Craig Tiller332f1b32016-05-24 13:21:21 -0700201 grpc_exec_ctx_sched(exec_ctx, cb,
Craig Tiller77c983d2016-05-24 13:23:14 -0700202 GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700203 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700204 }
Craig Tillerb0298592015-08-27 07:38:01 -0700205
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100206 tcp->read_cb = cb;
Craig Tillerb0298592015-08-27 07:38:01 -0700207 tcp->read_slices = read_slices;
Craig Tillera82950e2015-09-22 12:33:20 -0700208 gpr_slice_buffer_reset_and_unref(read_slices);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100209
Craig Tillera82950e2015-09-22 12:33:20 -0700210 tcp->read_slice = gpr_slice_malloc(8192);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100211
Craig Tiller620e9652015-12-14 12:02:50 -0800212 buffer.len = (ULONG)GPR_SLICE_LENGTH(
213 tcp->read_slice); // we know slice size fits in 32bit.
Craig Tillera82950e2015-09-22 12:33:20 -0700214 buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100215
Craig Tiller82f9bd82015-09-23 09:31:51 -0700216 TCP_REF(tcp, "read");
217
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200218 /* First let's try a synchronous, non-blocking read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700219 status =
220 WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
221 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100222
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200223 /* Did we get data immediately ? Yay. */
Craig Tillera82950e2015-09-22 12:33:20 -0700224 if (info->wsa_error != WSAEWOULDBLOCK) {
Craig Tillera82950e2015-09-22 12:33:20 -0700225 info->bytes_transfered = bytes_read;
Craig Tiller332f1b32016-05-24 13:21:21 -0700226 grpc_exec_ctx_sched(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700227 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700228 }
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200229
Craig Tiller45724b32015-09-22 10:42:19 -0700230 /* Otherwise, let's retry, by queuing a read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700231 memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
232 status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
233 &info->overlapped, NULL);
Craig Tiller45724b32015-09-22 10:42:19 -0700234
Craig Tillera82950e2015-09-22 12:33:20 -0700235 if (status != 0) {
236 int wsa_error = WSAGetLastError();
237 if (wsa_error != WSA_IO_PENDING) {
Craig Tillera82950e2015-09-22 12:33:20 -0700238 info->wsa_error = wsa_error;
Craig Tiller332f1b32016-05-24 13:21:21 -0700239 grpc_exec_ctx_sched(exec_ctx, &tcp->on_read,
Craig Tiller77c983d2016-05-24 13:23:14 -0700240 GRPC_WSA_ERROR(info->wsa_error, "WSARecv"), NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700241 return;
Craig Tiller45724b32015-09-22 10:42:19 -0700242 }
Craig Tillera82950e2015-09-22 12:33:20 -0700243 }
Craig Tiller45724b32015-09-22 10:42:19 -0700244
Craig Tiller82f9bd82015-09-23 09:31:51 -0700245 grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100246}
247
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200248/* Asynchronous callback from the IOCP, or the background thread. */
Craig Tillera41ac572016-05-17 16:08:17 -0700249static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
Craig Tillera82950e2015-09-22 12:33:20 -0700250 grpc_tcp *tcp = (grpc_tcp *)tcpp;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100251 grpc_winsocket *handle = tcp->socket;
252 grpc_winsocket_callback_info *info = &handle->write_info;
Craig Tiller33825112015-09-18 07:44:19 -0700253 grpc_closure *cb;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200254
Craig Tillera41ac572016-05-17 16:08:17 -0700255 GRPC_ERROR_REF(error);
256
Craig Tillera82950e2015-09-22 12:33:20 -0700257 gpr_mu_lock(&tcp->mu);
Nicolas Noblee1445362015-05-11 17:40:26 -0700258 cb = tcp->write_cb;
259 tcp->write_cb = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700260 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100261
Craig Tillera41ac572016-05-17 16:08:17 -0700262 if (error == GRPC_ERROR_NONE) {
Craig Tillera82950e2015-09-22 12:33:20 -0700263 if (info->wsa_error != 0) {
Craig Tillera41ac572016-05-17 16:08:17 -0700264 error = GRPC_WSA_ERROR(info->wsa_error, "WSASend");
Craig Tillera82950e2015-09-22 12:33:20 -0700265 } else {
266 GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
Nicolas Noblee1445362015-05-11 17:40:26 -0700267 }
Craig Tillera82950e2015-09-22 12:33:20 -0700268 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100269
Craig Tillera82950e2015-09-22 12:33:20 -0700270 TCP_UNREF(tcp, "write");
Craig Tiller332f1b32016-05-24 13:21:21 -0700271 grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100272}
273
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200274/* Initiates a write. */
Craig Tiller565b18b2015-09-23 10:09:42 -0700275static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
276 gpr_slice_buffer *slices, grpc_closure *cb) {
Craig Tillera82950e2015-09-22 12:33:20 -0700277 grpc_tcp *tcp = (grpc_tcp *)ep;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100278 grpc_winsocket *socket = tcp->socket;
279 grpc_winsocket_callback_info *info = &socket->write_info;
280 unsigned i;
281 DWORD bytes_sent;
282 int status;
283 WSABUF local_buffers[16];
284 WSABUF *allocated = NULL;
285 WSABUF *buffers = local_buffers;
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800286 size_t len;
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100287
Craig Tillera82950e2015-09-22 12:33:20 -0700288 if (tcp->shutting_down) {
Craig Tiller332f1b32016-05-24 13:21:21 -0700289 grpc_exec_ctx_sched(exec_ctx, cb,
Craig Tiller77c983d2016-05-24 13:23:14 -0700290 GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700291 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700292 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100293
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100294 tcp->write_cb = cb;
Craig Tillerb0298592015-08-27 07:38:01 -0700295 tcp->write_slices = slices;
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800296 GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
Craig Tillera82950e2015-09-22 12:33:20 -0700297 if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) {
298 buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count);
299 allocated = buffers;
300 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100301
Craig Tillera82950e2015-09-22 12:33:20 -0700302 for (i = 0; i < tcp->write_slices->count; i++) {
Jan Tattermuschf67f0712015-12-07 18:09:49 -0800303 len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
304 GPR_ASSERT(len <= ULONG_MAX);
Craig Tiller620e9652015-12-14 12:02:50 -0800305 buffers[i].len = (ULONG)len;
Craig Tillera82950e2015-09-22 12:33:20 -0700306 buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
307 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100308
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200309 /* First, let's try a synchronous, non-blocking write. */
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -0800310 status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
Craig Tillera82950e2015-09-22 12:33:20 -0700311 &bytes_sent, 0, NULL, NULL);
312 info->wsa_error = status == 0 ? 0 : WSAGetLastError();
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100313
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200314 /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
315 connection that has its send queue filled up. But if we don't, then we can
316 avoid doing an async write operation at all. */
Craig Tillera82950e2015-09-22 12:33:20 -0700317 if (info->wsa_error != WSAEWOULDBLOCK) {
Craig Tiller3e149f32016-05-17 16:11:04 -0700318 grpc_error *error = status == 0
319 ? GRPC_ERROR_NONE
320 : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
Craig Tiller332f1b32016-05-24 13:21:21 -0700321 grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700322 return;
Craig Tillera82950e2015-09-22 12:33:20 -0700323 }
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100324
Craig Tillera82950e2015-09-22 12:33:20 -0700325 TCP_REF(tcp, "write");
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700326
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200327 /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
328 operation, this time asynchronously. */
Craig Tillera82950e2015-09-22 12:33:20 -0700329 memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -0800330 status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
Craig Tillera82950e2015-09-22 12:33:20 -0700331 &bytes_sent, 0, &socket->write_info.overlapped, NULL);
332 if (allocated) gpr_free(allocated);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100333
Craig Tillera82950e2015-09-22 12:33:20 -0700334 if (status != 0) {
335 int wsa_error = WSAGetLastError();
336 if (wsa_error != WSA_IO_PENDING) {
337 TCP_UNREF(tcp, "write");
Craig Tiller332f1b32016-05-24 13:21:21 -0700338 grpc_exec_ctx_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"),
Craig Tiller77c983d2016-05-24 13:23:14 -0700339 NULL);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700340 return;
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200341 }
Craig Tillera82950e2015-09-22 12:33:20 -0700342 }
Nicolas "Pixel" Noble7f2e98c2015-05-08 01:41:21 +0200343
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200344 /* As all is now setup, we can now ask for the IOCP notification. It may
345 trigger the callback immediately however, but no matter. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700346 grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100347}
348
Craig Tiller565b18b2015-09-23 10:09:42 -0700349static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
350 grpc_pollset *ps) {
Jan Tattermuschdeab29e2015-08-03 12:32:44 -0700351 grpc_tcp *tcp;
Craig Tillera82950e2015-09-22 12:33:20 -0700352 (void)ps;
353 tcp = (grpc_tcp *)ep;
354 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noblef29e9db2015-07-29 06:00:22 +0200355}
356
Craig Tiller565b18b2015-09-23 10:09:42 -0700357static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
358 grpc_pollset_set *pss) {
Jan Tattermuschdeab29e2015-08-03 12:32:44 -0700359 grpc_tcp *tcp;
Craig Tillera82950e2015-09-22 12:33:20 -0700360 (void)pss;
361 tcp = (grpc_tcp *)ep;
362 grpc_iocp_add_socket(tcp->socket);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100363}
364
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200365/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
366 for the potential read and write operations. It is up to the caller to
367 guarantee this isn't called in parallel to a read or write request, so
368 we're not going to protect against these. However the IO Completion Port
369 callback will happen from another thread, so we need to protect against
370 concurrent access of the data structure in that regard. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700371static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
Craig Tillera82950e2015-09-22 12:33:20 -0700372 grpc_tcp *tcp = (grpc_tcp *)ep;
373 gpr_mu_lock(&tcp->mu);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200374 /* At that point, what may happen is that we're already inside the IOCP
375 callback. See the comments in on_read and on_write. */
376 tcp->shutting_down = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700377 grpc_winsocket_shutdown(tcp->socket);
378 gpr_mu_unlock(&tcp->mu);
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100379}
380
Craig Tiller82f9bd82015-09-23 09:31:51 -0700381static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
Makarand Dharmapurikar61494432016-06-22 13:34:59 -0700382 grpc_network_status_unregister_endpoint(ep);
Craig Tillera82950e2015-09-22 12:33:20 -0700383 grpc_tcp *tcp = (grpc_tcp *)ep;
384 TCP_UNREF(tcp, "destroy");
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100385}
386
Craig Tillera82950e2015-09-22 12:33:20 -0700387static char *win_get_peer(grpc_endpoint *ep) {
388 grpc_tcp *tcp = (grpc_tcp *)ep;
389 return gpr_strdup(tcp->peer_string);
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700390}
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100391
Craig Tiller5e4fb0e2016-06-30 14:53:51 -0700392static grpc_workqueue *win_get_workqueue(grpc_endpoint *ep) { return NULL; }
393
394static grpc_endpoint_vtable vtable = {win_read,
395 win_write,
396 win_get_workqueue,
397 win_add_to_pollset,
398 win_add_to_pollset_set,
399 win_shutdown,
400 win_destroy,
401 win_get_peer};
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100402
Craig Tillera82950e2015-09-22 12:33:20 -0700403grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
404 grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
405 memset(tcp, 0, sizeof(grpc_tcp));
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100406 tcp->base.vtable = &vtable;
407 tcp->socket = socket;
Craig Tillera82950e2015-09-22 12:33:20 -0700408 gpr_mu_init(&tcp->mu);
409 gpr_ref_init(&tcp->refcount, 1);
Craig Tiller82f9bd82015-09-23 09:31:51 -0700410 grpc_closure_init(&tcp->on_read, on_read, tcp);
Craig Tiller258f8de2015-09-23 12:32:40 -0700411 grpc_closure_init(&tcp->on_write, on_write, tcp);
Craig Tillera82950e2015-09-22 12:33:20 -0700412 tcp->peer_string = gpr_strdup(peer_string);
Makarand Dharmapurikar0579cfc2016-06-20 15:45:24 -0700413 /* Tell network status tracking code about the new endpoint */
414 grpc_network_status_register_endpoint(&tcp->base);
415
Nicolas "Pixel" Noble21f627a2015-02-04 01:31:14 +0100416 return &tcp->base;
417}
418
Craig Tillerd6c98df2015-08-18 09:33:44 -0700419#endif /* GPR_WINSOCK_SOCKET */