blob: 0162afc1add84f76b12d23e071ab7abd4065b5c2 [file] [log] [blame]
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +01001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +01004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +01008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010016 *
17 */
18
murgatroid9954070892016-08-08 17:01:18 -070019#include "src/core/lib/iomgr/port.h"
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010020
murgatroid99623dd4f2016-08-08 17:31:27 -070021#ifdef GRPC_WINSOCK_SOCKET
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010022
Michael Lumish77c6cce2016-09-26 13:51:57 -070023#include "src/core/lib/iomgr/sockaddr.h"
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -080024
Michael Lumish77c6cce2016-09-26 13:51:57 -070025#include <io.h>
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010026
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010027#include <grpc/support/alloc.h>
28#include <grpc/support/log.h>
Yuchen Zeng12dfdc32016-04-26 22:05:41 -070029#include <grpc/support/log_windows.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070030#include <grpc/support/string_util.h>
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010031#include <grpc/support/sync.h>
32#include <grpc/support/time.h>
33
Craig Tiller4254d3b2017-04-05 14:03:49 -070034#include "src/core/lib/channel/channel_args.h"
Craig Tiller9533d042016-03-25 17:11:06 -070035#include "src/core/lib/iomgr/iocp_windows.h"
36#include "src/core/lib/iomgr/pollset_windows.h"
Michael Lumish77c6cce2016-09-26 13:51:57 -070037#include "src/core/lib/iomgr/resolve_address.h"
38#include "src/core/lib/iomgr/sockaddr_utils.h"
Craig Tiller9533d042016-03-25 17:11:06 -070039#include "src/core/lib/iomgr/socket_windows.h"
40#include "src/core/lib/iomgr/tcp_server.h"
41#include "src/core/lib/iomgr/tcp_windows.h"
Nicolas Nobled72ba6a2015-02-09 16:30:35 -080042
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010043#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
44
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010045/* one listening port */
Dan Born5d81d152016-01-12 20:29:29 -080046typedef struct grpc_tcp_listener grpc_tcp_listener;
Nicolas Noble8f714622015-11-19 11:16:54 -080047struct grpc_tcp_listener {
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070048 /* This seemingly magic number comes from AcceptEx's documentation. each
49 address buffer needs to have at least 16 more bytes at their end. */
Craig Tiller7536af02015-12-22 13:49:30 -080050 uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070051 /* This will hold the socket for the next accept. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010052 SOCKET new_socket;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -080053 /* The listener winsocket. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010054 grpc_winsocket *socket;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -080055 /* The actual TCP port number. */
56 int port;
Dan Bornfa6b6062016-01-08 21:01:59 -080057 unsigned port_index;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010058 grpc_tcp_server *server;
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -070059 /* The cached AcceptEx for that port. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010060 LPFN_ACCEPTEX AcceptEx;
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -070061 int shutting_down;
Craig Tillercbafdd12016-11-29 13:54:00 -080062 int outstanding_calls;
Craig Tiller82f9bd82015-09-23 09:31:51 -070063 /* closure for socket notification of accept being ready */
64 grpc_closure on_accept;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -080065 /* linked list */
Nicolas Noble8f714622015-11-19 11:16:54 -080066 struct grpc_tcp_listener *next;
67};
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010068
69/* the overall server */
Craig Tillera82950e2015-09-22 12:33:20 -070070struct grpc_tcp_server {
Dan Bornfa6b6062016-01-08 21:01:59 -080071 gpr_refcount refs;
Robbie Shade3cd2d182015-08-28 14:30:35 -040072 /* Called whenever accept() succeeds on a server port. */
73 grpc_tcp_server_cb on_accept_cb;
74 void *on_accept_cb_arg;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010075
76 gpr_mu mu;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +010077
78 /* active port count: how many ports are actually still listening */
79 int active_ports;
80
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -080081 /* linked list of server ports */
Nicolas Noble8f714622015-11-19 11:16:54 -080082 grpc_tcp_listener *head;
Dan Bornfa6b6062016-01-08 21:01:59 -080083 grpc_tcp_listener *tail;
Craig Tiller063560e2015-09-01 08:44:42 -070084
Dan Born9c12bc22016-01-13 16:52:20 -080085 /* List of closures passed to shutdown_starting_add(). */
86 grpc_closure_list shutdown_starting;
87
Craig Tiller063560e2015-09-01 08:44:42 -070088 /* shutdown callback */
Craig Tiller82f9bd82015-09-23 09:31:51 -070089 grpc_closure *shutdown_complete;
Craig Tiller290e9a72016-10-28 08:17:00 -070090
Craig Tillerde090652017-04-05 14:00:24 -070091 grpc_channel_args *channel_args;
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 Tillera5ea56b2016-10-28 08:19:02 -070096grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
97 grpc_closure *shutdown_complete,
Craig Tillerb1878952016-06-20 09:11:54 -070098 const grpc_channel_args *args,
Craig Tiller3e149f32016-05-17 16:11:04 -070099 grpc_tcp_server **server) {
Craig Tillera82950e2015-09-22 12:33:20 -0700100 grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
Craig Tillerde090652017-04-05 14:00:24 -0700101 s->channel_args = grpc_channel_args_copy(args);
Dan Bornfa6b6062016-01-08 21:01:59 -0800102 gpr_ref_init(&s->refs, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700103 gpr_mu_init(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100104 s->active_ports = 0;
Robbie Shade3cd2d182015-08-28 14:30:35 -0400105 s->on_accept_cb = NULL;
106 s->on_accept_cb_arg = NULL;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800107 s->head = NULL;
Dan Bornfa6b6062016-01-08 21:01:59 -0800108 s->tail = NULL;
Dan Born9c12bc22016-01-13 16:52:20 -0800109 s->shutdown_starting.head = NULL;
110 s->shutdown_starting.tail = NULL;
Dan Bornfa6b6062016-01-08 21:01:59 -0800111 s->shutdown_complete = shutdown_complete;
Craig Tillera41ac572016-05-17 16:08:17 -0700112 *server = s;
113 return GRPC_ERROR_NONE;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100114}
115
Craig Tillerfdc17aa2016-11-29 13:54:19 -0800116static void destroy_server(grpc_exec_ctx *exec_ctx, void *arg,
117 grpc_error *error) {
Craig Tillercbafdd12016-11-29 13:54:00 -0800118 grpc_tcp_server *s = arg;
Craig Tiller5100ea02015-09-01 12:23:28 -0700119
120 /* Now that the accepts have been aborted, we can destroy the sockets.
Craig Tiller45724b32015-09-22 10:42:19 -0700121 The IOCP won't get notified on these, so we can flag them as already
122 closed by the system. */
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800123 while (s->head) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800124 grpc_tcp_listener *sp = s->head;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800125 s->head = sp->next;
126 sp->next = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700127 grpc_winsocket_destroy(sp->socket);
Dan Born50ef3042016-01-13 13:35:33 -0800128 gpr_free(sp);
Craig Tillera82950e2015-09-22 12:33:20 -0700129 }
Craig Tillerde090652017-04-05 14:00:24 -0700130 grpc_channel_args_destroy(exec_ctx, s->channel_args);
Craig Tillera82950e2015-09-22 12:33:20 -0700131 gpr_free(s);
Craig Tiller5100ea02015-09-01 12:23:28 -0700132}
133
Craig Tillerfdc17aa2016-11-29 13:54:19 -0800134static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
135 grpc_tcp_server *s) {
Craig Tillercbafdd12016-11-29 13:54:00 -0800136 if (s->shutdown_complete != NULL) {
ncteisen274bbbe2017-06-08 14:57:11 -0700137 GRPC_CLOSURE_SCHED(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
Craig Tillercbafdd12016-11-29 13:54:00 -0800138 }
139
ncteisen274bbbe2017-06-08 14:57:11 -0700140 GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE(destroy_server, s,
Craig Tillerd4654562017-01-03 08:45:56 -0800141 grpc_schedule_on_exec_ctx),
142 GRPC_ERROR_NONE);
Craig Tillercbafdd12016-11-29 13:54:00 -0800143}
144
Dan Bornfa6b6062016-01-08 21:01:59 -0800145grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
Dan Born966a4482016-09-26 15:51:42 -0700146 gpr_ref_non_zero(&s->refs);
Dan Bornfa6b6062016-01-08 21:01:59 -0800147 return s;
148}
149
Dan Born9c12bc22016-01-13 16:52:20 -0800150void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
151 grpc_closure *shutdown_starting) {
152 gpr_mu_lock(&s->mu);
Craig Tiller3e149f32016-05-17 16:11:04 -0700153 grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
154 GRPC_ERROR_NONE);
Dan Born9c12bc22016-01-13 16:52:20 -0800155 gpr_mu_unlock(&s->mu);
156}
157
Dan Born5d81d152016-01-12 20:29:29 -0800158static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800159 grpc_tcp_listener *sp;
Craig Tillera82950e2015-09-22 12:33:20 -0700160 gpr_mu_lock(&s->mu);
Craig Tiller063560e2015-09-01 08:44:42 -0700161
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700162 /* First, shutdown all fd's. This will queue abortion calls for all
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200163 of the pending accepts due to the normal operation mechanism. */
Craig Tillera82950e2015-09-22 12:33:20 -0700164 if (s->active_ports == 0) {
Craig Tillercbafdd12016-11-29 13:54:00 -0800165 finish_shutdown_locked(exec_ctx, s);
166 } else {
167 for (sp = s->head; sp; sp = sp->next) {
168 sp->shutting_down = 1;
169 grpc_winsocket_shutdown(sp->socket);
170 }
Craig Tillera82950e2015-09-22 12:33:20 -0700171 }
172 gpr_mu_unlock(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100173}
174
Dan Bornfa6b6062016-01-08 21:01:59 -0800175void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
176 if (gpr_unref(&s->refs)) {
Dan Born966a4482016-09-26 15:51:42 -0700177 grpc_tcp_server_shutdown_listeners(exec_ctx, s);
Dan Born9c12bc22016-01-13 16:52:20 -0800178 gpr_mu_lock(&s->mu);
ncteisen274bbbe2017-06-08 14:57:11 -0700179 GRPC_CLOSURE_LIST_SCHED(exec_ctx, &s->shutdown_starting);
Dan Born9c12bc22016-01-13 16:52:20 -0800180 gpr_mu_unlock(&s->mu);
Dan Born966a4482016-09-26 15:51:42 -0700181 tcp_server_destroy(exec_ctx, s);
Dan Bornfa6b6062016-01-08 21:01:59 -0800182 }
183}
184
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700185/* Prepare (bind) a recently-created socket for listening. */
murgatroid99dedb9232016-09-26 13:54:04 -0700186static grpc_error *prepare_socket(SOCKET sock,
187 const grpc_resolved_address *addr,
Michael Lumish77c6cce2016-09-26 13:51:57 -0700188 int *port) {
Michael Lumish77c6cce2016-09-26 13:51:57 -0700189 grpc_resolved_address sockname_temp;
Craig Tillera41ac572016-05-17 16:08:17 -0700190 grpc_error *error = GRPC_ERROR_NONE;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100191
Craig Tillera41ac572016-05-17 16:08:17 -0700192 error = grpc_tcp_prepare_socket(sock);
193 if (error != GRPC_ERROR_NONE) {
194 goto failure;
Craig Tillera82950e2015-09-22 12:33:20 -0700195 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100196
murgatroid99dedb9232016-09-26 13:54:04 -0700197 if (bind(sock, (const struct sockaddr *)addr->addr, (int)addr->len) ==
198 SOCKET_ERROR) {
Craig Tillera41ac572016-05-17 16:08:17 -0700199 error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
200 goto failure;
Craig Tillera82950e2015-09-22 12:33:20 -0700201 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100202
Craig Tillera82950e2015-09-22 12:33:20 -0700203 if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
Craig Tillera41ac572016-05-17 16:08:17 -0700204 error = GRPC_WSA_ERROR(WSAGetLastError(), "listen");
205 goto failure;
Craig Tillera82950e2015-09-22 12:33:20 -0700206 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100207
Craig Tiller85fe0382016-10-28 08:43:01 -0700208 int sockname_temp_len = sizeof(struct sockaddr_storage);
murgatroid99dedb9232016-09-26 13:54:04 -0700209 if (getsockname(sock, (struct sockaddr *)sockname_temp.addr,
Craig Tiller85fe0382016-10-28 08:43:01 -0700210 &sockname_temp_len) == SOCKET_ERROR) {
Craig Tillera41ac572016-05-17 16:08:17 -0700211 error = GRPC_WSA_ERROR(WSAGetLastError(), "getsockname");
212 goto failure;
Craig Tillera82950e2015-09-22 12:33:20 -0700213 }
Mario Emmenlauerd817c1b2016-12-13 22:35:50 +0100214 sockname_temp.len = (size_t)sockname_temp_len;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100215
Michael Lumish77c6cce2016-09-26 13:51:57 -0700216 *port = grpc_sockaddr_get_port(&sockname_temp);
Craig Tillera41ac572016-05-17 16:08:17 -0700217 return GRPC_ERROR_NONE;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100218
Craig Tillera41ac572016-05-17 16:08:17 -0700219failure:
220 GPR_ASSERT(error != GRPC_ERROR_NONE);
221 char *tgtaddr = grpc_sockaddr_to_uri(addr);
Jan Tattermuschdf715182017-01-11 10:44:41 +0100222 grpc_error_set_int(
ncteisen4b36a3d2017-03-13 19:08:06 -0700223 grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
Craig Tiller3e149f32016-05-17 16:11:04 -0700224 "Failed to prepare server socket", &error, 1),
ncteisen4b36a3d2017-03-13 19:08:06 -0700225 GRPC_ERROR_STR_TARGET_ADDRESS,
226 grpc_slice_from_copied_string(tgtaddr)),
Craig Tiller3e149f32016-05-17 16:11:04 -0700227 GRPC_ERROR_INT_FD, (intptr_t)sock);
Craig Tillera41ac572016-05-17 16:08:17 -0700228 gpr_free(tgtaddr);
229 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700230 if (sock != INVALID_SOCKET) closesocket(sock);
Craig Tillera41ac572016-05-17 16:08:17 -0700231 return error;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100232}
233
Craig Tillercbafdd12016-11-29 13:54:00 -0800234static void decrement_active_ports_and_notify_locked(grpc_exec_ctx *exec_ctx,
Craig Tillerfdc17aa2016-11-29 13:54:19 -0800235 grpc_tcp_listener *sp) {
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700236 sp->shutting_down = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700237 GPR_ASSERT(sp->server->active_ports > 0);
yang-g9aa4f1b2016-03-02 16:39:13 -0800238 if (0 == --sp->server->active_ports) {
Craig Tillercbafdd12016-11-29 13:54:00 -0800239 finish_shutdown_locked(exec_ctx, sp->server);
Craig Tillera82950e2015-09-22 12:33:20 -0700240 }
Jan Tattermusch2f25d982015-08-03 18:01:26 -0700241}
242
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700243/* In order to do an async accept, we need to create a socket first which
244 will be the one assigned to the new incoming connection. */
Craig Tillercbafdd12016-11-29 13:54:00 -0800245static grpc_error *start_accept_locked(grpc_exec_ctx *exec_ctx,
Craig Tillerfdc17aa2016-11-29 13:54:19 -0800246 grpc_tcp_listener *port) {
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100247 SOCKET sock = INVALID_SOCKET;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100248 BOOL success;
Craig Tillera82950e2015-09-22 12:33:20 -0700249 DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100250 DWORD bytes_received = 0;
Craig Tillera41ac572016-05-17 16:08:17 -0700251 grpc_error *error = GRPC_ERROR_NONE;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100252
Craig Tillercbafdd12016-11-29 13:54:00 -0800253 if (port->shutting_down) {
254 return GRPC_ERROR_NONE;
255 }
256
Craig Tillera82950e2015-09-22 12:33:20 -0700257 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
258 WSA_FLAG_OVERLAPPED);
Craig Tillera82950e2015-09-22 12:33:20 -0700259 if (sock == INVALID_SOCKET) {
Craig Tillera41ac572016-05-17 16:08:17 -0700260 error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
Craig Tillera82950e2015-09-22 12:33:20 -0700261 goto failure;
262 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100263
Craig Tillera41ac572016-05-17 16:08:17 -0700264 error = grpc_tcp_prepare_socket(sock);
265 if (error != GRPC_ERROR_NONE) goto failure;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100266
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700267 /* Start the "accept" asynchronously. */
Craig Tillera82950e2015-09-22 12:33:20 -0700268 success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
269 addrlen, addrlen, &bytes_received,
270 &port->socket->read_info.overlapped);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100271
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700272 /* It is possible to get an accept immediately without delay. However, we
273 will still get an IOCP notification for it. So let's just ignore it. */
Craig Tillera82950e2015-09-22 12:33:20 -0700274 if (!success) {
Craig Tillera41ac572016-05-17 16:08:17 -0700275 int last_error = WSAGetLastError();
276 if (last_error != ERROR_IO_PENDING) {
277 error = GRPC_WSA_ERROR(last_error, "AcceptEx");
Craig Tillera82950e2015-09-22 12:33:20 -0700278 goto failure;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100279 }
Craig Tillera82950e2015-09-22 12:33:20 -0700280 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100281
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700282 /* We're ready to do the accept. Calling grpc_socket_notify_on_read may
283 immediately process an accept that happened in the meantime. */
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100284 port->new_socket = sock;
Craig Tiller82f9bd82015-09-23 09:31:51 -0700285 grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept);
Craig Tillercbafdd12016-11-29 13:54:00 -0800286 port->outstanding_calls++;
Craig Tillera41ac572016-05-17 16:08:17 -0700287 return error;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100288
289failure:
Craig Tillera41ac572016-05-17 16:08:17 -0700290 GPR_ASSERT(error != GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700291 if (sock != INVALID_SOCKET) closesocket(sock);
Craig Tillera41ac572016-05-17 16:08:17 -0700292 return error;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100293}
294
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700295/* Event manager callback when reads are ready. */
Craig Tillera41ac572016-05-17 16:08:17 -0700296static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800297 grpc_tcp_listener *sp = arg;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100298 SOCKET sock = sp->new_socket;
299 grpc_winsocket_callback_info *info = &sp->socket->read_info;
300 grpc_endpoint *ep = NULL;
Michael Lumish77c6cce2016-09-26 13:51:57 -0700301 grpc_resolved_address peer_name;
Craig Tiller81bcc4c2015-07-20 14:04:18 -0700302 char *peer_name_string;
303 char *fd_name;
chai2010e55e1832015-07-14 13:24:48 +0800304 DWORD transfered_bytes;
305 DWORD flags;
306 BOOL wsa_success;
Jan Tattermusch3f7809d2015-07-24 13:20:40 -0700307 int err;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100308
Craig Tillercbafdd12016-11-29 13:54:00 -0800309 gpr_mu_lock(&sp->server->mu);
310
Michael Lumish77c6cce2016-09-26 13:51:57 -0700311 peer_name.len = sizeof(struct sockaddr_storage);
312
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200313 /* The general mechanism for shutting down is to queue abortion calls. While
314 this is necessary in the read/write case, it's useless for the accept
Jan Tattermuscheab5c332015-07-29 11:49:31 -0700315 case. We only need to adjust the pending callback count */
Craig Tillera41ac572016-05-17 16:08:17 -0700316 if (error != GRPC_ERROR_NONE) {
317 const char *msg = grpc_error_string(error);
318 gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg);
Craig Tiller7c70b6c2017-01-23 07:48:42 -0800319
Craig Tillercbafdd12016-11-29 13:54:00 -0800320 gpr_mu_unlock(&sp->server->mu);
Craig Tillera82950e2015-09-22 12:33:20 -0700321 return;
322 }
Nicolas "Pixel" Noble404fc6a2015-05-02 02:34:39 -0700323
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200324 /* The IOCP notified us of a completed operation. Let's grab the results,
Craig Tiller45724b32015-09-22 10:42:19 -0700325 and act accordingly. */
chai2010e55e1832015-07-14 13:24:48 +0800326 transfered_bytes = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700327 wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
328 &transfered_bytes, FALSE, &flags);
329 if (!wsa_success) {
Craig Tillercbafdd12016-11-29 13:54:00 -0800330 if (!sp->shutting_down) {
Craig Tillera82950e2015-09-22 12:33:20 -0700331 char *utf8_message = gpr_format_message(WSAGetLastError());
332 gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
333 gpr_free(utf8_message);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100334 }
Craig Tillercbafdd12016-11-29 13:54:00 -0800335 closesocket(sock);
Craig Tillera82950e2015-09-22 12:33:20 -0700336 } else {
337 if (!sp->shutting_down) {
338 peer_name_string = NULL;
339 err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
340 (char *)&sp->socket->socket, sizeof(sp->socket->socket));
341 if (err) {
342 char *utf8_message = gpr_format_message(WSAGetLastError());
343 gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
344 gpr_free(utf8_message);
345 }
Craig Tiller6108d1f2016-10-28 08:43:21 -0700346 int peer_name_len = (int)peer_name.len;
murgatroid99dedb9232016-09-26 13:54:04 -0700347 err =
Craig Tiller85fe0382016-10-28 08:43:01 -0700348 getpeername(sock, (struct sockaddr *)peer_name.addr, &peer_name_len);
Mario Emmenlauerd817c1b2016-12-13 22:35:50 +0100349 peer_name.len = (size_t)peer_name_len;
Craig Tillera82950e2015-09-22 12:33:20 -0700350 if (!err) {
Michael Lumish77c6cce2016-09-26 13:51:57 -0700351 peer_name_string = grpc_sockaddr_to_uri(&peer_name);
Craig Tillera82950e2015-09-22 12:33:20 -0700352 } else {
353 char *utf8_message = gpr_format_message(WSAGetLastError());
354 gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
355 gpr_free(utf8_message);
356 }
357 gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
Craig Tillerde090652017-04-05 14:00:24 -0700358 ep = grpc_tcp_create(exec_ctx, grpc_winsocket_create(sock, fd_name),
359 sp->server->channel_args, peer_name_string);
Craig Tillera82950e2015-09-22 12:33:20 -0700360 gpr_free(fd_name);
361 gpr_free(peer_name_string);
Craig Tillerfaf8f682015-10-06 09:12:34 -0700362 } else {
363 closesocket(sock);
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200364 }
Craig Tillera82950e2015-09-22 12:33:20 -0700365 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100366
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700367 /* The only time we should call our callback, is where we successfully
368 managed to accept a connection, and created an endpoint. */
Craig Tiller8ad69bf2016-05-20 08:48:22 -0700369 if (ep) {
Mark D. Roth6c07bf82016-12-09 08:38:38 -0800370 // Create acceptor.
371 grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor));
372 acceptor->from_server = sp->server;
373 acceptor->port_index = sp->port_index;
374 acceptor->fd_index = 0;
Craig Tillere0049582016-05-20 10:31:09 -0700375 sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep, NULL,
Mark D. Rotheed38152016-12-08 13:59:13 -0800376 acceptor);
Craig Tiller8ad69bf2016-05-20 08:48:22 -0700377 }
Nicolas "Pixel" Noble0f981e92015-05-03 10:40:56 +0200378 /* As we were notified from the IOCP of one and exactly one accept,
Nicolas "Pixel" Noblee503cd52015-07-14 02:27:23 +0200379 the former socked we created has now either been destroy or assigned
380 to the new connection. We need to create a new one for the next
381 connection. */
Craig Tillerfdc17aa2016-11-29 13:54:19 -0800382 GPR_ASSERT(
383 GRPC_LOG_IF_ERROR("start_accept", start_accept_locked(exec_ctx, sp)));
Craig Tillercbafdd12016-11-29 13:54:00 -0800384 if (0 == --sp->outstanding_calls) {
385 decrement_active_ports_and_notify_locked(exec_ctx, sp);
386 }
387 gpr_mu_unlock(&sp->server->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100388}
389
Craig Tillera41ac572016-05-17 16:08:17 -0700390static grpc_error *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
Michael Lumish77c6cce2016-09-26 13:51:57 -0700391 const grpc_resolved_address *addr,
392 unsigned port_index,
Craig Tiller3e149f32016-05-17 16:11:04 -0700393 grpc_tcp_listener **listener) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800394 grpc_tcp_listener *sp = NULL;
Ken Payson8891ef52016-06-22 16:47:52 -0700395 int port = -1;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100396 int status;
397 GUID guid = WSAID_ACCEPTEX;
398 DWORD ioctl_num_bytes;
399 LPFN_ACCEPTEX AcceptEx;
Craig Tillera41ac572016-05-17 16:08:17 -0700400 grpc_error *error = GRPC_ERROR_NONE;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100401
Nicolas "Pixel" Noble8e1a55d2015-05-02 15:21:25 -0700402 /* We need to grab the AcceptEx pointer for that port, as it may be
403 interface-dependent. We'll cache it to avoid doing that again. */
Craig Tillera82950e2015-09-22 12:33:20 -0700404 status =
405 WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
406 &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100407
Craig Tillera82950e2015-09-22 12:33:20 -0700408 if (status != 0) {
409 char *utf8_message = gpr_format_message(WSAGetLastError());
410 gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
411 gpr_free(utf8_message);
412 closesocket(sock);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800413 return NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700414 }
Craig Tiller45724b32015-09-22 10:42:19 -0700415
Michael Lumish77c6cce2016-09-26 13:51:57 -0700416 error = prepare_socket(sock, addr, &port);
Craig Tillera41ac572016-05-17 16:08:17 -0700417 if (error != GRPC_ERROR_NONE) {
418 return error;
Craig Tillera82950e2015-09-22 12:33:20 -0700419 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100420
Craig Tillera41ac572016-05-17 16:08:17 -0700421 GPR_ASSERT(port >= 0);
422 gpr_mu_lock(&s->mu);
423 GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
424 sp = gpr_malloc(sizeof(grpc_tcp_listener));
425 sp->next = NULL;
426 if (s->head == NULL) {
427 s->head = sp;
428 } else {
429 s->tail->next = sp;
430 }
431 s->tail = sp;
432 sp->server = s;
433 sp->socket = grpc_winsocket_create(sock, "listener");
434 sp->shutting_down = 0;
Craig Tillercbafdd12016-11-29 13:54:00 -0800435 sp->outstanding_calls = 0;
Craig Tillera41ac572016-05-17 16:08:17 -0700436 sp->AcceptEx = AcceptEx;
437 sp->new_socket = INVALID_SOCKET;
438 sp->port = port;
439 sp->port_index = port_index;
ncteisen274bbbe2017-06-08 14:57:11 -0700440 GRPC_CLOSURE_INIT(&sp->on_accept, on_accept, sp, grpc_schedule_on_exec_ctx);
Craig Tillera41ac572016-05-17 16:08:17 -0700441 GPR_ASSERT(sp->socket);
442 gpr_mu_unlock(&s->mu);
443 *listener = sp;
444
445 return GRPC_ERROR_NONE;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100446}
447
Michael Lumish77c6cce2016-09-26 13:51:57 -0700448grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s,
murgatroid99dedb9232016-09-26 13:54:04 -0700449 const grpc_resolved_address *addr,
Michael Lumish77c6cce2016-09-26 13:51:57 -0700450 int *port) {
Craig Tiller5352ff12016-05-18 10:44:38 -0700451 grpc_tcp_listener *sp = NULL;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100452 SOCKET sock;
Michael Lumish77c6cce2016-09-26 13:51:57 -0700453 grpc_resolved_address addr6_v4mapped;
454 grpc_resolved_address wildcard;
455 grpc_resolved_address *allocated_addr = NULL;
456 grpc_resolved_address sockname_temp;
Dan Bornfa6b6062016-01-08 21:01:59 -0800457 unsigned port_index = 0;
Craig Tillera41ac572016-05-17 16:08:17 -0700458 grpc_error *error = GRPC_ERROR_NONE;
459
Dan Bornfa6b6062016-01-08 21:01:59 -0800460 if (s->tail != NULL) {
461 port_index = s->tail->port_index + 1;
462 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100463
464 /* Check if this is a wildcard port, and if so, try to keep the port the same
465 as some previously created listener. */
Craig Tillera82950e2015-09-22 12:33:20 -0700466 if (grpc_sockaddr_get_port(addr) == 0) {
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800467 for (sp = s->head; sp; sp = sp->next) {
Craig Tiller85fe0382016-10-28 08:43:01 -0700468 int sockname_temp_len = sizeof(struct sockaddr_storage);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800469 if (0 == getsockname(sp->socket->socket,
murgatroid99dedb9232016-09-26 13:54:04 -0700470 (struct sockaddr *)sockname_temp.addr,
Craig Tiller85fe0382016-10-28 08:43:01 -0700471 &sockname_temp_len)) {
Mario Emmenlauerd817c1b2016-12-13 22:35:50 +0100472 sockname_temp.len = (size_t)sockname_temp_len;
Michael Lumish77c6cce2016-09-26 13:51:57 -0700473 *port = grpc_sockaddr_get_port(&sockname_temp);
Craig Tillera41ac572016-05-17 16:08:17 -0700474 if (*port > 0) {
Michael Lumish77c6cce2016-09-26 13:51:57 -0700475 allocated_addr = gpr_malloc(sizeof(grpc_resolved_address));
476 memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
Craig Tillera41ac572016-05-17 16:08:17 -0700477 grpc_sockaddr_set_port(allocated_addr, *port);
Craig Tillera82950e2015-09-22 12:33:20 -0700478 addr = allocated_addr;
479 break;
480 }
481 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100482 }
Craig Tillera82950e2015-09-22 12:33:20 -0700483 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100484
Craig Tillera82950e2015-09-22 12:33:20 -0700485 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
Michael Lumish77c6cce2016-09-26 13:51:57 -0700486 addr = &addr6_v4mapped;
Craig Tillera82950e2015-09-22 12:33:20 -0700487 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100488
489 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
Craig Tillera41ac572016-05-17 16:08:17 -0700490 if (grpc_sockaddr_is_wildcard(addr, port)) {
491 grpc_sockaddr_make_wildcard6(*port, &wildcard);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100492
Michael Lumish77c6cce2016-09-26 13:51:57 -0700493 addr = &wildcard;
Craig Tillera82950e2015-09-22 12:33:20 -0700494 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100495
Craig Tillera82950e2015-09-22 12:33:20 -0700496 sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
497 WSA_FLAG_OVERLAPPED);
498 if (sock == INVALID_SOCKET) {
Craig Tillera41ac572016-05-17 16:08:17 -0700499 error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
500 goto done;
Craig Tillera82950e2015-09-22 12:33:20 -0700501 }
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100502
Michael Lumish77c6cce2016-09-26 13:51:57 -0700503 error = add_socket_to_server(s, sock, addr, port_index, &sp);
Craig Tillera41ac572016-05-17 16:08:17 -0700504
505done:
Craig Tillera82950e2015-09-22 12:33:20 -0700506 gpr_free(allocated_addr);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100507
Craig Tillera41ac572016-05-17 16:08:17 -0700508 if (error != GRPC_ERROR_NONE) {
ncteisen4b36a3d2017-03-13 19:08:06 -0700509 grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
Craig Tiller3e149f32016-05-17 16:11:04 -0700510 "Failed to add port to server", &error, 1);
Craig Tillera41ac572016-05-17 16:08:17 -0700511 GRPC_ERROR_UNREF(error);
512 error = error_out;
Craig Tiller5352ff12016-05-18 10:44:38 -0700513 *port = -1;
514 } else {
515 GPR_ASSERT(sp != NULL);
516 *port = sp->port;
Dan Bornfa6b6062016-01-08 21:01:59 -0800517 }
Craig Tillera41ac572016-05-17 16:08:17 -0700518 return error;
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100519}
520
Craig Tiller565b18b2015-09-23 10:09:42 -0700521void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
522 grpc_pollset **pollset, size_t pollset_count,
Craig Tillera82950e2015-09-22 12:33:20 -0700523 grpc_tcp_server_cb on_accept_cb,
524 void *on_accept_cb_arg) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800525 grpc_tcp_listener *sp;
Craig Tillera82950e2015-09-22 12:33:20 -0700526 GPR_ASSERT(on_accept_cb);
527 gpr_mu_lock(&s->mu);
528 GPR_ASSERT(!s->on_accept_cb);
529 GPR_ASSERT(s->active_ports == 0);
Robbie Shade3cd2d182015-08-28 14:30:35 -0400530 s->on_accept_cb = on_accept_cb;
531 s->on_accept_cb_arg = on_accept_cb_arg;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800532 for (sp = s->head; sp; sp = sp->next) {
Craig Tillerfdc17aa2016-11-29 13:54:19 -0800533 GPR_ASSERT(
534 GRPC_LOG_IF_ERROR("start_accept", start_accept_locked(exec_ctx, sp)));
Craig Tillera82950e2015-09-22 12:33:20 -0700535 s->active_ports++;
536 }
537 gpr_mu_unlock(&s->mu);
Nicolas "Pixel" Noble0f3ec822015-02-05 19:40:38 +0100538}
539
yang-g9275d402016-07-11 16:51:39 -0700540void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
541 grpc_tcp_server *s) {}
542
murgatroid99623dd4f2016-08-08 17:31:27 -0700543#endif /* GRPC_WINSOCK_SOCKET */