blob: 55cd1a5d6eb5fba9ba74f9a775b7c599ba9fed1e [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 Tiller82f9bd82015-09-23 09:31:51 -0700201static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx, server_port *sp) {
Craig Tiller5100ea02015-09-01 12:23:28 -0700202 int notify = 0;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700203 sp->shutting_down = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700204 gpr_mu_lock(&sp->server->mu);
205 GPR_ASSERT(sp->server->active_ports > 0);
206 if (0 == --sp->server->active_ports &&
207 sp->server->shutdown_complete != NULL) {
208 notify = 1;
209 }
210 gpr_mu_unlock(&sp->server->mu);
211 if (notify) {
Craig Tiller82f9bd82015-09-23 09:31:51 -0700212 finish_shutdown(exec_ctx, sp->server);
Craig Tillera82950e2015-09-22 12:33:20 -0700213 }
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700214}
215
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700216/* In order to do an async accept, we need to create a socket first which
217 will be the one assigned to the new incoming connection. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700218static void start_accept(grpc_exec_ctx *exec_ctx, server_port *port) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100219 SOCKET sock = INVALID_SOCKET;
220 char *message;
221 char *utf8_message;
222 BOOL success;
Craig Tillera82950e2015-09-22 12:33:20 -0700223 DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100224 DWORD bytes_received = 0;
225
Craig Tillera82950e2015-09-22 12:33:20 -0700226 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
227 WSA_FLAG_OVERLAPPED);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100228
Craig Tillera82950e2015-09-22 12:33:20 -0700229 if (sock == INVALID_SOCKET) {
230 message = "Unable to create socket: %s";
231 goto failure;
232 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100233
Craig Tillera82950e2015-09-22 12:33:20 -0700234 if (!grpc_tcp_prepare_socket(sock)) {
235 message = "Unable to prepare socket: %s";
236 goto failure;
237 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100238
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700239 /* Start the "accept" asynchronously. */
Craig Tillera82950e2015-09-22 12:33:20 -0700240 success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
241 addrlen, addrlen, &bytes_received,
242 &port->socket->read_info.overlapped);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100243
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700244 /* It is possible to get an accept immediately without delay. However, we
245 will still get an IOCP notification for it. So let's just ignore it. */
Craig Tillera82950e2015-09-22 12:33:20 -0700246 if (!success) {
247 int error = WSAGetLastError();
248 if (error != ERROR_IO_PENDING) {
249 message = "AcceptEx failed: %s";
250 goto failure;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100251 }
Craig Tillera82950e2015-09-22 12:33:20 -0700252 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100253
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700254 /* We're ready to do the accept. Calling grpc_socket_notify_on_read may
255 immediately process an accept that happened in the meantime. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100256 port->new_socket = sock;
Craig Tiller82f9bd82015-09-23 09:31:51 -0700257 grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100258 return;
259
260failure:
Craig Tillera82950e2015-09-22 12:33:20 -0700261 if (port->shutting_down) {
262 /* We are abandoning the listener port, take that into account to prevent
263 occasional hangs on shutdown. The hang happens when sp->shutting_down
264 change is not seen by on_accept and we proceed to trying new accept,
265 but we fail there because the listening port has been closed in the
266 meantime. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700267 decrement_active_ports_and_notify(exec_ctx, port);
Craig Tillera82950e2015-09-22 12:33:20 -0700268 return;
269 }
270 utf8_message = gpr_format_message(WSAGetLastError());
271 gpr_log(GPR_ERROR, message, utf8_message);
272 gpr_free(utf8_message);
273 if (sock != INVALID_SOCKET) closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100274}
275
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700276/* Event manager callback when reads are ready. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700277static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100278 server_port *sp = arg;
279 SOCKET sock = sp->new_socket;
280 grpc_winsocket_callback_info *info = &sp->socket->read_info;
281 grpc_endpoint *ep = NULL;
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700282 struct sockaddr_storage peer_name;
283 char *peer_name_string;
284 char *fd_name;
Craig Tillera82950e2015-09-22 12:33:20 -0700285 int peer_name_len = sizeof(peer_name);
chai2010e55e1832015-07-14 13:24:48 +0800286 DWORD transfered_bytes;
287 DWORD flags;
288 BOOL wsa_success;
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700289 int err;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100290
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200291 /* The general mechanism for shutting down is to queue abortion calls. While
292 this is necessary in the read/write case, it's useless for the accept
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700293 case. We only need to adjust the pending callback count */
Craig Tillera82950e2015-09-22 12:33:20 -0700294 if (!from_iocp) {
295 return;
296 }
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700297
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200298 /* The IOCP notified us of a completed operation. Let's grab the results,
Craig Tiller45724b32015-09-22 10:42:19 -0700299 and act accordingly. */
chai2010e55e1832015-07-14 13:24:48 +0800300 transfered_bytes = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700301 wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
302 &transfered_bytes, FALSE, &flags);
303 if (!wsa_success) {
304 if (sp->shutting_down) {
305 /* During the shutdown case, we ARE expecting an error. So that's well,
306 and we can wake up the shutdown thread. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700307 decrement_active_ports_and_notify(exec_ctx, sp);
Craig Tillera82950e2015-09-22 12:33:20 -0700308 return;
309 } else {
310 char *utf8_message = gpr_format_message(WSAGetLastError());
311 gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
312 gpr_free(utf8_message);
313 closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100314 }
Craig Tillera82950e2015-09-22 12:33:20 -0700315 } else {
316 if (!sp->shutting_down) {
317 peer_name_string = NULL;
318 err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
319 (char *)&sp->socket->socket, sizeof(sp->socket->socket));
320 if (err) {
321 char *utf8_message = gpr_format_message(WSAGetLastError());
322 gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
323 gpr_free(utf8_message);
324 }
325 err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
326 if (!err) {
327 peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
328 } else {
329 char *utf8_message = gpr_format_message(WSAGetLastError());
330 gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
331 gpr_free(utf8_message);
332 }
333 gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
334 ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
335 peer_name_string);
336 gpr_free(fd_name);
337 gpr_free(peer_name_string);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200338 }
Craig Tillera82950e2015-09-22 12:33:20 -0700339 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100340
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700341 /* The only time we should call our callback, is where we successfully
342 managed to accept a connection, and created an endpoint. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700343 if (ep) sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200344 /* As we were notified from the IOCP of one and exactly one accept,
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200345 the former socked we created has now either been destroy or assigned
346 to the new connection. We need to create a new one for the next
347 connection. */
Craig Tiller82f9bd82015-09-23 09:31:51 -0700348 start_accept(exec_ctx, sp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100349}
350
Craig Tillera82950e2015-09-22 12:33:20 -0700351static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
Jan Tattermusch48e57fa2015-09-21 13:43:54 -0700352 const struct sockaddr *addr, size_t addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100353 server_port *sp;
354 int port;
355 int status;
356 GUID guid = WSAID_ACCEPTEX;
357 DWORD ioctl_num_bytes;
358 LPFN_ACCEPTEX AcceptEx;
359
Craig Tillera82950e2015-09-22 12:33:20 -0700360 if (sock == INVALID_SOCKET) return -1;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100361
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700362 /* We need to grab the AcceptEx pointer for that port, as it may be
363 interface-dependent. We'll cache it to avoid doing that again. */
Craig Tillera82950e2015-09-22 12:33:20 -0700364 status =
365 WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
366 &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100367
Craig Tillera82950e2015-09-22 12:33:20 -0700368 if (status != 0) {
369 char *utf8_message = gpr_format_message(WSAGetLastError());
370 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
371 gpr_free(utf8_message);
372 closesocket(sock);
373 return -1;
374 }
Craig Tiller45724b32015-09-22 10:42:19 -0700375
Craig Tillera82950e2015-09-22 12:33:20 -0700376 port = prepare_socket(sock, addr, addr_len);
377 if (port >= 0) {
378 gpr_mu_lock(&s->mu);
379 GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
380 /* append it to the list under a lock */
381 if (s->nports == s->port_capacity) {
382 s->port_capacity *= 2;
383 s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
Craig Tiller45724b32015-09-22 10:42:19 -0700384 }
Craig Tillera82950e2015-09-22 12:33:20 -0700385 sp = &s->ports[s->nports++];
386 sp->server = s;
387 sp->socket = grpc_winsocket_create(sock, "listener");
388 sp->shutting_down = 0;
389 sp->AcceptEx = AcceptEx;
390 sp->new_socket = INVALID_SOCKET;
391 GPR_ASSERT(sp->socket);
392 gpr_mu_unlock(&s->mu);
393 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100394
395 return port;
396}
397
Craig Tillera82950e2015-09-22 12:33:20 -0700398int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
Craig Tiller82f9bd82015-09-23 09:31:51 -0700399 size_t addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100400 int allocated_port = -1;
401 unsigned i;
402 SOCKET sock;
403 struct sockaddr_in6 addr6_v4mapped;
404 struct sockaddr_in6 wildcard;
405 struct sockaddr *allocated_addr = NULL;
406 struct sockaddr_storage sockname_temp;
407 socklen_t sockname_len;
408 int port;
409
410 /* Check if this is a wildcard port, and if so, try to keep the port the same
411 as some previously created listener. */
Craig Tillera82950e2015-09-22 12:33:20 -0700412 if (grpc_sockaddr_get_port(addr) == 0) {
413 for (i = 0; i < s->nports; i++) {
414 sockname_len = sizeof(sockname_temp);
415 if (0 == getsockname(s->ports[i].socket->socket,
416 (struct sockaddr *)&sockname_temp, &sockname_len)) {
417 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
418 if (port > 0) {
419 allocated_addr = malloc(addr_len);
420 memcpy(allocated_addr, addr, addr_len);
421 grpc_sockaddr_set_port(allocated_addr, port);
422 addr = allocated_addr;
423 break;
424 }
425 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100426 }
Craig Tillera82950e2015-09-22 12:33:20 -0700427 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100428
Craig Tillera82950e2015-09-22 12:33:20 -0700429 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
430 addr = (const struct sockaddr *)&addr6_v4mapped;
431 addr_len = sizeof(addr6_v4mapped);
432 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100433
434 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
Craig Tillera82950e2015-09-22 12:33:20 -0700435 if (grpc_sockaddr_is_wildcard(addr, &port)) {
436 grpc_sockaddr_make_wildcard6(port, &wildcard);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100437
Craig Tillera82950e2015-09-22 12:33:20 -0700438 addr = (struct sockaddr *)&wildcard;
439 addr_len = sizeof(wildcard);
440 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100441
Craig Tillera82950e2015-09-22 12:33:20 -0700442 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
443 WSA_FLAG_OVERLAPPED);
444 if (sock == INVALID_SOCKET) {
445 char *utf8_message = gpr_format_message(WSAGetLastError());
446 gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
447 gpr_free(utf8_message);
448 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100449
Craig Tillera82950e2015-09-22 12:33:20 -0700450 allocated_port = add_socket_to_server(s, sock, addr, addr_len);
451 gpr_free(allocated_addr);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100452
453 return allocated_port;
454}
455
Craig Tiller45724b32015-09-22 10:42:19 -0700456SOCKET
Craig Tillera82950e2015-09-22 12:33:20 -0700457grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100458 return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
459}
460
Craig Tiller82f9bd82015-09-23 09:31:51 -0700461void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
462 grpc_pollset **pollset,
Craig Tillera82950e2015-09-22 12:33:20 -0700463 size_t pollset_count,
464 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 */