blob: a09c1ae33594b16baeedf097b1f592101089d718 [file] [log] [blame]
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +01001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +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#define _GNU_SOURCE
39#include "src/core/iomgr/sockaddr_utils.h"
40
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010041#include <grpc/support/alloc.h>
42#include <grpc/support/log.h>
43#include <grpc/support/log_win32.h>
44#include <grpc/support/sync.h>
45#include <grpc/support/time.h>
46
Nicolas Nobled72ba6a2015-02-09 16:30:35 -080047#include "src/core/iomgr/iocp_windows.h"
48#include "src/core/iomgr/pollset_windows.h"
49#include "src/core/iomgr/socket_windows.h"
50#include "src/core/iomgr/tcp_server.h"
51#include "src/core/iomgr/tcp_windows.h"
52
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010053#define INIT_PORT_CAP 2
54#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
55
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010056/* one listening port */
57typedef struct server_port {
58 gpr_uint8 addresses[sizeof(struct sockaddr_in6) * 2 + 32];
59 SOCKET new_socket;
60 grpc_winsocket *socket;
61 grpc_tcp_server *server;
62 LPFN_ACCEPTEX AcceptEx;
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -070063 int shutting_down;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010064} server_port;
65
66/* the overall server */
67struct grpc_tcp_server {
68 grpc_tcp_server_cb cb;
69 void *cb_arg;
70
71 gpr_mu mu;
72 gpr_cv cv;
73
74 /* active port count: how many ports are actually still listening */
75 int active_ports;
76
77 /* all listening ports */
78 server_port *ports;
79 size_t nports;
80 size_t port_capacity;
81};
82
83grpc_tcp_server *grpc_tcp_server_create(void) {
84 grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
85 gpr_mu_init(&s->mu);
86 gpr_cv_init(&s->cv);
87 s->active_ports = 0;
88 s->cb = NULL;
89 s->cb_arg = NULL;
90 s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
91 s->nports = 0;
92 s->port_capacity = INIT_PORT_CAP;
93 return s;
94}
95
Craig Tiller6d979162015-04-07 16:13:13 -070096void grpc_tcp_server_destroy(grpc_tcp_server *s,
Craig Tillerc02c1d82015-04-07 16:21:55 -070097 void (*shutdown_done)(void *shutdown_done_arg),
98 void *shutdown_done_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010099 size_t i;
100 gpr_mu_lock(&s->mu);
101 /* shutdown all fd's */
102 for (i = 0; i < s->nports; i++) {
103 grpc_winsocket_shutdown(s->ports[i].socket);
104 }
105 /* wait while that happens */
106 while (s->active_ports) {
107 gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
108 }
109 gpr_mu_unlock(&s->mu);
110
111 /* delete ALL the things */
112 for (i = 0; i < s->nports; i++) {
113 server_port *sp = &s->ports[i];
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700114 sp->socket->closed_early = 1;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100115 grpc_winsocket_orphan(sp->socket);
116 }
117 gpr_free(s->ports);
118 gpr_free(s);
Craig Tiller6d979162015-04-07 16:13:13 -0700119
120 if (shutdown_done) {
Craig Tillerc02c1d82015-04-07 16:21:55 -0700121 shutdown_done(shutdown_done_arg);
Craig Tiller6d979162015-04-07 16:13:13 -0700122 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100123}
124
125/* Prepare a recently-created socket for listening. */
Craig Tillerc02c1d82015-04-07 16:21:55 -0700126static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
127 int addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100128 struct sockaddr_storage sockname_temp;
129 socklen_t sockname_len;
130
131 if (sock == INVALID_SOCKET) goto error;
132
133 if (!grpc_tcp_prepare_socket(sock)) {
134 char *utf8_message = gpr_format_message(WSAGetLastError());
135 gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
136 gpr_free(utf8_message);
137 goto error;
138 }
139
140 if (bind(sock, addr, addr_len) == SOCKET_ERROR) {
141 char *addr_str;
142 char *utf8_message = gpr_format_message(WSAGetLastError());
143 grpc_sockaddr_to_string(&addr_str, addr, 0);
144 gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
145 gpr_free(utf8_message);
146 gpr_free(addr_str);
147 goto error;
148 }
149
150 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
151 char *utf8_message = gpr_format_message(WSAGetLastError());
152 gpr_log(GPR_ERROR, "listen: %s", utf8_message);
153 gpr_free(utf8_message);
154 goto error;
155 }
156
157 sockname_len = sizeof(sockname_temp);
Craig Tillerc02c1d82015-04-07 16:21:55 -0700158 if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
159 SOCKET_ERROR) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100160 char *utf8_message = gpr_format_message(WSAGetLastError());
161 gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
162 gpr_free(utf8_message);
163 goto error;
164 }
165
Craig Tillerc02c1d82015-04-07 16:21:55 -0700166 return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100167
168error:
169 if (sock != INVALID_SOCKET) closesocket(sock);
170 return -1;
171}
172
173static void on_accept(void *arg, int success);
174
175static void start_accept(server_port *port) {
176 SOCKET sock = INVALID_SOCKET;
177 char *message;
178 char *utf8_message;
179 BOOL success;
180 DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
181 DWORD bytes_received = 0;
182
183 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
184 WSA_FLAG_OVERLAPPED);
185
186 if (sock == INVALID_SOCKET) {
187 message = "Unable to create socket: %s";
188 goto failure;
189 }
190
191 if (!grpc_tcp_prepare_socket(sock)) {
192 message = "Unable to prepare socket: %s";
193 goto failure;
194 }
195
196 success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
197 addrlen, addrlen, &bytes_received,
198 &port->socket->read_info.overlapped);
199
Jan Tattermusch5618a9d2015-04-21 18:10:16 -0700200 if (!success) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100201 int error = WSAGetLastError();
202 if (error != ERROR_IO_PENDING) {
203 message = "AcceptEx failed: %s";
204 goto failure;
205 }
206 }
207
208 port->new_socket = sock;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800209 grpc_socket_notify_on_read(port->socket, on_accept, port);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100210 return;
211
212failure:
213 utf8_message = gpr_format_message(WSAGetLastError());
214 gpr_log(GPR_ERROR, message, utf8_message);
215 gpr_free(utf8_message);
216 if (sock != INVALID_SOCKET) closesocket(sock);
217}
218
219/* event manager callback when reads are ready */
220static void on_accept(void *arg, int success) {
221 server_port *sp = arg;
222 SOCKET sock = sp->new_socket;
223 grpc_winsocket_callback_info *info = &sp->socket->read_info;
224 grpc_endpoint *ep = NULL;
225
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700226 if (sp->shutting_down) {
227 sp->shutting_down = 0;
228 gpr_mu_lock(&sp->server->mu);
229 if (0 == --sp->server->active_ports) {
230 gpr_cv_broadcast(&sp->server->cv);
231 }
232 gpr_mu_unlock(&sp->server->mu);
233 return;
234 }
235
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100236 if (success) {
237 DWORD transfered_bytes = 0;
238 DWORD flags;
239 BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
Craig Tillerc02c1d82015-04-07 16:21:55 -0700240 &transfered_bytes, FALSE, &flags);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100241 if (!wsa_success) {
242 char *utf8_message = gpr_format_message(WSAGetLastError());
243 gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
244 gpr_free(utf8_message);
245 closesocket(sock);
246 } else {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100247 ep = grpc_tcp_create(grpc_winsocket_create(sock));
248 }
249 } else {
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700250 sp->shutting_down = 1;
251 sp->new_socket = INVALID_SOCKET;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100252 closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100253 }
254
255 if (ep) sp->server->cb(sp->server->cb_arg, ep);
Jan Tattermusch638c1ee2015-04-21 17:14:44 -0700256 if (success) {
257 start_accept(sp);
258 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100259}
260
261static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
262 const struct sockaddr *addr, int addr_len) {
263 server_port *sp;
264 int port;
265 int status;
266 GUID guid = WSAID_ACCEPTEX;
267 DWORD ioctl_num_bytes;
268 LPFN_ACCEPTEX AcceptEx;
269
270 if (sock == INVALID_SOCKET) return -1;
271
Craig Tillerc02c1d82015-04-07 16:21:55 -0700272 status =
273 WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
274 &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100275
276 if (status != 0) {
277 char *utf8_message = gpr_format_message(WSAGetLastError());
278 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
279 gpr_free(utf8_message);
280 closesocket(sock);
281 return -1;
282 }
283
284 port = prepare_socket(sock, addr, addr_len);
285 if (port >= 0) {
286 gpr_mu_lock(&s->mu);
287 GPR_ASSERT(!s->cb && "must add ports before starting server");
288 /* append it to the list under a lock */
289 if (s->nports == s->port_capacity) {
290 s->port_capacity *= 2;
291 s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
292 }
293 sp = &s->ports[s->nports++];
294 sp->server = s;
295 sp->socket = grpc_winsocket_create(sock);
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700296 sp->shutting_down = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100297 sp->AcceptEx = AcceptEx;
298 GPR_ASSERT(sp->socket);
299 gpr_mu_unlock(&s->mu);
300 }
301
302 return port;
303}
304
305int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
306 int addr_len) {
307 int allocated_port = -1;
308 unsigned i;
309 SOCKET sock;
310 struct sockaddr_in6 addr6_v4mapped;
311 struct sockaddr_in6 wildcard;
312 struct sockaddr *allocated_addr = NULL;
313 struct sockaddr_storage sockname_temp;
314 socklen_t sockname_len;
315 int port;
316
317 /* Check if this is a wildcard port, and if so, try to keep the port the same
318 as some previously created listener. */
319 if (grpc_sockaddr_get_port(addr) == 0) {
320 for (i = 0; i < s->nports; i++) {
321 sockname_len = sizeof(sockname_temp);
322 if (0 == getsockname(s->ports[i].socket->socket,
Craig Tillerc02c1d82015-04-07 16:21:55 -0700323 (struct sockaddr *)&sockname_temp, &sockname_len)) {
324 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100325 if (port > 0) {
326 allocated_addr = malloc(addr_len);
327 memcpy(allocated_addr, addr, addr_len);
328 grpc_sockaddr_set_port(allocated_addr, port);
329 addr = allocated_addr;
330 break;
331 }
332 }
333 }
334 }
335
336 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
337 addr = (const struct sockaddr *)&addr6_v4mapped;
338 addr_len = sizeof(addr6_v4mapped);
339 }
340
341 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
342 if (grpc_sockaddr_is_wildcard(addr, &port)) {
343 grpc_sockaddr_make_wildcard6(port, &wildcard);
344
Craig Tillerc02c1d82015-04-07 16:21:55 -0700345 addr = (struct sockaddr *)&wildcard;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100346 addr_len = sizeof(wildcard);
347 }
348
349 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
350 WSA_FLAG_OVERLAPPED);
351 if (sock == INVALID_SOCKET) {
352 char *utf8_message = gpr_format_message(WSAGetLastError());
353 gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
354 gpr_free(utf8_message);
355 }
356
357 allocated_port = add_socket_to_server(s, sock, addr, addr_len);
358 gpr_free(allocated_addr);
359
360 return allocated_port;
361}
362
363SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
364 return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
365}
366
Nicolas "Pixel" Noble94964fd2015-02-21 07:19:19 +0100367void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
368 size_t pollset_count, grpc_tcp_server_cb cb,
369 void *cb_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100370 size_t i;
371 GPR_ASSERT(cb);
372 gpr_mu_lock(&s->mu);
373 GPR_ASSERT(!s->cb);
374 GPR_ASSERT(s->active_ports == 0);
375 s->cb = cb;
376 s->cb_arg = cb_arg;
377 for (i = 0; i < s->nports; i++) {
378 start_accept(s->ports + i);
379 s->active_ports++;
380 }
381 gpr_mu_unlock(&s->mu);
382}
383
Craig Tillerc02c1d82015-04-07 16:21:55 -0700384#endif /* GPR_WINSOCK_SOCKET */