blob: 7244606e98c559bdf647add9dd5aa7300b09eb32 [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>
Masood Malekghassemi701af602015-06-03 15:01:17 -070044#include <grpc/support/string_util.h>
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010045#include <grpc/support/sync.h>
46#include <grpc/support/time.h>
47
Nicolas Nobled72ba6a2015-02-09 16:30:35 -080048#include "src/core/iomgr/iocp_windows.h"
49#include "src/core/iomgr/pollset_windows.h"
50#include "src/core/iomgr/socket_windows.h"
51#include "src/core/iomgr/tcp_server.h"
52#include "src/core/iomgr/tcp_windows.h"
53
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010054#define INIT_PORT_CAP 2
55#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
56
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010057/* one listening port */
Craig Tillera82950e2015-09-22 12:33:20 -070058typedef struct server_port {
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070059 /* This seemingly magic number comes from AcceptEx's documentation. each
60 address buffer needs to have at least 16 more bytes at their end. */
Craig Tillera82950e2015-09-22 12:33:20 -070061 gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070062 /* This will hold the socket for the next accept. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010063 SOCKET new_socket;
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070064 /* The listener winsocked. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010065 grpc_winsocket *socket;
66 grpc_tcp_server *server;
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070067 /* The cached AcceptEx for that port. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010068 LPFN_ACCEPTEX AcceptEx;
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -070069 int shutting_down;
Craig Tiller82f9bd82015-09-23 09:31:51 -070070 /* closure for socket notification of accept being ready */
71 grpc_closure on_accept;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010072} server_port;
73
74/* the overall server */
Craig Tillera82950e2015-09-22 12:33:20 -070075struct grpc_tcp_server {
Robbie Shade3cd2d182015-08-28 14:30:35 -040076 /* Called whenever accept() succeeds on a server port. */
77 grpc_tcp_server_cb on_accept_cb;
78 void *on_accept_cb_arg;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010079
80 gpr_mu mu;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010081
82 /* active port count: how many ports are actually still listening */
83 int active_ports;
84
85 /* all listening ports */
86 server_port *ports;
87 size_t nports;
88 size_t port_capacity;
Craig Tiller063560e2015-09-01 08:44:42 -070089
90 /* shutdown callback */
Craig Tiller82f9bd82015-09-23 09:31:51 -070091 grpc_closure *shutdown_complete;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010092};
93
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070094/* Public function. Allocates the proper data structures to hold a
95 grpc_tcp_server. */
Craig Tillera82950e2015-09-22 12:33:20 -070096grpc_tcp_server *grpc_tcp_server_create(void) {
97 grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
98 gpr_mu_init(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010099 s->active_ports = 0;
Robbie Shade3cd2d182015-08-28 14:30:35 -0400100 s->on_accept_cb = NULL;
101 s->on_accept_cb_arg = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700102 s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100103 s->nports = 0;
104 s->port_capacity = INIT_PORT_CAP;
Craig Tiller063560e2015-09-01 08:44:42 -0700105 s->shutdown_complete = NULL;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100106 return s;
107}
108
Craig Tillera82950e2015-09-22 12:33:20 -0700109static void dont_care_about_shutdown_completion(void *arg) {}
Craig Tiller063560e2015-09-01 08:44:42 -0700110
Craig Tiller82f9bd82015-09-23 09:31:51 -0700111static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Craig Tiller5100ea02015-09-01 12:23:28 -0700112 size_t i;
113
Craig Tiller82f9bd82015-09-23 09:31:51 -0700114 grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1);
Craig Tiller5100ea02015-09-01 12:23:28 -0700115
116 /* Now that the accepts have been aborted, we can destroy the sockets.
Craig Tiller45724b32015-09-22 10:42:19 -0700117 The IOCP won't get notified on these, so we can flag them as already
118 closed by the system. */
Craig Tillera82950e2015-09-22 12:33:20 -0700119 for (i = 0; i < s->nports; i++) {
120 server_port *sp = &s->ports[i];
121 grpc_winsocket_destroy(sp->socket);
122 }
123 gpr_free(s->ports);
124 gpr_free(s);
Craig Tiller5100ea02015-09-01 12:23:28 -0700125}
126
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700127/* Public function. Stops and destroys a grpc_tcp_server. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700128void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
129 grpc_closure *shutdown_complete) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100130 size_t i;
Craig Tiller063560e2015-09-01 08:44:42 -0700131 int immediately_done = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700132 gpr_mu_lock(&s->mu);
Craig Tiller063560e2015-09-01 08:44:42 -0700133
Craig Tiller82f9bd82015-09-23 09:31:51 -0700134 s->shutdown_complete = shutdown_complete;
Craig Tiller063560e2015-09-01 08:44:42 -0700135
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700136 /* First, shutdown all fd's. This will queue abortion calls for all
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200137 of the pending accepts due to the normal operation mechanism. */
Craig Tillera82950e2015-09-22 12:33:20 -0700138 if (s->active_ports == 0) {
139 immediately_done = 1;
140 }
141 for (i = 0; i < s->nports; i++) {
142 server_port *sp = &s->ports[i];
143 sp->shutting_down = 1;
144 grpc_winsocket_shutdown(sp->socket);
145 }
146 gpr_mu_unlock(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100147
Craig Tillera82950e2015-09-22 12:33:20 -0700148 if (immediately_done) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700149 finish_shutdown(exec_ctx, s);
Craig Tillera82950e2015-09-22 12:33:20 -0700150 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100151}
152
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700153/* Prepare (bind) a recently-created socket for listening. */
Craig Tillera82950e2015-09-22 12:33:20 -0700154static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
Jan Tattermusch48e57fa2015-09-21 13:43:54 -0700155 size_t addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100156 struct sockaddr_storage sockname_temp;
157 socklen_t sockname_len;
158
Craig Tillera82950e2015-09-22 12:33:20 -0700159 if (sock == INVALID_SOCKET) goto error;
160
161 if (!grpc_tcp_prepare_socket(sock)) {
162 char *utf8_message = gpr_format_message(WSAGetLastError());
163 gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
164 gpr_free(utf8_message);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100165 goto error;
Craig Tillera82950e2015-09-22 12:33:20 -0700166 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100167
Jan Tattermusch48e57fa2015-09-21 13:43:54 -0700168 if (bind(sock, addr, (int)addr_len) == SOCKET_ERROR) {
Craig Tillera82950e2015-09-22 12:33:20 -0700169 char *addr_str;
170 char *utf8_message = gpr_format_message(WSAGetLastError());
171 grpc_sockaddr_to_string(&addr_str, addr, 0);
172 gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
173 gpr_free(utf8_message);
174 gpr_free(addr_str);
175 goto error;
176 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100177
Craig Tillera82950e2015-09-22 12:33:20 -0700178 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
179 char *utf8_message = gpr_format_message(WSAGetLastError());
180 gpr_log(GPR_ERROR, "listen: %s", utf8_message);
181 gpr_free(utf8_message);
182 goto error;
183 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100184
Craig Tillera82950e2015-09-22 12:33:20 -0700185 sockname_len = sizeof(sockname_temp);
186 if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
187 SOCKET_ERROR) {
188 char *utf8_message = gpr_format_message(WSAGetLastError());
189 gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
190 gpr_free(utf8_message);
191 goto error;
192 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100193
Craig Tillera82950e2015-09-22 12:33:20 -0700194 return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100195
196error:
Craig Tillera82950e2015-09-22 12:33:20 -0700197 if (sock != INVALID_SOCKET) closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100198 return -1;
199}
200
Craig Tiller565b18b2015-09-23 10:09:42 -0700201static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
202 server_port *sp) {
Craig Tiller5100ea02015-09-01 12:23:28 -0700203 int notify = 0;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700204 sp->shutting_down = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700205 gpr_mu_lock(&sp->server->mu);
206 GPR_ASSERT(sp->server->active_ports > 0);
207 if (0 == --sp->server->active_ports &&
208 sp->server->shutdown_complete != NULL) {
209 notify = 1;
210 }
211 gpr_mu_unlock(&sp->server->mu);
212 if (notify) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700213 finish_shutdown(exec_ctx, sp->server);
Craig Tillera82950e2015-09-22 12:33:20 -0700214 }
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700215}
216
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700217/* In order to do an async accept, we need to create a socket first which
218 will be the one assigned to the new incoming connection. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700219static void start_accept(grpc_exec_ctx *exec_ctx, server_port *port) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100220 SOCKET sock = INVALID_SOCKET;
221 char *message;
222 char *utf8_message;
223 BOOL success;
Craig Tillera82950e2015-09-22 12:33:20 -0700224 DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100225 DWORD bytes_received = 0;
226
Craig Tillera82950e2015-09-22 12:33:20 -0700227 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
228 WSA_FLAG_OVERLAPPED);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100229
Craig Tillera82950e2015-09-22 12:33:20 -0700230 if (sock == INVALID_SOCKET) {
231 message = "Unable to create socket: %s";
232 goto failure;
233 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100234
Craig Tillera82950e2015-09-22 12:33:20 -0700235 if (!grpc_tcp_prepare_socket(sock)) {
236 message = "Unable to prepare socket: %s";
237 goto failure;
238 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100239
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700240 /* Start the "accept" asynchronously. */
Craig Tillera82950e2015-09-22 12:33:20 -0700241 success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
242 addrlen, addrlen, &bytes_received,
243 &port->socket->read_info.overlapped);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100244
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700245 /* It is possible to get an accept immediately without delay. However, we
246 will still get an IOCP notification for it. So let's just ignore it. */
Craig Tillera82950e2015-09-22 12:33:20 -0700247 if (!success) {
248 int error = WSAGetLastError();
249 if (error != ERROR_IO_PENDING) {
250 message = "AcceptEx failed: %s";
251 goto failure;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100252 }
Craig Tillera82950e2015-09-22 12:33:20 -0700253 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100254
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700255 /* We're ready to do the accept. Calling grpc_socket_notify_on_read may
256 immediately process an accept that happened in the meantime. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100257 port->new_socket = sock;
Craig Tiller82f9bd82015-09-23 09:31:51 -0700258 grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100259 return;
260
261failure:
Craig Tillera82950e2015-09-22 12:33:20 -0700262 if (port->shutting_down) {
263 /* We are abandoning the listener port, take that into account to prevent
264 occasional hangs on shutdown. The hang happens when sp->shutting_down
265 change is not seen by on_accept and we proceed to trying new accept,
266 but we fail there because the listening port has been closed in the
267 meantime. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700268 decrement_active_ports_and_notify(exec_ctx, port);
Craig Tillera82950e2015-09-22 12:33:20 -0700269 return;
270 }
271 utf8_message = gpr_format_message(WSAGetLastError());
272 gpr_log(GPR_ERROR, message, utf8_message);
273 gpr_free(utf8_message);
274 if (sock != INVALID_SOCKET) closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100275}
276
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700277/* Event manager callback when reads are ready. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700278static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100279 server_port *sp = arg;
280 SOCKET sock = sp->new_socket;
281 grpc_winsocket_callback_info *info = &sp->socket->read_info;
282 grpc_endpoint *ep = NULL;
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700283 struct sockaddr_storage peer_name;
284 char *peer_name_string;
285 char *fd_name;
Craig Tillera82950e2015-09-22 12:33:20 -0700286 int peer_name_len = sizeof(peer_name);
chai2010e55e1832015-07-14 13:24:48 +0800287 DWORD transfered_bytes;
288 DWORD flags;
289 BOOL wsa_success;
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700290 int err;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100291
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200292 /* The general mechanism for shutting down is to queue abortion calls. While
293 this is necessary in the read/write case, it's useless for the accept
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700294 case. We only need to adjust the pending callback count */
Craig Tillera82950e2015-09-22 12:33:20 -0700295 if (!from_iocp) {
296 return;
297 }
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700298
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200299 /* The IOCP notified us of a completed operation. Let's grab the results,
Craig Tiller45724b32015-09-22 10:42:19 -0700300 and act accordingly. */
chai2010e55e1832015-07-14 13:24:48 +0800301 transfered_bytes = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700302 wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
303 &transfered_bytes, FALSE, &flags);
304 if (!wsa_success) {
305 if (sp->shutting_down) {
306 /* During the shutdown case, we ARE expecting an error. So that's well,
307 and we can wake up the shutdown thread. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700308 decrement_active_ports_and_notify(exec_ctx, sp);
Craig Tillera82950e2015-09-22 12:33:20 -0700309 return;
310 } else {
311 char *utf8_message = gpr_format_message(WSAGetLastError());
312 gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
313 gpr_free(utf8_message);
314 closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100315 }
Craig Tillera82950e2015-09-22 12:33:20 -0700316 } else {
317 if (!sp->shutting_down) {
318 peer_name_string = NULL;
319 err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
320 (char *)&sp->socket->socket, sizeof(sp->socket->socket));
321 if (err) {
322 char *utf8_message = gpr_format_message(WSAGetLastError());
323 gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
324 gpr_free(utf8_message);
325 }
326 err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
327 if (!err) {
328 peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
329 } else {
330 char *utf8_message = gpr_format_message(WSAGetLastError());
331 gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
332 gpr_free(utf8_message);
333 }
334 gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
335 ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
336 peer_name_string);
337 gpr_free(fd_name);
338 gpr_free(peer_name_string);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200339 }
Craig Tillera82950e2015-09-22 12:33:20 -0700340 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100341
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700342 /* The only time we should call our callback, is where we successfully
343 managed to accept a connection, and created an endpoint. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700344 if (ep) sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200345 /* As we were notified from the IOCP of one and exactly one accept,
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200346 the former socked we created has now either been destroy or assigned
347 to the new connection. We need to create a new one for the next
348 connection. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700349 start_accept(exec_ctx, sp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100350}
351
Craig Tillera82950e2015-09-22 12:33:20 -0700352static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
Jan Tattermusch48e57fa2015-09-21 13:43:54 -0700353 const struct sockaddr *addr, size_t addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100354 server_port *sp;
355 int port;
356 int status;
357 GUID guid = WSAID_ACCEPTEX;
358 DWORD ioctl_num_bytes;
359 LPFN_ACCEPTEX AcceptEx;
360
Craig Tillera82950e2015-09-22 12:33:20 -0700361 if (sock == INVALID_SOCKET) return -1;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100362
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700363 /* We need to grab the AcceptEx pointer for that port, as it may be
364 interface-dependent. We'll cache it to avoid doing that again. */
Craig Tillera82950e2015-09-22 12:33:20 -0700365 status =
366 WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
367 &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100368
Craig Tillera82950e2015-09-22 12:33:20 -0700369 if (status != 0) {
370 char *utf8_message = gpr_format_message(WSAGetLastError());
371 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
372 gpr_free(utf8_message);
373 closesocket(sock);
374 return -1;
375 }
Craig Tiller45724b32015-09-22 10:42:19 -0700376
Craig Tillera82950e2015-09-22 12:33:20 -0700377 port = prepare_socket(sock, addr, addr_len);
378 if (port >= 0) {
379 gpr_mu_lock(&s->mu);
380 GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
381 /* append it to the list under a lock */
382 if (s->nports == s->port_capacity) {
383 s->port_capacity *= 2;
384 s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
Craig Tiller45724b32015-09-22 10:42:19 -0700385 }
Craig Tillera82950e2015-09-22 12:33:20 -0700386 sp = &s->ports[s->nports++];
387 sp->server = s;
388 sp->socket = grpc_winsocket_create(sock, "listener");
389 sp->shutting_down = 0;
390 sp->AcceptEx = AcceptEx;
391 sp->new_socket = INVALID_SOCKET;
392 GPR_ASSERT(sp->socket);
393 gpr_mu_unlock(&s->mu);
394 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100395
396 return port;
397}
398
Craig Tillera82950e2015-09-22 12:33:20 -0700399int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
Craig Tiller82f9bd82015-09-23 09:31:51 -0700400 size_t addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100401 int allocated_port = -1;
402 unsigned i;
403 SOCKET sock;
404 struct sockaddr_in6 addr6_v4mapped;
405 struct sockaddr_in6 wildcard;
406 struct sockaddr *allocated_addr = NULL;
407 struct sockaddr_storage sockname_temp;
408 socklen_t sockname_len;
409 int port;
410
411 /* Check if this is a wildcard port, and if so, try to keep the port the same
412 as some previously created listener. */
Craig Tillera82950e2015-09-22 12:33:20 -0700413 if (grpc_sockaddr_get_port(addr) == 0) {
414 for (i = 0; i < s->nports; i++) {
415 sockname_len = sizeof(sockname_temp);
416 if (0 == getsockname(s->ports[i].socket->socket,
417 (struct sockaddr *)&sockname_temp, &sockname_len)) {
418 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
419 if (port > 0) {
420 allocated_addr = malloc(addr_len);
421 memcpy(allocated_addr, addr, addr_len);
422 grpc_sockaddr_set_port(allocated_addr, port);
423 addr = allocated_addr;
424 break;
425 }
426 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100427 }
Craig Tillera82950e2015-09-22 12:33:20 -0700428 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100429
Craig Tillera82950e2015-09-22 12:33:20 -0700430 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
431 addr = (const struct sockaddr *)&addr6_v4mapped;
432 addr_len = sizeof(addr6_v4mapped);
433 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100434
435 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
Craig Tillera82950e2015-09-22 12:33:20 -0700436 if (grpc_sockaddr_is_wildcard(addr, &port)) {
437 grpc_sockaddr_make_wildcard6(port, &wildcard);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100438
Craig Tillera82950e2015-09-22 12:33:20 -0700439 addr = (struct sockaddr *)&wildcard;
440 addr_len = sizeof(wildcard);
441 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100442
Craig Tillera82950e2015-09-22 12:33:20 -0700443 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
444 WSA_FLAG_OVERLAPPED);
445 if (sock == INVALID_SOCKET) {
446 char *utf8_message = gpr_format_message(WSAGetLastError());
447 gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
448 gpr_free(utf8_message);
449 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100450
Craig Tillera82950e2015-09-22 12:33:20 -0700451 allocated_port = add_socket_to_server(s, sock, addr, addr_len);
452 gpr_free(allocated_addr);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100453
454 return allocated_port;
455}
456
Craig Tiller45724b32015-09-22 10:42:19 -0700457SOCKET
Craig Tillera82950e2015-09-22 12:33:20 -0700458grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100459 return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
460}
461
Craig Tiller565b18b2015-09-23 10:09:42 -0700462void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
463 grpc_pollset **pollset, size_t pollset_count,
Craig Tillera82950e2015-09-22 12:33:20 -0700464 grpc_tcp_server_cb on_accept_cb,
465 void *on_accept_cb_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100466 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700467 GPR_ASSERT(on_accept_cb);
468 gpr_mu_lock(&s->mu);
469 GPR_ASSERT(!s->on_accept_cb);
470 GPR_ASSERT(s->active_ports == 0);
Robbie Shade3cd2d182015-08-28 14:30:35 -0400471 s->on_accept_cb = on_accept_cb;
472 s->on_accept_cb_arg = on_accept_cb_arg;
Craig Tillera82950e2015-09-22 12:33:20 -0700473 for (i = 0; i < s->nports; i++) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700474 start_accept(exec_ctx, s->ports + i);
Craig Tillera82950e2015-09-22 12:33:20 -0700475 s->active_ports++;
476 }
477 gpr_mu_unlock(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100478}
479
Craig Tillerc02c1d82015-04-07 16:21:55 -0700480#endif /* GPR_WINSOCK_SOCKET */