blob: 06612d639cccb1624239f715ba3c58ccc442eabf [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 *
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 Nobleb7ebd3b2014-11-26 16:33:03 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080010 *
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 Nobleb7ebd3b2014-11-26 16:33:03 -080016 *
17 */
18
David Klempner78b79922015-02-04 10:18:59 -080019/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
20#ifndef _GNU_SOURCE
21#define _GNU_SOURCE
22#endif
23
murgatroid9954070892016-08-08 17:01:18 -070024#include "src/core/lib/iomgr/port.h"
Craig Tiller0c0b60c2015-01-21 15:49:28 -080025
murgatroid99623dd4f2016-08-08 17:31:27 -070026#ifdef GRPC_POSIX_SOCKET
Craig Tiller0c0b60c2015-01-21 15:49:28 -080027
Craig Tiller9533d042016-03-25 17:11:06 -070028#include "src/core/lib/iomgr/tcp_server.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080029
Craig Tilleraa31da42015-02-17 16:33:35 -080030#include <errno.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080031#include <fcntl.h>
32#include <netinet/in.h>
33#include <netinet/tcp.h>
Craig Tilleraa31da42015-02-17 16:33:35 -080034#include <string.h>
35#include <sys/socket.h>
36#include <sys/stat.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037#include <sys/types.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080038#include <unistd.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039
Craig Tillerf40df232016-03-25 13:38:14 -070040#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42#include <grpc/support/string_util.h>
43#include <grpc/support/sync.h>
44#include <grpc/support/time.h>
Craig Tillerc027e772016-05-03 16:27:00 -070045#include <grpc/support/useful.h>
46
Craig Tiller547cb4b2017-03-28 09:50:33 -070047#include "src/core/lib/channel/channel_args.h"
Craig Tiller9533d042016-03-25 17:11:06 -070048#include "src/core/lib/iomgr/resolve_address.h"
murgatroid997871f732016-09-23 13:49:05 -070049#include "src/core/lib/iomgr/sockaddr.h"
Craig Tiller9533d042016-03-25 17:11:06 -070050#include "src/core/lib/iomgr/sockaddr_utils.h"
51#include "src/core/lib/iomgr/socket_utils_posix.h"
52#include "src/core/lib/iomgr/tcp_posix.h"
Yuchen Zeng47155ed2017-03-13 17:18:07 -070053#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
Craig Tiller9533d042016-03-25 17:11:06 -070054#include "src/core/lib/iomgr/unix_sockets_posix.h"
55#include "src/core/lib/support/string.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080056
Craig Tilleref962642016-05-18 22:57:17 -070057static gpr_once check_init = GPR_ONCE_INIT;
Nicolas "Pixel" Noblebaa35fc2016-08-19 02:20:11 +020058static bool has_so_reuseport = false;
Craig Tilleref962642016-05-18 22:57:17 -070059
60static void init(void) {
Nicolas "Pixel" Noblebaa35fc2016-08-19 02:20:11 +020061#ifndef GPR_MANYLINUX1
Craig Tilleref962642016-05-18 22:57:17 -070062 int s = socket(AF_INET, SOCK_STREAM, 0);
63 if (s >= 0) {
64 has_so_reuseport = GRPC_LOG_IF_ERROR("check for SO_REUSEPORT",
65 grpc_set_socket_reuse_port(s, 1));
66 close(s);
67 }
Nicolas "Pixel" Noblebaa35fc2016-08-19 02:20:11 +020068#endif
Craig Tilleref962642016-05-18 22:57:17 -070069}
70
Craig Tillere34c2852016-09-23 09:43:32 -070071grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
72 grpc_closure *shutdown_complete,
Craig Tilleref962642016-05-18 22:57:17 -070073 const grpc_channel_args *args,
Craig Tiller0b5857f2016-05-04 10:58:06 -070074 grpc_tcp_server **server) {
Craig Tilleref962642016-05-18 22:57:17 -070075 gpr_once_init(&check_init, init);
76
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070077 grpc_tcp_server *s = (grpc_tcp_server *)gpr_zalloc(sizeof(grpc_tcp_server));
Craig Tilleref962642016-05-18 22:57:17 -070078 s->so_reuseport = has_so_reuseport;
Dan Born8886a812016-07-08 16:06:07 -070079 s->expand_wildcard_addrs = false;
Craig Tilleref962642016-05-18 22:57:17 -070080 for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
81 if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
82 if (args->args[i].type == GRPC_ARG_INTEGER) {
83 s->so_reuseport =
84 has_so_reuseport && (args->args[i].value.integer != 0);
85 } else {
86 gpr_free(s);
ncteisen4b36a3d2017-03-13 19:08:06 -070087 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT
88 " must be an integer");
Craig Tilleref962642016-05-18 22:57:17 -070089 }
Dan Born8886a812016-07-08 16:06:07 -070090 } else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) {
91 if (args->args[i].type == GRPC_ARG_INTEGER) {
92 s->expand_wildcard_addrs = (args->args[i].value.integer != 0);
93 } else {
Dan Born8886a812016-07-08 16:06:07 -070094 gpr_free(s);
ncteisen4b36a3d2017-03-13 19:08:06 -070095 return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
96 GRPC_ARG_EXPAND_WILDCARD_ADDRS " must be an integer");
Dan Born8886a812016-07-08 16:06:07 -070097 }
Craig Tilleref962642016-05-18 22:57:17 -070098 }
99 }
Dan Bornfa6b6062016-01-08 21:01:59 -0800100 gpr_ref_init(&s->refs, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700101 gpr_mu_init(&s->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800102 s->active_ports = 0;
Craig Tilleraec96aa2015-04-07 14:32:15 -0700103 s->destroyed_ports = 0;
Craig Tilleref962642016-05-18 22:57:17 -0700104 s->shutdown = false;
Dan Born9c12bc22016-01-13 16:52:20 -0800105 s->shutdown_starting.head = NULL;
106 s->shutdown_starting.tail = NULL;
Dan Bornfa6b6062016-01-08 21:01:59 -0800107 s->shutdown_complete = shutdown_complete;
Robbie Shade3cd2d182015-08-28 14:30:35 -0400108 s->on_accept_cb = NULL;
109 s->on_accept_cb_arg = NULL;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800110 s->head = NULL;
Dan Bornfa6b6062016-01-08 21:01:59 -0800111 s->tail = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800112 s->nports = 0;
Craig Tiller547cb4b2017-03-28 09:50:33 -0700113 s->channel_args = grpc_channel_args_copy(args);
Craig Tillerb76471d2016-07-01 10:24:56 -0700114 gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0);
Craig Tiller0b5857f2016-05-04 10:58:06 -0700115 *server = s;
116 return GRPC_ERROR_NONE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800117}
118
Craig Tillera82950e2015-09-22 12:33:20 -0700119static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Dan Born930c2982016-09-08 19:12:18 -0700120 gpr_mu_lock(&s->mu);
121 GPR_ASSERT(s->shutdown);
122 gpr_mu_unlock(&s->mu);
Dan Bornfa6b6062016-01-08 21:01:59 -0800123 if (s->shutdown_complete != NULL) {
ncteisen274bbbe2017-06-08 14:57:11 -0700124 GRPC_CLOSURE_SCHED(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
Dan Bornfa6b6062016-01-08 21:01:59 -0800125 }
Craig Tilleraec96aa2015-04-07 14:32:15 -0700126
Craig Tillera82950e2015-09-22 12:33:20 -0700127 gpr_mu_destroy(&s->mu);
Craig Tilleraec96aa2015-04-07 14:32:15 -0700128
Nicolas "Pixel" Noblec6a7c6e2015-11-19 21:55:44 +0100129 while (s->head) {
130 grpc_tcp_listener *sp = s->head;
131 s->head = sp->next;
Dan Bornfa6b6062016-01-08 21:01:59 -0800132 gpr_free(sp);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800133 }
Craig Tiller547cb4b2017-03-28 09:50:33 -0700134 grpc_channel_args_destroy(exec_ctx, s->channel_args);
Craig Tillere34c2852016-09-23 09:43:32 -0700135
Craig Tillera82950e2015-09-22 12:33:20 -0700136 gpr_free(s);
Craig Tilleraec96aa2015-04-07 14:32:15 -0700137}
138
Craig Tiller6c396862016-01-28 13:53:40 -0800139static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
Craig Tillerc027e772016-05-03 16:27:00 -0700140 grpc_error *error) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700141 grpc_tcp_server *s = (grpc_tcp_server *)server;
Craig Tillera82950e2015-09-22 12:33:20 -0700142 gpr_mu_lock(&s->mu);
Craig Tilleraec96aa2015-04-07 14:32:15 -0700143 s->destroyed_ports++;
Craig Tillera82950e2015-09-22 12:33:20 -0700144 if (s->destroyed_ports == s->nports) {
145 gpr_mu_unlock(&s->mu);
146 finish_shutdown(exec_ctx, s);
147 } else {
148 GPR_ASSERT(s->destroyed_ports < s->nports);
149 gpr_mu_unlock(&s->mu);
150 }
Craig Tilleraec96aa2015-04-07 14:32:15 -0700151}
152
Craig Tiller6174b9a2015-06-18 08:13:05 -0700153/* called when all listening endpoints have been shutdown, so no further
154 events will be received on them - at this point it's safe to destroy
155 things */
Craig Tillera82950e2015-09-22 12:33:20 -0700156static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800157 /* delete ALL the things */
Craig Tillera82950e2015-09-22 12:33:20 -0700158 gpr_mu_lock(&s->mu);
Craig Tiller6f051402015-05-13 11:42:42 -0700159
yang-gaef398b2017-03-07 15:43:53 -0800160 GPR_ASSERT(s->shutdown);
Craig Tiller45724b32015-09-22 10:42:19 -0700161
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800162 if (s->head) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800163 grpc_tcp_listener *sp;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800164 for (sp = s->head; sp; sp = sp->next) {
murgatroid997871f732016-09-23 13:49:05 -0700165 grpc_unlink_if_unix_domain_socket(&sp->addr);
ncteisen274bbbe2017-06-08 14:57:11 -0700166 GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s,
Craig Tiller3cb34472016-12-28 16:11:38 -0800167 grpc_schedule_on_exec_ctx);
yang-g5d850372015-12-01 10:32:28 -0800168 grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
Yuchen Zengd40a7ae2017-07-12 15:59:56 -0700169 false /* already_closed */, "tcp_listener_shutdown");
Craig Tiller45724b32015-09-22 10:42:19 -0700170 }
Craig Tillera82950e2015-09-22 12:33:20 -0700171 gpr_mu_unlock(&s->mu);
172 } else {
173 gpr_mu_unlock(&s->mu);
174 finish_shutdown(exec_ctx, s);
175 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800176}
177
Dan Born5d81d152016-01-12 20:29:29 -0800178static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Craig Tillera82950e2015-09-22 12:33:20 -0700179 gpr_mu_lock(&s->mu);
Craig Tiller6f051402015-05-13 11:42:42 -0700180
Craig Tillera82950e2015-09-22 12:33:20 -0700181 GPR_ASSERT(!s->shutdown);
Craig Tilleref962642016-05-18 22:57:17 -0700182 s->shutdown = true;
Craig Tiller6f051402015-05-13 11:42:42 -0700183
Craig Tiller6f051402015-05-13 11:42:42 -0700184 /* shutdown all fd's */
Craig Tillera82950e2015-09-22 12:33:20 -0700185 if (s->active_ports) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800186 grpc_tcp_listener *sp;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800187 for (sp = s->head; sp; sp = sp->next) {
ncteisen4b36a3d2017-03-13 19:08:06 -0700188 grpc_fd_shutdown(exec_ctx, sp->emfd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
189 "Server destroyed"));
Craig Tiller6f051402015-05-13 11:42:42 -0700190 }
Craig Tillera82950e2015-09-22 12:33:20 -0700191 gpr_mu_unlock(&s->mu);
192 } else {
193 gpr_mu_unlock(&s->mu);
194 deactivated_all_ports(exec_ctx, s);
195 }
Craig Tiller6f051402015-05-13 11:42:42 -0700196}
197
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800198/* event manager callback when reads are ready */
Craig Tillerc027e772016-05-03 16:27:00 -0700199static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700200 grpc_tcp_listener *sp = (grpc_tcp_listener *)arg;
Yash Tibrewal533d1182017-09-18 10:48:22 -0700201 grpc_pollset *read_notifier_pollset;
Craig Tillerc027e772016-05-03 16:27:00 -0700202 if (err != GRPC_ERROR_NONE) {
Craig Tillera82950e2015-09-22 12:33:20 -0700203 goto error;
204 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800205
Yash Tibrewal533d1182017-09-18 10:48:22 -0700206 read_notifier_pollset =
Craig Tillerb76471d2016-07-01 10:24:56 -0700207 sp->server->pollsets[(size_t)gpr_atm_no_barrier_fetch_add(
208 &sp->server->next_pollset_to_assign, 1) %
Craig Tiller53dd6b92016-05-24 13:49:50 -0700209 sp->server->pollset_count];
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700210
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800211 /* loop until accept4 returns EAGAIN, and then re-arm notification */
Craig Tillera82950e2015-09-22 12:33:20 -0700212 for (;;) {
murgatroid997871f732016-09-23 13:49:05 -0700213 grpc_resolved_address addr;
Craig Tillera82950e2015-09-22 12:33:20 -0700214 char *addr_str;
215 char *name;
murgatroid997871f732016-09-23 13:49:05 -0700216 addr.len = sizeof(struct sockaddr_storage);
Craig Tillera82950e2015-09-22 12:33:20 -0700217 /* Note: If we ever decide to return this address to the user, remember to
218 strip off the ::ffff:0.0.0.0/96 prefix first. */
murgatroid997871f732016-09-23 13:49:05 -0700219 int fd = grpc_accept4(sp->fd, &addr, 1, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700220 if (fd < 0) {
221 switch (errno) {
222 case EINTR:
223 continue;
224 case EAGAIN:
225 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
226 return;
227 default:
Craig Tiller14444642017-03-07 16:21:55 -0800228 gpr_mu_lock(&sp->server->mu);
Craig Tillerf26236a2017-03-07 09:43:51 -0800229 if (!sp->server->shutdown_listeners) {
230 gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno));
231 } else {
232 /* if we have shutdown listeners, accept4 could fail, and we
233 needn't notify users */
234 }
Craig Tiller14444642017-03-07 16:21:55 -0800235 gpr_mu_unlock(&sp->server->mu);
Craig Tillera82950e2015-09-22 12:33:20 -0700236 goto error;
237 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800238 }
239
Craig Tillera82950e2015-09-22 12:33:20 -0700240 grpc_set_socket_no_sigpipe_if_possible(fd);
241
murgatroid997871f732016-09-23 13:49:05 -0700242 addr_str = grpc_sockaddr_to_uri(&addr);
Craig Tillera82950e2015-09-22 12:33:20 -0700243 gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
244
Craig Tiller84f75d42017-05-03 13:06:35 -0700245 if (GRPC_TRACER_ON(grpc_tcp_trace)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700246 gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str);
247 }
248
Mark D. Rotheed38152016-12-08 13:59:13 -0800249 grpc_fd *fdobj = grpc_fd_create(fd, name);
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700250
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700251 grpc_pollset_add_fd(exec_ctx, read_notifier_pollset, fdobj);
252
Mark D. Roth6c07bf82016-12-09 08:38:38 -0800253 // Create acceptor.
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700254 grpc_tcp_server_acceptor *acceptor =
255 (grpc_tcp_server_acceptor *)gpr_malloc(sizeof(*acceptor));
Mark D. Roth6c07bf82016-12-09 08:38:38 -0800256 acceptor->from_server = sp->server;
257 acceptor->port_index = sp->port_index;
258 acceptor->fd_index = sp->fd_index;
259
Craig Tillera82950e2015-09-22 12:33:20 -0700260 sp->server->on_accept_cb(
261 exec_ctx, sp->server->on_accept_cb_arg,
Craig Tiller547cb4b2017-03-28 09:50:33 -0700262 grpc_tcp_create(exec_ctx, fdobj, sp->server->channel_args, addr_str),
Mark D. Rotheed38152016-12-08 13:59:13 -0800263 read_notifier_pollset, acceptor);
Craig Tillera82950e2015-09-22 12:33:20 -0700264
265 gpr_free(name);
266 gpr_free(addr_str);
267 }
268
yang-gb063c872015-10-07 11:40:13 -0700269 GPR_UNREACHABLE_CODE(return );
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800270
271error:
Craig Tillera82950e2015-09-22 12:33:20 -0700272 gpr_mu_lock(&sp->server->mu);
yang-gaef398b2017-03-07 15:43:53 -0800273 if (0 == --sp->server->active_ports && sp->server->shutdown) {
Craig Tillera82950e2015-09-22 12:33:20 -0700274 gpr_mu_unlock(&sp->server->mu);
275 deactivated_all_ports(exec_ctx, sp->server);
276 } else {
277 gpr_mu_unlock(&sp->server->mu);
278 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800279}
280
Dan Born8886a812016-07-08 16:06:07 -0700281/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
282static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
283 unsigned port_index,
284 int requested_port,
285 int *out_port) {
286 grpc_resolved_address wild4;
287 grpc_resolved_address wild6;
288 unsigned fd_index = 0;
289 grpc_dualstack_mode dsmode;
290 grpc_tcp_listener *sp = NULL;
291 grpc_tcp_listener *sp2 = NULL;
292 grpc_error *v6_err = GRPC_ERROR_NONE;
293 grpc_error *v4_err = GRPC_ERROR_NONE;
294 *out_port = -1;
Yuchen Zengca294652017-03-13 14:50:34 -0700295
Yuchen Zeng47155ed2017-03-13 17:18:07 -0700296 if (grpc_tcp_server_have_ifaddrs() && s->expand_wildcard_addrs) {
297 return grpc_tcp_server_add_all_local_addrs(s, port_index, requested_port,
298 out_port);
Dan Born8886a812016-07-08 16:06:07 -0700299 }
Yuchen Zengca294652017-03-13 14:50:34 -0700300
Dan Born8886a812016-07-08 16:06:07 -0700301 grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6);
302 /* Try listening on IPv6 first. */
Yuchen Zeng47155ed2017-03-13 17:18:07 -0700303 if ((v6_err = grpc_tcp_server_add_addr(s, &wild6, port_index, fd_index,
304 &dsmode, &sp)) == GRPC_ERROR_NONE) {
Dan Born8886a812016-07-08 16:06:07 -0700305 ++fd_index;
306 requested_port = *out_port = sp->port;
307 if (dsmode == GRPC_DSMODE_DUALSTACK || dsmode == GRPC_DSMODE_IPV4) {
308 return GRPC_ERROR_NONE;
309 }
310 }
311 /* If we got a v6-only socket or nothing, try adding 0.0.0.0. */
312 grpc_sockaddr_set_port(&wild4, requested_port);
Yuchen Zeng47155ed2017-03-13 17:18:07 -0700313 if ((v4_err = grpc_tcp_server_add_addr(s, &wild4, port_index, fd_index,
314 &dsmode, &sp2)) == GRPC_ERROR_NONE) {
Dan Born8886a812016-07-08 16:06:07 -0700315 *out_port = sp2->port;
316 if (sp != NULL) {
317 sp2->is_sibling = 1;
318 sp->sibling = sp2;
319 }
320 }
321 if (*out_port > 0) {
Yuchen Zengcb2f3f62017-03-17 14:30:09 -0700322 if (v6_err != GRPC_ERROR_NONE) {
323 gpr_log(GPR_INFO,
324 "Failed to add :: listener, "
325 "the environment may not support IPv6: %s",
326 grpc_error_string(v6_err));
327 GRPC_ERROR_UNREF(v6_err);
328 }
329 if (v4_err != GRPC_ERROR_NONE) {
330 gpr_log(GPR_INFO,
331 "Failed to add 0.0.0.0 listener, "
332 "the environment may not support IPv4: %s",
333 grpc_error_string(v4_err));
334 GRPC_ERROR_UNREF(v4_err);
335 }
Dan Born8886a812016-07-08 16:06:07 -0700336 return GRPC_ERROR_NONE;
337 } else {
ncteisen4b36a3d2017-03-13 19:08:06 -0700338 grpc_error *root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
339 "Failed to add any wildcard listeners");
Dan Born8886a812016-07-08 16:06:07 -0700340 GPR_ASSERT(v6_err != GRPC_ERROR_NONE && v4_err != GRPC_ERROR_NONE);
341 root_err = grpc_error_add_child(root_err, v6_err);
342 root_err = grpc_error_add_child(root_err, v4_err);
343 return root_err;
344 }
345}
346
Craig Tilleref962642016-05-18 22:57:17 -0700347static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
348 grpc_tcp_listener *sp = NULL;
349 char *addr_str;
350 char *name;
351 grpc_error *err;
352
353 for (grpc_tcp_listener *l = listener->next; l && l->is_sibling; l = l->next) {
354 l->fd_index += count;
355 }
356
357 for (unsigned i = 0; i < count; i++) {
Craig Tiller136698c2016-05-19 11:49:44 -0700358 int fd = -1;
359 int port = -1;
Craig Tilleref962642016-05-18 22:57:17 -0700360 grpc_dualstack_mode dsmode;
murgatroid99dedb9232016-09-26 13:54:04 -0700361 err = grpc_create_dualstack_socket(&listener->addr, SOCK_STREAM, 0, &dsmode,
362 &fd);
Craig Tilleref962642016-05-18 22:57:17 -0700363 if (err != GRPC_ERROR_NONE) return err;
Yuchen Zeng68745bb2017-03-14 17:51:07 -0700364 err = grpc_tcp_server_prepare_socket(fd, &listener->addr, true, &port);
Craig Tilleref962642016-05-18 22:57:17 -0700365 if (err != GRPC_ERROR_NONE) return err;
Craig Tiller644da982016-05-19 09:19:28 -0700366 listener->server->nports++;
murgatroid997871f732016-09-23 13:49:05 -0700367 grpc_sockaddr_to_string(&addr_str, &listener->addr, 1);
Craig Tilleref962642016-05-18 22:57:17 -0700368 gpr_asprintf(&name, "tcp-server-listener:%s/clone-%d", addr_str, i);
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700369 sp = (grpc_tcp_listener *)gpr_malloc(sizeof(grpc_tcp_listener));
Craig Tilleref962642016-05-18 22:57:17 -0700370 sp->next = listener->next;
371 listener->next = sp;
Dan Bornad1f31f2016-07-08 13:24:49 -0700372 /* sp (the new listener) is a sibling of 'listener' (the original
373 listener). */
374 sp->is_sibling = 1;
375 sp->sibling = listener->sibling;
376 listener->sibling = sp;
Craig Tilleref962642016-05-18 22:57:17 -0700377 sp->server = listener->server;
378 sp->fd = fd;
379 sp->emfd = grpc_fd_create(fd, name);
murgatroid997871f732016-09-23 13:49:05 -0700380 memcpy(&sp->addr, &listener->addr, sizeof(grpc_resolved_address));
Craig Tilleref962642016-05-18 22:57:17 -0700381 sp->port = port;
382 sp->port_index = listener->port_index;
383 sp->fd_index = listener->fd_index + count - i;
Craig Tilleref962642016-05-18 22:57:17 -0700384 GPR_ASSERT(sp->emfd);
385 while (listener->server->tail->next != NULL) {
386 listener->server->tail = listener->server->tail->next;
387 }
388 gpr_free(addr_str);
389 gpr_free(name);
390 }
391
392 return GRPC_ERROR_NONE;
393}
394
murgatroid997871f732016-09-23 13:49:05 -0700395grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s,
396 const grpc_resolved_address *addr,
397 int *out_port) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800398 grpc_tcp_listener *sp;
murgatroid997871f732016-09-23 13:49:05 -0700399 grpc_resolved_address sockname_temp;
Dan Born8886a812016-07-08 16:06:07 -0700400 grpc_resolved_address addr6_v4mapped;
401 int requested_port = grpc_sockaddr_get_port(addr);
Dan Bornfa6b6062016-01-08 21:01:59 -0800402 unsigned port_index = 0;
Dan Born8886a812016-07-08 16:06:07 -0700403 grpc_dualstack_mode dsmode;
404 grpc_error *err;
405 *out_port = -1;
Dan Bornfa6b6062016-01-08 21:01:59 -0800406 if (s->tail != NULL) {
407 port_index = s->tail->port_index + 1;
408 }
murgatroid997871f732016-09-23 13:49:05 -0700409 grpc_unlink_if_unix_domain_socket(addr);
Craig Tilleraa31da42015-02-17 16:33:35 -0800410
ctiller570d1f42015-01-12 16:29:52 -0800411 /* Check if this is a wildcard port, and if so, try to keep the port the same
412 as some previously created listener. */
Dan Born8886a812016-07-08 16:06:07 -0700413 if (requested_port == 0) {
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800414 for (sp = s->head; sp; sp = sp->next) {
murgatroid997871f732016-09-23 13:49:05 -0700415 sockname_temp.len = sizeof(struct sockaddr_storage);
Dan Born8886a812016-07-08 16:06:07 -0700416 if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp.addr,
murgatroid997871f732016-09-23 13:49:05 -0700417 (socklen_t *)&sockname_temp.len)) {
Dan Born8886a812016-07-08 16:06:07 -0700418 int used_port = grpc_sockaddr_get_port(&sockname_temp);
419 if (used_port > 0) {
420 memcpy(&sockname_temp, addr, sizeof(grpc_resolved_address));
421 grpc_sockaddr_set_port(&sockname_temp, used_port);
422 requested_port = used_port;
423 addr = &sockname_temp;
Craig Tillera82950e2015-09-22 12:33:20 -0700424 break;
425 }
426 }
ctiller570d1f42015-01-12 16:29:52 -0800427 }
Craig Tillera82950e2015-09-22 12:33:20 -0700428 }
Dan Born8886a812016-07-08 16:06:07 -0700429 if (grpc_sockaddr_is_wildcard(addr, &requested_port)) {
430 return add_wildcard_addrs_to_server(s, port_index, requested_port,
431 out_port);
432 }
Craig Tillera82950e2015-09-22 12:33:20 -0700433 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
murgatroid997871f732016-09-23 13:49:05 -0700434 addr = &addr6_v4mapped;
Craig Tillera82950e2015-09-22 12:33:20 -0700435 }
Yuchen Zeng47155ed2017-03-13 17:18:07 -0700436 if ((err = grpc_tcp_server_add_addr(s, addr, port_index, 0, &dsmode, &sp)) ==
Dan Born8886a812016-07-08 16:06:07 -0700437 GRPC_ERROR_NONE) {
Craig Tillerc027e772016-05-03 16:27:00 -0700438 *out_port = sp->port;
Dan Bornfa6b6062016-01-08 21:01:59 -0800439 }
Dan Born8886a812016-07-08 16:06:07 -0700440 return err;
nnoble0c475f02014-12-05 15:37:39 -0800441}
442
Dan Born19e01fd2016-10-18 11:49:45 -0700443/* Return listener at port_index or NULL. Should only be called with s->mu
444 locked. */
Dan Born4e826be2016-10-03 20:33:25 -0700445static grpc_tcp_listener *get_port_index(grpc_tcp_server *s,
446 unsigned port_index) {
447 unsigned num_ports = 0;
448 grpc_tcp_listener *sp;
449 for (sp = s->head; sp; sp = sp->next) {
450 if (!sp->is_sibling) {
451 if (++num_ports > port_index) {
452 return sp;
453 }
454 }
455 }
456 return NULL;
457}
458
Dan Born5d81d152016-01-12 20:29:29 -0800459unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
460 unsigned port_index) {
Dan Bornfa6b6062016-01-08 21:01:59 -0800461 unsigned num_fds = 0;
Dan Born930c2982016-09-08 19:12:18 -0700462 gpr_mu_lock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700463 grpc_tcp_listener *sp = get_port_index(s, port_index);
464 for (; sp; sp = sp->sibling) {
465 ++num_fds;
Dan Bornfa6b6062016-01-08 21:01:59 -0800466 }
Dan Born930c2982016-09-08 19:12:18 -0700467 gpr_mu_unlock(&s->mu);
Dan Bornfa6b6062016-01-08 21:01:59 -0800468 return num_fds;
469}
470
Dan Born5d81d152016-01-12 20:29:29 -0800471int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
472 unsigned fd_index) {
Dan Born930c2982016-09-08 19:12:18 -0700473 gpr_mu_lock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700474 grpc_tcp_listener *sp = get_port_index(s, port_index);
475 for (; sp; sp = sp->sibling, --fd_index) {
476 if (fd_index == 0) {
Dan Bornd9b763b2016-10-17 15:00:20 -0700477 gpr_mu_unlock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700478 return sp->fd;
Dan Bornfa6b6062016-01-08 21:01:59 -0800479 }
480 }
Dan Born930c2982016-09-08 19:12:18 -0700481 gpr_mu_unlock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700482 return -1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800483}
484
Craig Tillera82950e2015-09-22 12:33:20 -0700485void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
486 grpc_pollset **pollsets, size_t pollset_count,
487 grpc_tcp_server_cb on_accept_cb,
488 void *on_accept_cb_arg) {
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800489 size_t i;
Nicolas Noble8f714622015-11-19 11:16:54 -0800490 grpc_tcp_listener *sp;
Craig Tillera82950e2015-09-22 12:33:20 -0700491 GPR_ASSERT(on_accept_cb);
492 gpr_mu_lock(&s->mu);
493 GPR_ASSERT(!s->on_accept_cb);
494 GPR_ASSERT(s->active_ports == 0);
Robbie Shade3cd2d182015-08-28 14:30:35 -0400495 s->on_accept_cb = on_accept_cb;
496 s->on_accept_cb_arg = on_accept_cb_arg;
Craig Tiller0189ac02015-05-11 14:59:19 -0700497 s->pollsets = pollsets;
498 s->pollset_count = pollset_count;
Craig Tilleref962642016-05-18 22:57:17 -0700499 sp = s->head;
500 while (sp != NULL) {
murgatroid997871f732016-09-23 13:49:05 -0700501 if (s->so_reuseport && !grpc_is_unix_socket(&sp->addr) &&
Yuchen Zengd745a6f2016-08-08 20:44:36 -0700502 pollset_count > 1) {
Craig Tilleref962642016-05-18 22:57:17 -0700503 GPR_ASSERT(GRPC_LOG_IF_ERROR(
504 "clone_port", clone_port(sp, (unsigned)(pollset_count - 1))));
505 for (i = 0; i < pollset_count; i++) {
506 grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
ncteisen274bbbe2017-06-08 14:57:11 -0700507 GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp,
Craig Tiller3cb34472016-12-28 16:11:38 -0800508 grpc_schedule_on_exec_ctx);
Craig Tilleref962642016-05-18 22:57:17 -0700509 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
510 s->active_ports++;
511 sp = sp->next;
512 }
513 } else {
514 for (i = 0; i < pollset_count; i++) {
515 grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
516 }
ncteisen274bbbe2017-06-08 14:57:11 -0700517 GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp,
Craig Tiller3cb34472016-12-28 16:11:38 -0800518 grpc_schedule_on_exec_ctx);
Craig Tilleref962642016-05-18 22:57:17 -0700519 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
520 s->active_ports++;
521 sp = sp->next;
ctiller58393c22015-01-07 14:03:30 -0800522 }
Craig Tillera82950e2015-09-22 12:33:20 -0700523 }
524 gpr_mu_unlock(&s->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800525}
Craig Tiller0c0b60c2015-01-21 15:49:28 -0800526
Dan Bornfa6b6062016-01-08 21:01:59 -0800527grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
Dan Born930c2982016-09-08 19:12:18 -0700528 gpr_ref_non_zero(&s->refs);
Dan Bornfa6b6062016-01-08 21:01:59 -0800529 return s;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800530}
531
Dan Born9c12bc22016-01-13 16:52:20 -0800532void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
533 grpc_closure *shutdown_starting) {
534 gpr_mu_lock(&s->mu);
Craig Tillerc027e772016-05-03 16:27:00 -0700535 grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
536 GRPC_ERROR_NONE);
Dan Born9c12bc22016-01-13 16:52:20 -0800537 gpr_mu_unlock(&s->mu);
538}
539
Dan Bornfa6b6062016-01-08 21:01:59 -0800540void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
541 if (gpr_unref(&s->refs)) {
Dan Born930c2982016-09-08 19:12:18 -0700542 grpc_tcp_server_shutdown_listeners(exec_ctx, s);
Dan Born9c12bc22016-01-13 16:52:20 -0800543 gpr_mu_lock(&s->mu);
ncteisen274bbbe2017-06-08 14:57:11 -0700544 GRPC_CLOSURE_LIST_SCHED(exec_ctx, &s->shutdown_starting);
Dan Born9c12bc22016-01-13 16:52:20 -0800545 gpr_mu_unlock(&s->mu);
Dan Born930c2982016-09-08 19:12:18 -0700546 tcp_server_destroy(exec_ctx, s);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800547 }
548}
549
yang-g9275d402016-07-11 16:51:39 -0700550void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
551 grpc_tcp_server *s) {
552 gpr_mu_lock(&s->mu);
Craig Tillerf26236a2017-03-07 09:43:51 -0800553 s->shutdown_listeners = true;
yang-g9275d402016-07-11 16:51:39 -0700554 /* shutdown all fd's */
555 if (s->active_ports) {
556 grpc_tcp_listener *sp;
557 for (sp = s->head; sp; sp = sp->next) {
Craig Tillercda759d2017-01-27 11:37:37 -0800558 grpc_fd_shutdown(exec_ctx, sp->emfd,
ncteisen4b36a3d2017-03-13 19:08:06 -0700559 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"));
yang-g9275d402016-07-11 16:51:39 -0700560 }
561 }
562 gpr_mu_unlock(&s->mu);
563}
564
Craig Tiller190d3602015-02-18 09:23:38 -0800565#endif