blob: b513d854aae183d5650701abb6ae2821d3a094f2 [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
Craig Tiller5100ea02015-09-01 12:23:28 -0700109static void finish_shutdown(grpc_tcp_server *s) {
110 size_t i;
111
112 s->shutdown_complete(s->shutdown_complete_arg);
113
114 /* Now that the accepts have been aborted, we can destroy the sockets.
115 The IOCP won't get notified on these, so we can flag them as already
116 closed by the system. */
117 for (i = 0; i < s->nports; i++) {
118 server_port *sp = &s->ports[i];
119 grpc_winsocket_destroy(sp->socket);
120 }
121 gpr_free(s->ports);
122 gpr_free(s);
123}
124
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700125/* Public function. Stops and destroys a grpc_tcp_server. */
Craig Tiller6d979162015-04-07 16:13:13 -0700126void grpc_tcp_server_destroy(grpc_tcp_server *s,
Craig Tiller063560e2015-09-01 08:44:42 -0700127 void (*shutdown_complete)(void *shutdown_done_arg),
128 void *shutdown_complete_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100129 size_t i;
Craig Tiller063560e2015-09-01 08:44:42 -0700130 int immediately_done = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100131 gpr_mu_lock(&s->mu);
Craig Tiller063560e2015-09-01 08:44:42 -0700132
133 s->shutdown_complete = shutdown_complete
134 ? shutdown_complete
135 : dont_care_about_shutdown_completion;
136 s->shutdown_complete_arg = shutdown_complete_arg;
137
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700138 /* First, shutdown all fd's. This will queue abortion calls for all
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200139 of the pending accepts due to the normal operation mechanism. */
Craig Tiller063560e2015-09-01 08:44:42 -0700140 if (s->active_ports == 0) {
141 immediately_done = 1;
142 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100143 for (i = 0; i < s->nports; i++) {
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200144 server_port *sp = &s->ports[i];
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200145 sp->shutting_down = 1;
Craig Tiller9f80fcf2015-08-28 08:22:48 -0700146 grpc_winsocket_shutdown(sp->socket);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100147 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100148 gpr_mu_unlock(&s->mu);
149
Craig Tiller063560e2015-09-01 08:44:42 -0700150 if (immediately_done) {
Craig Tiller5100ea02015-09-01 12:23:28 -0700151 finish_shutdown(s);
Craig Tiller6d979162015-04-07 16:13:13 -0700152 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100153}
154
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700155/* Prepare (bind) a recently-created socket for listening. */
Craig Tillerc02c1d82015-04-07 16:21:55 -0700156static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
157 int addr_len) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100158 struct sockaddr_storage sockname_temp;
159 socklen_t sockname_len;
160
161 if (sock == INVALID_SOCKET) goto error;
162
163 if (!grpc_tcp_prepare_socket(sock)) {
164 char *utf8_message = gpr_format_message(WSAGetLastError());
165 gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
166 gpr_free(utf8_message);
167 goto error;
168 }
169
170 if (bind(sock, addr, addr_len) == SOCKET_ERROR) {
171 char *addr_str;
172 char *utf8_message = gpr_format_message(WSAGetLastError());
173 grpc_sockaddr_to_string(&addr_str, addr, 0);
174 gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
175 gpr_free(utf8_message);
176 gpr_free(addr_str);
177 goto error;
178 }
179
180 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
181 char *utf8_message = gpr_format_message(WSAGetLastError());
182 gpr_log(GPR_ERROR, "listen: %s", utf8_message);
183 gpr_free(utf8_message);
184 goto error;
185 }
186
187 sockname_len = sizeof(sockname_temp);
Craig Tillerc02c1d82015-04-07 16:21:55 -0700188 if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
189 SOCKET_ERROR) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100190 char *utf8_message = gpr_format_message(WSAGetLastError());
191 gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
192 gpr_free(utf8_message);
193 goto error;
194 }
195
Craig Tillerc02c1d82015-04-07 16:21:55 -0700196 return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100197
198error:
199 if (sock != INVALID_SOCKET) closesocket(sock);
200 return -1;
201}
202
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700203static void decrement_active_ports_and_notify(server_port *sp) {
Craig Tiller5100ea02015-09-01 12:23:28 -0700204 int notify = 0;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700205 sp->shutting_down = 0;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700206 gpr_mu_lock(&sp->server->mu);
207 GPR_ASSERT(sp->server->active_ports > 0);
Craig Tiller5100ea02015-09-01 12:23:28 -0700208 if (0 == --sp->server->active_ports && sp->server->shutdown_complete != NULL) {
209 notify = 1;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700210 }
211 gpr_mu_unlock(&sp->server->mu);
Craig Tiller5100ea02015-09-01 12:23:28 -0700212 if (notify) {
213 finish_shutdown(sp->server);
Craig Tiller063560e2015-09-01 08:44:42 -0700214 }
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700215}
216
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700217/* start_accept will reference that for the IOCP notification request. */
218static void on_accept(void *arg, int from_iocp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100219
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700220/* In order to do an async accept, we need to create a socket first which
221 will be the one assigned to the new incoming connection. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100222static void start_accept(server_port *port) {
223 SOCKET sock = INVALID_SOCKET;
224 char *message;
225 char *utf8_message;
226 BOOL success;
227 DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
228 DWORD bytes_received = 0;
229
230 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
231 WSA_FLAG_OVERLAPPED);
232
233 if (sock == INVALID_SOCKET) {
234 message = "Unable to create socket: %s";
235 goto failure;
236 }
237
238 if (!grpc_tcp_prepare_socket(sock)) {
239 message = "Unable to prepare socket: %s";
240 goto failure;
241 }
242
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700243 /* Start the "accept" asynchronously. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100244 success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
245 addrlen, addrlen, &bytes_received,
246 &port->socket->read_info.overlapped);
247
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700248 /* It is possible to get an accept immediately without delay. However, we
249 will still get an IOCP notification for it. So let's just ignore it. */
Jan Tattermusch5618a9d2015-04-21 18:10:16 -0700250 if (!success) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100251 int error = WSAGetLastError();
252 if (error != ERROR_IO_PENDING) {
253 message = "AcceptEx failed: %s";
254 goto failure;
255 }
256 }
257
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700258 /* We're ready to do the accept. Calling grpc_socket_notify_on_read may
259 immediately process an accept that happened in the meantime. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100260 port->new_socket = sock;
Nicolas Noble45e67a32015-02-09 16:20:49 -0800261 grpc_socket_notify_on_read(port->socket, on_accept, port);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100262 return;
263
264failure:
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700265 if (port->shutting_down) {
266 /* We are abandoning the listener port, take that into account to prevent
Jan Tattermuschdd8a80f2015-08-04 11:05:56 -0700267 occasional hangs on shutdown. The hang happens when sp->shutting_down
268 change is not seen by on_accept and we proceed to trying new accept,
269 but we fail there because the listening port has been closed in the
270 meantime. */
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700271 decrement_active_ports_and_notify(port);
Jan Tattermuschdd8a80f2015-08-04 11:05:56 -0700272 return;
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700273 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100274 utf8_message = gpr_format_message(WSAGetLastError());
275 gpr_log(GPR_ERROR, message, utf8_message);
276 gpr_free(utf8_message);
277 if (sock != INVALID_SOCKET) closesocket(sock);
278}
279
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700280/* Event manager callback when reads are ready. */
281static void on_accept(void *arg, int from_iocp) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100282 server_port *sp = arg;
283 SOCKET sock = sp->new_socket;
284 grpc_winsocket_callback_info *info = &sp->socket->read_info;
285 grpc_endpoint *ep = NULL;
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700286 struct sockaddr_storage peer_name;
287 char *peer_name_string;
288 char *fd_name;
289 int peer_name_len = sizeof(peer_name);
chai2010e55e1832015-07-14 13:24:48 +0800290 DWORD transfered_bytes;
291 DWORD flags;
292 BOOL wsa_success;
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700293 int err;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100294
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200295 /* The general mechanism for shutting down is to queue abortion calls. While
296 this is necessary in the read/write case, it's useless for the accept
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700297 case. We only need to adjust the pending callback count */
298 if (!from_iocp) {
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700299 return;
300 }
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700301
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200302 /* The IOCP notified us of a completed operation. Let's grab the results,
303 and act accordingly. */
chai2010e55e1832015-07-14 13:24:48 +0800304 transfered_bytes = 0;
305 wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700306 &transfered_bytes, FALSE, &flags);
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200307 if (!wsa_success) {
308 if (sp->shutting_down) {
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700309 /* During the shutdown case, we ARE expecting an error. So that's well,
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200310 and we can wake up the shutdown thread. */
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700311 decrement_active_ports_and_notify(sp);
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200312 return;
313 } else {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100314 char *utf8_message = gpr_format_message(WSAGetLastError());
315 gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
316 gpr_free(utf8_message);
317 closesocket(sock);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100318 }
319 } else {
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200320 if (!sp->shutting_down) {
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700321 peer_name_string = NULL;
Jan Tattermuschd298a952015-07-24 13:45:56 -0700322 err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700323 (char *)&sp->socket->socket, sizeof(sp->socket->socket));
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700324 if (err) {
325 char *utf8_message = gpr_format_message(WSAGetLastError());
Jan Tattermuschd298a952015-07-24 13:45:56 -0700326 gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700327 gpr_free(utf8_message);
328 }
Craig Tillerd6c98df2015-08-18 09:33:44 -0700329 err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700330 if (!err) {
Craig Tillerd6c98df2015-08-18 09:33:44 -0700331 peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700332 } else {
333 char *utf8_message = gpr_format_message(WSAGetLastError());
334 gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
335 gpr_free(utf8_message);
336 }
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700337 gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
Jan Tattermuschd298a952015-07-24 13:45:56 -0700338 ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
339 peer_name_string);
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700340 gpr_free(fd_name);
341 gpr_free(peer_name_string);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200342 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100343 }
344
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700345 /* The only time we should call our callback, is where we successfully
346 managed to accept a connection, and created an endpoint. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100347 if (ep) sp->server->cb(sp->server->cb_arg, ep);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200348 /* As we were notified from the IOCP of one and exactly one accept,
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200349 the former socked we created has now either been destroy or assigned
350 to the new connection. We need to create a new one for the next
351 connection. */
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200352 start_accept(sp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100353}
354
355static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
356 const struct sockaddr *addr, int addr_len) {
357 server_port *sp;
358 int port;
359 int status;
360 GUID guid = WSAID_ACCEPTEX;
361 DWORD ioctl_num_bytes;
362 LPFN_ACCEPTEX AcceptEx;
363
364 if (sock == INVALID_SOCKET) return -1;
365
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700366 /* We need to grab the AcceptEx pointer for that port, as it may be
367 interface-dependent. We'll cache it to avoid doing that again. */
Craig Tillerc02c1d82015-04-07 16:21:55 -0700368 status =
369 WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
370 &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100371
372 if (status != 0) {
373 char *utf8_message = gpr_format_message(WSAGetLastError());
374 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
375 gpr_free(utf8_message);
376 closesocket(sock);
377 return -1;
378 }
379
380 port = prepare_socket(sock, addr, addr_len);
381 if (port >= 0) {
382 gpr_mu_lock(&s->mu);
383 GPR_ASSERT(!s->cb && "must add ports before starting server");
384 /* append it to the list under a lock */
385 if (s->nports == s->port_capacity) {
386 s->port_capacity *= 2;
387 s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
388 }
389 sp = &s->ports[s->nports++];
390 sp->server = s;
Craig Tiller33da3322015-06-02 10:29:40 -0700391 sp->socket = grpc_winsocket_create(sock, "listener");
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700392 sp->shutting_down = 0;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100393 sp->AcceptEx = AcceptEx;
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200394 sp->new_socket = INVALID_SOCKET;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100395 GPR_ASSERT(sp->socket);
396 gpr_mu_unlock(&s->mu);
397 }
398
399 return port;
400}
401
402int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
403 int addr_len) {
404 int allocated_port = -1;
405 unsigned i;
406 SOCKET sock;
407 struct sockaddr_in6 addr6_v4mapped;
408 struct sockaddr_in6 wildcard;
409 struct sockaddr *allocated_addr = NULL;
410 struct sockaddr_storage sockname_temp;
411 socklen_t sockname_len;
412 int port;
413
414 /* Check if this is a wildcard port, and if so, try to keep the port the same
415 as some previously created listener. */
416 if (grpc_sockaddr_get_port(addr) == 0) {
417 for (i = 0; i < s->nports; i++) {
418 sockname_len = sizeof(sockname_temp);
419 if (0 == getsockname(s->ports[i].socket->socket,
Craig Tillerc02c1d82015-04-07 16:21:55 -0700420 (struct sockaddr *)&sockname_temp, &sockname_len)) {
421 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100422 if (port > 0) {
423 allocated_addr = malloc(addr_len);
424 memcpy(allocated_addr, addr, addr_len);
425 grpc_sockaddr_set_port(allocated_addr, port);
426 addr = allocated_addr;
427 break;
428 }
429 }
430 }
431 }
432
433 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
434 addr = (const struct sockaddr *)&addr6_v4mapped;
435 addr_len = sizeof(addr6_v4mapped);
436 }
437
438 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
439 if (grpc_sockaddr_is_wildcard(addr, &port)) {
440 grpc_sockaddr_make_wildcard6(port, &wildcard);
441
Craig Tillerc02c1d82015-04-07 16:21:55 -0700442 addr = (struct sockaddr *)&wildcard;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100443 addr_len = sizeof(wildcard);
444 }
445
446 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
447 WSA_FLAG_OVERLAPPED);
448 if (sock == INVALID_SOCKET) {
449 char *utf8_message = gpr_format_message(WSAGetLastError());
450 gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
451 gpr_free(utf8_message);
452 }
453
454 allocated_port = add_socket_to_server(s, sock, addr, addr_len);
455 gpr_free(allocated_addr);
456
457 return allocated_port;
458}
459
460SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
461 return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
462}
463
Nicolas "Pixel" Noble94964fd2015-02-21 07:19:19 +0100464void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
465 size_t pollset_count, grpc_tcp_server_cb cb,
466 void *cb_arg) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100467 size_t i;
468 GPR_ASSERT(cb);
469 gpr_mu_lock(&s->mu);
470 GPR_ASSERT(!s->cb);
471 GPR_ASSERT(s->active_ports == 0);
472 s->cb = cb;
473 s->cb_arg = cb_arg;
474 for (i = 0; i < s->nports; i++) {
475 start_accept(s->ports + i);
476 s->active_ports++;
477 }
478 gpr_mu_unlock(&s->mu);
479}
480
Craig Tillerc02c1d82015-04-07 16:21:55 -0700481#endif /* GPR_WINSOCK_SOCKET */