blob: 21f19f0ba286ff493e74e2a0289fcfd6769c9fa0 [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 */
58typedef 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. */
61 gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
62 /* 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;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010070} server_port;
71
72/* the overall server */
73struct grpc_tcp_server {
74 grpc_tcp_server_cb cb;
75 void *cb_arg;
76
77 gpr_mu mu;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010078
79 /* active port count: how many ports are actually still listening */
80 int active_ports;
81
82 /* all listening ports */
83 server_port *ports;
84 size_t nports;
85 size_t port_capacity;
Craig Tiller063560e2015-09-01 08:44:42 -070086
87 /* shutdown callback */
88 void(*shutdown_complete)(void *);
89 void *shutdown_complete_arg;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010090};
91
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070092/* Public function. Allocates the proper data structures to hold a
93 grpc_tcp_server. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010094grpc_tcp_server *grpc_tcp_server_create(void) {
95 grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
96 gpr_mu_init(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010097 s->active_ports = 0;
98 s->cb = NULL;
99 s->cb_arg = NULL;
100 s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
101 s->nports = 0;
102 s->port_capacity = INIT_PORT_CAP;
Craig Tiller063560e2015-09-01 08:44:42 -0700103 s->shutdown_complete = NULL;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100104 return s;
105}
106
Craig Tiller063560e2015-09-01 08:44:42 -0700107static void dont_care_about_shutdown_completion(void *arg) {}
108
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700109/* Public function. Stops and destroys a grpc_tcp_server. */
Craig Tiller6d979162015-04-07 16:13:13 -0700110void grpc_tcp_server_destroy(grpc_tcp_server *s,
Craig Tiller063560e2015-09-01 08:44:42 -0700111 void (*shutdown_complete)(void *shutdown_done_arg),
112 void *shutdown_complete_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100113 size_t i;
Craig Tiller063560e2015-09-01 08:44:42 -0700114 int immediately_done = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100115 gpr_mu_lock(&s->mu);
Craig Tiller063560e2015-09-01 08:44:42 -0700116
117 s->shutdown_complete = shutdown_complete
118 ? shutdown_complete
119 : dont_care_about_shutdown_completion;
120 s->shutdown_complete_arg = shutdown_complete_arg;
121
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700122 /* First, shutdown all fd's. This will queue abortion calls for all
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200123 of the pending accepts due to the normal operation mechanism. */
Craig Tiller063560e2015-09-01 08:44:42 -0700124 if (s->active_ports == 0) {
125 immediately_done = 1;
126 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100127 for (i = 0; i < s->nports; i++) {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200128 server_port *sp = &s->ports[i];
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200129 sp->shutting_down = 1;
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700130 grpc_winsocket_shutdown(sp->socket);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100131 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100132 gpr_mu_unlock(&s->mu);
133
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700134 /* Now that the accepts have been aborted, we can destroy the sockets.
135 The IOCP won't get notified on these, so we can flag them as already
136 closed by the system. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100137 for (i = 0; i < s->nports; i++) {
138 server_port *sp = &s->ports[i];
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700139 grpc_winsocket_destroy(sp->socket);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100140 }
141 gpr_free(s->ports);
142 gpr_free(s);
Craig Tiller6d979162015-04-07 16:13:13 -0700143
Craig Tiller063560e2015-09-01 08:44:42 -0700144 if (immediately_done) {
145 s->shutdown_complete(s->shutdown_complete_arg);
Craig Tiller6d979162015-04-07 16:13:13 -0700146 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100147}
148
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700149/* Prepare (bind) a recently-created socket for listening. */
Craig Tillerc02c1d82015-04-07 16:21:55 -0700150static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
151 int addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100152 struct sockaddr_storage sockname_temp;
153 socklen_t sockname_len;
154
155 if (sock == INVALID_SOCKET) goto error;
156
157 if (!grpc_tcp_prepare_socket(sock)) {
158 char *utf8_message = gpr_format_message(WSAGetLastError());
159 gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
160 gpr_free(utf8_message);
161 goto error;
162 }
163
164 if (bind(sock, addr, addr_len) == SOCKET_ERROR) {
165 char *addr_str;
166 char *utf8_message = gpr_format_message(WSAGetLastError());
167 grpc_sockaddr_to_string(&addr_str, addr, 0);
168 gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
169 gpr_free(utf8_message);
170 gpr_free(addr_str);
171 goto error;
172 }
173
174 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
175 char *utf8_message = gpr_format_message(WSAGetLastError());
176 gpr_log(GPR_ERROR, "listen: %s", utf8_message);
177 gpr_free(utf8_message);
178 goto error;
179 }
180
181 sockname_len = sizeof(sockname_temp);
Craig Tillerc02c1d82015-04-07 16:21:55 -0700182 if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
183 SOCKET_ERROR) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100184 char *utf8_message = gpr_format_message(WSAGetLastError());
185 gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
186 gpr_free(utf8_message);
187 goto error;
188 }
189
Craig Tillerc02c1d82015-04-07 16:21:55 -0700190 return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100191
192error:
193 if (sock != INVALID_SOCKET) closesocket(sock);
194 return -1;
195}
196
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700197static void decrement_active_ports_and_notify(server_port *sp) {
Craig Tiller063560e2015-09-01 08:44:42 -0700198 void(*notify)(void *) = NULL;
199 void *notify_arg = NULL;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700200 sp->shutting_down = 0;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700201 gpr_mu_lock(&sp->server->mu);
202 GPR_ASSERT(sp->server->active_ports > 0);
203 if (0 == --sp->server->active_ports) {
Craig Tiller063560e2015-09-01 08:44:42 -0700204 notify = sp->server->shutdown_complete;
205 notify_arg = sp->server->shutdown_complete_arg;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700206 }
207 gpr_mu_unlock(&sp->server->mu);
Craig Tiller063560e2015-09-01 08:44:42 -0700208 if (notify != NULL) {
209 notify(notify_arg);
210 }
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700211}
212
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700213/* start_accept will reference that for the IOCP notification request. */
214static void on_accept(void *arg, int from_iocp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100215
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. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100218static void start_accept(server_port *port) {
219 SOCKET sock = INVALID_SOCKET;
220 char *message;
221 char *utf8_message;
222 BOOL success;
223 DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
224 DWORD bytes_received = 0;
225
226 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
227 WSA_FLAG_OVERLAPPED);
228
229 if (sock == INVALID_SOCKET) {
230 message = "Unable to create socket: %s";
231 goto failure;
232 }
233
234 if (!grpc_tcp_prepare_socket(sock)) {
235 message = "Unable to prepare socket: %s";
236 goto failure;
237 }
238
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700239 /* Start the "accept" asynchronously. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100240 success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
241 addrlen, addrlen, &bytes_received,
242 &port->socket->read_info.overlapped);
243
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. */
Jan Tattermusch5618a9d2015-04-21 18:10:16 -0700246 if (!success) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100247 int error = WSAGetLastError();
248 if (error != ERROR_IO_PENDING) {
249 message = "AcceptEx failed: %s";
250 goto failure;
251 }
252 }
253
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;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800257 grpc_socket_notify_on_read(port->socket, on_accept, port);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100258 return;
259
260failure:
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700261 if (port->shutting_down) {
262 /* We are abandoning the listener port, take that into account to prevent
Jan Tattermuschdd8a80f2015-08-04 11:05:56 -0700263 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. */
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700267 decrement_active_ports_and_notify(port);
Jan Tattermuschdd8a80f2015-08-04 11:05:56 -0700268 return;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700269 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100270 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);
274}
275
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700276/* Event manager callback when reads are ready. */
277static void on_accept(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;
285 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 */
294 if (!from_iocp) {
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700295 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,
299 and act accordingly. */
chai2010e55e1832015-07-14 13:24:48 +0800300 transfered_bytes = 0;
301 wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700302 &transfered_bytes, FALSE, &flags);
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200303 if (!wsa_success) {
304 if (sp->shutting_down) {
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700305 /* During the shutdown case, we ARE expecting an error. So that's well,
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200306 and we can wake up the shutdown thread. */
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700307 decrement_active_ports_and_notify(sp);
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200308 return;
309 } else {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100310 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 }
315 } else {
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200316 if (!sp->shutting_down) {
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700317 peer_name_string = NULL;
Jan Tattermuschd298a952015-07-24 13:45:56 -0700318 err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700319 (char *)&sp->socket->socket, sizeof(sp->socket->socket));
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700320 if (err) {
321 char *utf8_message = gpr_format_message(WSAGetLastError());
Jan Tattermuschd298a952015-07-24 13:45:56 -0700322 gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700323 gpr_free(utf8_message);
324 }
Craig Tillerd6c98df2015-08-18 09:33:44 -0700325 err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700326 if (!err) {
Craig Tillerd6c98df2015-08-18 09:33:44 -0700327 peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700328 } 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 }
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700333 gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
Jan Tattermuschd298a952015-07-24 13:45:56 -0700334 ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
335 peer_name_string);
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700336 gpr_free(fd_name);
337 gpr_free(peer_name_string);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200338 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100339 }
340
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. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100343 if (ep) sp->server->cb(sp->server->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. */
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200348 start_accept(sp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100349}
350
351static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
352 const struct sockaddr *addr, int addr_len) {
353 server_port *sp;
354 int port;
355 int status;
356 GUID guid = WSAID_ACCEPTEX;
357 DWORD ioctl_num_bytes;
358 LPFN_ACCEPTEX AcceptEx;
359
360 if (sock == INVALID_SOCKET) return -1;
361
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 Tillerc02c1d82015-04-07 16:21:55 -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
368 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 }
375
376 port = prepare_socket(sock, addr, addr_len);
377 if (port >= 0) {
378 gpr_mu_lock(&s->mu);
379 GPR_ASSERT(!s->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);
384 }
385 sp = &s->ports[s->nports++];
386 sp->server = s;
Craig Tiller33da3322015-06-02 10:29:40 -0700387 sp->socket = grpc_winsocket_create(sock, "listener");
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700388 sp->shutting_down = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100389 sp->AcceptEx = AcceptEx;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200390 sp->new_socket = INVALID_SOCKET;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100391 GPR_ASSERT(sp->socket);
392 gpr_mu_unlock(&s->mu);
393 }
394
395 return port;
396}
397
398int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
399 int addr_len) {
400 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. */
412 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,
Craig Tillerc02c1d82015-04-07 16:21:55 -0700416 (struct sockaddr *)&sockname_temp, &sockname_len)) {
417 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100418 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 }
426 }
427 }
428
429 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
430 addr = (const struct sockaddr *)&addr6_v4mapped;
431 addr_len = sizeof(addr6_v4mapped);
432 }
433
434 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
435 if (grpc_sockaddr_is_wildcard(addr, &port)) {
436 grpc_sockaddr_make_wildcard6(port, &wildcard);
437
Craig Tillerc02c1d82015-04-07 16:21:55 -0700438 addr = (struct sockaddr *)&wildcard;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100439 addr_len = sizeof(wildcard);
440 }
441
442 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 }
449
450 allocated_port = add_socket_to_server(s, sock, addr, addr_len);
451 gpr_free(allocated_addr);
452
453 return allocated_port;
454}
455
456SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
457 return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
458}
459
Nicolas "Pixel" Noble94964fd2015-02-21 07:19:19 +0100460void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
461 size_t pollset_count, grpc_tcp_server_cb cb,
462 void *cb_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100463 size_t i;
464 GPR_ASSERT(cb);
465 gpr_mu_lock(&s->mu);
466 GPR_ASSERT(!s->cb);
467 GPR_ASSERT(s->active_ports == 0);
468 s->cb = cb;
469 s->cb_arg = cb_arg;
470 for (i = 0; i < s->nports; i++) {
471 start_accept(s->ports + i);
472 s->active_ports++;
473 }
474 gpr_mu_unlock(&s->mu);
475}
476
Craig Tillerc02c1d82015-04-07 16:21:55 -0700477#endif /* GPR_WINSOCK_SOCKET */