blob: e9e7511c9cc40ca76136a1104c0fe3e419acab13 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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
David Klempner78b79922015-02-04 10:18:59 -080034/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
35#ifndef _GNU_SOURCE
36#define _GNU_SOURCE
37#endif
38
murgatroid9954070892016-08-08 17:01:18 -070039#include "src/core/lib/iomgr/port.h"
Craig Tiller0c0b60c2015-01-21 15:49:28 -080040
murgatroid99623dd4f2016-08-08 17:31:27 -070041#ifdef GRPC_POSIX_SOCKET
Craig Tiller0c0b60c2015-01-21 15:49:28 -080042
Craig Tiller9533d042016-03-25 17:11:06 -070043#include "src/core/lib/iomgr/tcp_server.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080044
Craig Tilleraa31da42015-02-17 16:33:35 -080045#include <errno.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080046#include <fcntl.h>
Craig Tilleraa31da42015-02-17 16:33:35 -080047#include <limits.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080048#include <netinet/in.h>
49#include <netinet/tcp.h>
50#include <stdio.h>
Craig Tilleraa31da42015-02-17 16:33:35 -080051#include <string.h>
52#include <sys/socket.h>
53#include <sys/stat.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054#include <sys/types.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080055#include <unistd.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080056
Craig Tillerf40df232016-03-25 13:38:14 -070057#include <grpc/support/alloc.h>
58#include <grpc/support/log.h>
59#include <grpc/support/string_util.h>
60#include <grpc/support/sync.h>
61#include <grpc/support/time.h>
Craig Tillerc027e772016-05-03 16:27:00 -070062#include <grpc/support/useful.h>
63
Craig Tiller9533d042016-03-25 17:11:06 -070064#include "src/core/lib/iomgr/resolve_address.h"
murgatroid997871f732016-09-23 13:49:05 -070065#include "src/core/lib/iomgr/sockaddr.h"
Craig Tiller9533d042016-03-25 17:11:06 -070066#include "src/core/lib/iomgr/sockaddr_utils.h"
67#include "src/core/lib/iomgr/socket_utils_posix.h"
68#include "src/core/lib/iomgr/tcp_posix.h"
69#include "src/core/lib/iomgr/unix_sockets_posix.h"
70#include "src/core/lib/support/string.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080071
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080072#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
73
74static gpr_once s_init_max_accept_queue_size;
75static int s_max_accept_queue_size;
76
77/* one listening port */
Dan Bornfa6b6062016-01-08 21:01:59 -080078typedef struct grpc_tcp_listener grpc_tcp_listener;
Nicolas Noble8f714622015-11-19 11:16:54 -080079struct grpc_tcp_listener {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080080 int fd;
ctiller18b49ab2014-12-09 14:39:16 -080081 grpc_fd *emfd;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082 grpc_tcp_server *server;
murgatroid997871f732016-09-23 13:49:05 -070083 grpc_resolved_address addr;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -080084 int port;
Dan Bornfa6b6062016-01-08 21:01:59 -080085 unsigned port_index;
86 unsigned fd_index;
Craig Tiller33825112015-09-18 07:44:19 -070087 grpc_closure read_closure;
88 grpc_closure destroyed_closure;
Nicolas Noble8f714622015-11-19 11:16:54 -080089 struct grpc_tcp_listener *next;
Dan Bornad1f31f2016-07-08 13:24:49 -070090 /* sibling is a linked list of all listeners for a given port. add_port and
91 clone_port place all new listeners in the same sibling list. A member of
92 the 'sibling' list is also a member of the 'next' list. The head of each
93 sibling list has is_sibling==0, and subsequent members of sibling lists
94 have is_sibling==1. is_sibling allows separate sibling lists to be
95 identified while iterating through 'next'. */
Nicolas "Pixel" Nobled86115e2015-11-20 05:56:25 +010096 struct grpc_tcp_listener *sibling;
97 int is_sibling;
Nicolas Noble8f714622015-11-19 11:16:54 -080098};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080099
100/* the overall server */
Craig Tillera82950e2015-09-22 12:33:20 -0700101struct grpc_tcp_server {
Dan Bornfa6b6062016-01-08 21:01:59 -0800102 gpr_refcount refs;
Robbie Shade3cd2d182015-08-28 14:30:35 -0400103 /* Called whenever accept() succeeds on a server port. */
104 grpc_tcp_server_cb on_accept_cb;
105 void *on_accept_cb_arg;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800106
107 gpr_mu mu;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800108
109 /* active port count: how many ports are actually still listening */
Craig Tilleraec96aa2015-04-07 14:32:15 -0700110 size_t active_ports;
111 /* destroyed port count: how many ports are completely destroyed */
112 size_t destroyed_ports;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800113
Craig Tilleref962642016-05-18 22:57:17 -0700114 /* is this server shutting down? */
115 bool shutdown;
116 /* use SO_REUSEPORT */
117 bool so_reuseport;
Craig Tiller6f051402015-05-13 11:42:42 -0700118
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800119 /* linked list of server ports */
Nicolas Noble8f714622015-11-19 11:16:54 -0800120 grpc_tcp_listener *head;
Dan Bornfa6b6062016-01-08 21:01:59 -0800121 grpc_tcp_listener *tail;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800122 unsigned nports;
Craig Tilleraec96aa2015-04-07 14:32:15 -0700123
Dan Born9c12bc22016-01-13 16:52:20 -0800124 /* List of closures passed to shutdown_starting_add(). */
125 grpc_closure_list shutdown_starting;
126
Craig Tilleraec96aa2015-04-07 14:32:15 -0700127 /* shutdown callback */
Craig Tillerd1bec032015-09-18 17:29:00 -0700128 grpc_closure *shutdown_complete;
Craig Tiller0189ac02015-05-11 14:59:19 -0700129
Craig Tiller6174b9a2015-06-18 08:13:05 -0700130 /* all pollsets interested in new connections */
Craig Tiller0189ac02015-05-11 14:59:19 -0700131 grpc_pollset **pollsets;
Craig Tiller6174b9a2015-06-18 08:13:05 -0700132 /* number of pollsets in the pollsets array */
Craig Tiller0189ac02015-05-11 14:59:19 -0700133 size_t pollset_count;
Craig Tiller53dd6b92016-05-24 13:49:50 -0700134
135 /* next pollset to assign a channel to */
Craig Tillerb76471d2016-07-01 10:24:56 -0700136 gpr_atm next_pollset_to_assign;
Craig Tillere34c2852016-09-23 09:43:32 -0700137
Craig Tiller20afa3d2016-10-17 14:52:14 -0700138 grpc_resource_quota *resource_quota;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800139};
140
Craig Tilleref962642016-05-18 22:57:17 -0700141static gpr_once check_init = GPR_ONCE_INIT;
Nicolas "Pixel" Noblebaa35fc2016-08-19 02:20:11 +0200142static bool has_so_reuseport = false;
Craig Tilleref962642016-05-18 22:57:17 -0700143
144static void init(void) {
Nicolas "Pixel" Noblebaa35fc2016-08-19 02:20:11 +0200145#ifndef GPR_MANYLINUX1
Craig Tilleref962642016-05-18 22:57:17 -0700146 int s = socket(AF_INET, SOCK_STREAM, 0);
147 if (s >= 0) {
148 has_so_reuseport = GRPC_LOG_IF_ERROR("check for SO_REUSEPORT",
149 grpc_set_socket_reuse_port(s, 1));
150 close(s);
151 }
Nicolas "Pixel" Noblebaa35fc2016-08-19 02:20:11 +0200152#endif
Craig Tilleref962642016-05-18 22:57:17 -0700153}
154
Craig Tillere34c2852016-09-23 09:43:32 -0700155grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
156 grpc_closure *shutdown_complete,
Craig Tilleref962642016-05-18 22:57:17 -0700157 const grpc_channel_args *args,
Craig Tiller0b5857f2016-05-04 10:58:06 -0700158 grpc_tcp_server **server) {
Craig Tilleref962642016-05-18 22:57:17 -0700159 gpr_once_init(&check_init, init);
160
Craig Tillera82950e2015-09-22 12:33:20 -0700161 grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
Craig Tilleref962642016-05-18 22:57:17 -0700162 s->so_reuseport = has_so_reuseport;
Craig Tiller20afa3d2016-10-17 14:52:14 -0700163 s->resource_quota = grpc_resource_quota_create(NULL);
Craig Tilleref962642016-05-18 22:57:17 -0700164 for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
165 if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
166 if (args->args[i].type == GRPC_ARG_INTEGER) {
167 s->so_reuseport =
168 has_so_reuseport && (args->args[i].value.integer != 0);
169 } else {
Craig Tillera59c16c2016-10-31 07:25:01 -0700170 grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
Craig Tilleref962642016-05-18 22:57:17 -0700171 gpr_free(s);
172 return GRPC_ERROR_CREATE(GRPC_ARG_ALLOW_REUSEPORT
173 " must be an integer");
174 }
Craig Tiller153eaa72016-10-21 13:52:36 -0700175 } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
Craig Tillere34c2852016-09-23 09:43:32 -0700176 if (args->args[i].type == GRPC_ARG_POINTER) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700177 grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
Craig Tiller20afa3d2016-10-17 14:52:14 -0700178 s->resource_quota =
Craig Tillera59c16c2016-10-31 07:25:01 -0700179 grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
Craig Tillere34c2852016-09-23 09:43:32 -0700180 } else {
Craig Tillera59c16c2016-10-31 07:25:01 -0700181 grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
Craig Tillere34c2852016-09-23 09:43:32 -0700182 gpr_free(s);
Craig Tiller153eaa72016-10-21 13:52:36 -0700183 return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA
Craig Tillere34c2852016-09-23 09:43:32 -0700184 " must be a pointer to a buffer pool");
185 }
Craig Tilleref962642016-05-18 22:57:17 -0700186 }
187 }
Dan Bornfa6b6062016-01-08 21:01:59 -0800188 gpr_ref_init(&s->refs, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700189 gpr_mu_init(&s->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800190 s->active_ports = 0;
Craig Tilleraec96aa2015-04-07 14:32:15 -0700191 s->destroyed_ports = 0;
Craig Tilleref962642016-05-18 22:57:17 -0700192 s->shutdown = false;
Dan Born9c12bc22016-01-13 16:52:20 -0800193 s->shutdown_starting.head = NULL;
194 s->shutdown_starting.tail = NULL;
Dan Bornfa6b6062016-01-08 21:01:59 -0800195 s->shutdown_complete = shutdown_complete;
Robbie Shade3cd2d182015-08-28 14:30:35 -0400196 s->on_accept_cb = NULL;
197 s->on_accept_cb_arg = NULL;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800198 s->head = NULL;
Dan Bornfa6b6062016-01-08 21:01:59 -0800199 s->tail = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800200 s->nports = 0;
Craig Tillerb76471d2016-07-01 10:24:56 -0700201 gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0);
Craig Tiller0b5857f2016-05-04 10:58:06 -0700202 *server = s;
203 return GRPC_ERROR_NONE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800204}
205
Craig Tillera82950e2015-09-22 12:33:20 -0700206static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Dan Born930c2982016-09-08 19:12:18 -0700207 gpr_mu_lock(&s->mu);
208 GPR_ASSERT(s->shutdown);
209 gpr_mu_unlock(&s->mu);
Dan Bornfa6b6062016-01-08 21:01:59 -0800210 if (s->shutdown_complete != NULL) {
Craig Tiller91031da2016-12-28 15:44:25 -0800211 grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
Dan Bornfa6b6062016-01-08 21:01:59 -0800212 }
Craig Tilleraec96aa2015-04-07 14:32:15 -0700213
Craig Tillera82950e2015-09-22 12:33:20 -0700214 gpr_mu_destroy(&s->mu);
Craig Tilleraec96aa2015-04-07 14:32:15 -0700215
Nicolas "Pixel" Noblec6a7c6e2015-11-19 21:55:44 +0100216 while (s->head) {
217 grpc_tcp_listener *sp = s->head;
218 s->head = sp->next;
Dan Bornfa6b6062016-01-08 21:01:59 -0800219 gpr_free(sp);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800220 }
221
Craig Tillera59c16c2016-10-31 07:25:01 -0700222 grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
Craig Tillere34c2852016-09-23 09:43:32 -0700223
Craig Tillera82950e2015-09-22 12:33:20 -0700224 gpr_free(s);
Craig Tilleraec96aa2015-04-07 14:32:15 -0700225}
226
Craig Tiller6c396862016-01-28 13:53:40 -0800227static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
Craig Tillerc027e772016-05-03 16:27:00 -0700228 grpc_error *error) {
Craig Tilleraec96aa2015-04-07 14:32:15 -0700229 grpc_tcp_server *s = server;
Craig Tillera82950e2015-09-22 12:33:20 -0700230 gpr_mu_lock(&s->mu);
Craig Tilleraec96aa2015-04-07 14:32:15 -0700231 s->destroyed_ports++;
Craig Tillera82950e2015-09-22 12:33:20 -0700232 if (s->destroyed_ports == s->nports) {
233 gpr_mu_unlock(&s->mu);
234 finish_shutdown(exec_ctx, s);
235 } else {
236 GPR_ASSERT(s->destroyed_ports < s->nports);
237 gpr_mu_unlock(&s->mu);
238 }
Craig Tilleraec96aa2015-04-07 14:32:15 -0700239}
240
Craig Tiller6174b9a2015-06-18 08:13:05 -0700241/* called when all listening endpoints have been shutdown, so no further
242 events will be received on them - at this point it's safe to destroy
243 things */
Craig Tillera82950e2015-09-22 12:33:20 -0700244static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800245 /* delete ALL the things */
Craig Tillera82950e2015-09-22 12:33:20 -0700246 gpr_mu_lock(&s->mu);
Craig Tiller6f051402015-05-13 11:42:42 -0700247
Craig Tillera82950e2015-09-22 12:33:20 -0700248 if (!s->shutdown) {
249 gpr_mu_unlock(&s->mu);
250 return;
251 }
Craig Tiller45724b32015-09-22 10:42:19 -0700252
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800253 if (s->head) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800254 grpc_tcp_listener *sp;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800255 for (sp = s->head; sp; sp = sp->next) {
murgatroid997871f732016-09-23 13:49:05 -0700256 grpc_unlink_if_unix_domain_socket(&sp->addr);
Craig Tiller3cb34472016-12-28 16:11:38 -0800257 grpc_closure_init(&sp->destroyed_closure, destroyed_port, s,
258 grpc_schedule_on_exec_ctx);
yang-g5d850372015-12-01 10:32:28 -0800259 grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
Craig Tillera82950e2015-09-22 12:33:20 -0700260 "tcp_listener_shutdown");
Craig Tiller45724b32015-09-22 10:42:19 -0700261 }
Craig Tillera82950e2015-09-22 12:33:20 -0700262 gpr_mu_unlock(&s->mu);
263 } else {
264 gpr_mu_unlock(&s->mu);
265 finish_shutdown(exec_ctx, s);
266 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800267}
268
Dan Born5d81d152016-01-12 20:29:29 -0800269static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
Craig Tillera82950e2015-09-22 12:33:20 -0700270 gpr_mu_lock(&s->mu);
Craig Tiller6f051402015-05-13 11:42:42 -0700271
Craig Tillera82950e2015-09-22 12:33:20 -0700272 GPR_ASSERT(!s->shutdown);
Craig Tilleref962642016-05-18 22:57:17 -0700273 s->shutdown = true;
Craig Tiller6f051402015-05-13 11:42:42 -0700274
Craig Tiller6f051402015-05-13 11:42:42 -0700275 /* shutdown all fd's */
Craig Tillera82950e2015-09-22 12:33:20 -0700276 if (s->active_ports) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800277 grpc_tcp_listener *sp;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800278 for (sp = s->head; sp; sp = sp->next) {
Craig Tillercda759d2017-01-27 11:37:37 -0800279 grpc_fd_shutdown(exec_ctx, sp->emfd,
280 GRPC_ERROR_CREATE("Server destroyed"));
Craig Tiller6f051402015-05-13 11:42:42 -0700281 }
Craig Tillera82950e2015-09-22 12:33:20 -0700282 gpr_mu_unlock(&s->mu);
283 } else {
284 gpr_mu_unlock(&s->mu);
285 deactivated_all_ports(exec_ctx, s);
286 }
Craig Tiller6f051402015-05-13 11:42:42 -0700287}
288
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800289/* get max listen queue size on linux */
Craig Tillera82950e2015-09-22 12:33:20 -0700290static void init_max_accept_queue_size(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800291 int n = SOMAXCONN;
292 char buf[64];
Craig Tillera82950e2015-09-22 12:33:20 -0700293 FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
294 if (fp == NULL) {
295 /* 2.4 kernel. */
296 s_max_accept_queue_size = SOMAXCONN;
297 return;
298 }
299 if (fgets(buf, sizeof buf, fp)) {
300 char *end;
301 long i = strtol(buf, &end, 10);
302 if (i > 0 && i <= INT_MAX && end && *end == 0) {
303 n = (int)i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800304 }
Craig Tillera82950e2015-09-22 12:33:20 -0700305 }
306 fclose(fp);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800307 s_max_accept_queue_size = n;
308
Craig Tillera82950e2015-09-22 12:33:20 -0700309 if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
310 gpr_log(GPR_INFO,
311 "Suspiciously small accept queue (%d) will probably lead to "
312 "connection drops",
313 s_max_accept_queue_size);
314 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800315}
316
Craig Tillera82950e2015-09-22 12:33:20 -0700317static int get_max_accept_queue_size(void) {
318 gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800319 return s_max_accept_queue_size;
320}
321
nnoble0c475f02014-12-05 15:37:39 -0800322/* Prepare a recently-created socket for listening. */
murgatroid997871f732016-09-23 13:49:05 -0700323static grpc_error *prepare_socket(int fd, const grpc_resolved_address *addr,
324 bool so_reuseport, int *port) {
325 grpc_resolved_address sockname_temp;
Craig Tiller80384bd2016-05-06 16:12:31 -0700326 grpc_error *err = GRPC_ERROR_NONE;
ctiller570d1f42015-01-12 16:29:52 -0800327
Craig Tiller80384bd2016-05-06 16:12:31 -0700328 GPR_ASSERT(fd >= 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800329
Yuchen Zeng2414bbb2016-08-08 21:22:54 -0700330 if (so_reuseport && !grpc_is_unix_socket(addr)) {
Craig Tilleref962642016-05-18 22:57:17 -0700331 err = grpc_set_socket_reuse_port(fd, 1);
332 if (err != GRPC_ERROR_NONE) goto error;
333 }
334
Craig Tiller80384bd2016-05-06 16:12:31 -0700335 err = grpc_set_socket_nonblocking(fd, 1);
336 if (err != GRPC_ERROR_NONE) goto error;
337 err = grpc_set_socket_cloexec(fd, 1);
338 if (err != GRPC_ERROR_NONE) goto error;
339 if (!grpc_is_unix_socket(addr)) {
340 err = grpc_set_socket_low_latency(fd, 1);
341 if (err != GRPC_ERROR_NONE) goto error;
342 err = grpc_set_socket_reuse_addr(fd, 1);
343 if (err != GRPC_ERROR_NONE) goto error;
Craig Tillera82950e2015-09-22 12:33:20 -0700344 }
Craig Tiller80384bd2016-05-06 16:12:31 -0700345 err = grpc_set_socket_no_sigpipe_if_possible(fd);
346 if (err != GRPC_ERROR_NONE) goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800347
murgatroid997871f732016-09-23 13:49:05 -0700348 GPR_ASSERT(addr->len < ~(socklen_t)0);
349 if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) {
David Garcia Quintas03291c42016-05-10 18:28:56 -0700350 err = GRPC_OS_ERROR(errno, "bind");
Craig Tillera82950e2015-09-22 12:33:20 -0700351 goto error;
352 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800353
Craig Tillera82950e2015-09-22 12:33:20 -0700354 if (listen(fd, get_max_accept_queue_size()) < 0) {
Craig Tiller80384bd2016-05-06 16:12:31 -0700355 err = GRPC_OS_ERROR(errno, "listen");
Craig Tillera82950e2015-09-22 12:33:20 -0700356 goto error;
357 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800358
murgatroid997871f732016-09-23 13:49:05 -0700359 sockname_temp.len = sizeof(struct sockaddr_storage);
360
murgatroid99dedb9232016-09-26 13:54:04 -0700361 if (getsockname(fd, (struct sockaddr *)sockname_temp.addr,
362 (socklen_t *)&sockname_temp.len) < 0) {
Craig Tiller80384bd2016-05-06 16:12:31 -0700363 err = GRPC_OS_ERROR(errno, "getsockname");
Craig Tillera82950e2015-09-22 12:33:20 -0700364 goto error;
365 }
ctiller570d1f42015-01-12 16:29:52 -0800366
murgatroid997871f732016-09-23 13:49:05 -0700367 *port = grpc_sockaddr_get_port(&sockname_temp);
Craig Tiller80384bd2016-05-06 16:12:31 -0700368 return GRPC_ERROR_NONE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800369
370error:
Craig Tiller94f84532016-05-06 21:03:29 -0700371 GPR_ASSERT(err != GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700372 if (fd >= 0) {
373 close(fd);
374 }
David Garcia Quintas32ec1332016-05-11 12:22:53 -0700375 grpc_error *ret = grpc_error_set_int(
Craig Tiller80384bd2016-05-06 16:12:31 -0700376 GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1),
377 GRPC_ERROR_INT_FD, fd);
David Garcia Quintas32ec1332016-05-11 12:22:53 -0700378 GRPC_ERROR_UNREF(err);
379 return ret;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800380}
381
382/* event manager callback when reads are ready */
Craig Tillerc027e772016-05-03 16:27:00 -0700383static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800384 grpc_tcp_listener *sp = arg;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800385
Craig Tillerc027e772016-05-03 16:27:00 -0700386 if (err != GRPC_ERROR_NONE) {
Craig Tillera82950e2015-09-22 12:33:20 -0700387 goto error;
388 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800389
Mark D. Rotheed38152016-12-08 13:59:13 -0800390 grpc_pollset *read_notifier_pollset =
Craig Tillerb76471d2016-07-01 10:24:56 -0700391 sp->server->pollsets[(size_t)gpr_atm_no_barrier_fetch_add(
392 &sp->server->next_pollset_to_assign, 1) %
Craig Tiller53dd6b92016-05-24 13:49:50 -0700393 sp->server->pollset_count];
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700394
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800395 /* loop until accept4 returns EAGAIN, and then re-arm notification */
Craig Tillera82950e2015-09-22 12:33:20 -0700396 for (;;) {
murgatroid997871f732016-09-23 13:49:05 -0700397 grpc_resolved_address addr;
Craig Tillera82950e2015-09-22 12:33:20 -0700398 char *addr_str;
399 char *name;
murgatroid997871f732016-09-23 13:49:05 -0700400 addr.len = sizeof(struct sockaddr_storage);
Craig Tillera82950e2015-09-22 12:33:20 -0700401 /* Note: If we ever decide to return this address to the user, remember to
402 strip off the ::ffff:0.0.0.0/96 prefix first. */
murgatroid997871f732016-09-23 13:49:05 -0700403 int fd = grpc_accept4(sp->fd, &addr, 1, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700404 if (fd < 0) {
405 switch (errno) {
406 case EINTR:
407 continue;
408 case EAGAIN:
409 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
410 return;
411 default:
412 gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno));
413 goto error;
414 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800415 }
416
Craig Tillera82950e2015-09-22 12:33:20 -0700417 grpc_set_socket_no_sigpipe_if_possible(fd);
418
murgatroid997871f732016-09-23 13:49:05 -0700419 addr_str = grpc_sockaddr_to_uri(&addr);
Craig Tillera82950e2015-09-22 12:33:20 -0700420 gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
421
422 if (grpc_tcp_trace) {
423 gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str);
424 }
425
Mark D. Rotheed38152016-12-08 13:59:13 -0800426 grpc_fd *fdobj = grpc_fd_create(fd, name);
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700427
428 if (read_notifier_pollset == NULL) {
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700429 gpr_log(GPR_ERROR, "Read notifier pollset is not set on the fd");
430 goto error;
Craig Tillera82950e2015-09-22 12:33:20 -0700431 }
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700432
Sree Kuchibhotla42b004a2016-04-08 14:41:49 -0700433 grpc_pollset_add_fd(exec_ctx, read_notifier_pollset, fdobj);
434
Mark D. Roth6c07bf82016-12-09 08:38:38 -0800435 // Create acceptor.
436 grpc_tcp_server_acceptor *acceptor = gpr_malloc(sizeof(*acceptor));
437 acceptor->from_server = sp->server;
438 acceptor->port_index = sp->port_index;
439 acceptor->fd_index = sp->fd_index;
440
Craig Tillera82950e2015-09-22 12:33:20 -0700441 sp->server->on_accept_cb(
442 exec_ctx, sp->server->on_accept_cb_arg,
Craig Tiller20afa3d2016-10-17 14:52:14 -0700443 grpc_tcp_create(fdobj, sp->server->resource_quota,
Craig Tillere34c2852016-09-23 09:43:32 -0700444 GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
Mark D. Rotheed38152016-12-08 13:59:13 -0800445 read_notifier_pollset, acceptor);
Craig Tillera82950e2015-09-22 12:33:20 -0700446
447 gpr_free(name);
448 gpr_free(addr_str);
449 }
450
yang-gb063c872015-10-07 11:40:13 -0700451 GPR_UNREACHABLE_CODE(return );
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800452
453error:
Craig Tillera82950e2015-09-22 12:33:20 -0700454 gpr_mu_lock(&sp->server->mu);
455 if (0 == --sp->server->active_ports) {
456 gpr_mu_unlock(&sp->server->mu);
457 deactivated_all_ports(exec_ctx, sp->server);
458 } else {
459 gpr_mu_unlock(&sp->server->mu);
460 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800461}
462
Craig Tiller80384bd2016-05-06 16:12:31 -0700463static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
murgatroid997871f732016-09-23 13:49:05 -0700464 const grpc_resolved_address *addr,
murgatroid99dedb9232016-09-26 13:54:04 -0700465 unsigned port_index, unsigned fd_index,
Craig Tiller80384bd2016-05-06 16:12:31 -0700466 grpc_tcp_listener **listener) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800467 grpc_tcp_listener *sp = NULL;
Craig Tiller91472962016-05-09 11:01:15 -0700468 int port = -1;
Craig Tillerfa275a92015-06-01 13:55:54 -0700469 char *addr_str;
470 char *name;
nnoble0c475f02014-12-05 15:37:39 -0800471
murgatroid997871f732016-09-23 13:49:05 -0700472 grpc_error *err = prepare_socket(fd, addr, s->so_reuseport, &port);
Craig Tiller80384bd2016-05-06 16:12:31 -0700473 if (err == GRPC_ERROR_NONE) {
Craig Tiller91472962016-05-09 11:01:15 -0700474 GPR_ASSERT(port > 0);
murgatroid997871f732016-09-23 13:49:05 -0700475 grpc_sockaddr_to_string(&addr_str, addr, 1);
Craig Tillera82950e2015-09-22 12:33:20 -0700476 gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
477 gpr_mu_lock(&s->mu);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800478 s->nports++;
Craig Tillera82950e2015-09-22 12:33:20 -0700479 GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
Nicolas Noble8f714622015-11-19 11:16:54 -0800480 sp = gpr_malloc(sizeof(grpc_tcp_listener));
Dan Bornfa6b6062016-01-08 21:01:59 -0800481 sp->next = NULL;
482 if (s->head == NULL) {
483 s->head = sp;
484 } else {
485 s->tail->next = sp;
486 }
487 s->tail = sp;
Craig Tillera82950e2015-09-22 12:33:20 -0700488 sp->server = s;
489 sp->fd = fd;
490 sp->emfd = grpc_fd_create(fd, name);
murgatroid997871f732016-09-23 13:49:05 -0700491 memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800492 sp->port = port;
Dan Bornfa6b6062016-01-08 21:01:59 -0800493 sp->port_index = port_index;
494 sp->fd_index = fd_index;
Nicolas "Pixel" Nobled86115e2015-11-20 05:56:25 +0100495 sp->is_sibling = 0;
496 sp->sibling = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700497 GPR_ASSERT(sp->emfd);
498 gpr_mu_unlock(&s->mu);
499 gpr_free(addr_str);
500 gpr_free(name);
501 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800502
Craig Tiller80384bd2016-05-06 16:12:31 -0700503 *listener = sp;
504 return err;
nnoble0c475f02014-12-05 15:37:39 -0800505}
506
Dan Bornad1f31f2016-07-08 13:24:49 -0700507/* Insert count new listeners after listener. Every new listener will have the
508 same listen address as listener (SO_REUSEPORT must be enabled). Every new
509 listener is a sibling of listener. */
Craig Tilleref962642016-05-18 22:57:17 -0700510static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
511 grpc_tcp_listener *sp = NULL;
512 char *addr_str;
513 char *name;
514 grpc_error *err;
515
516 for (grpc_tcp_listener *l = listener->next; l && l->is_sibling; l = l->next) {
517 l->fd_index += count;
518 }
519
520 for (unsigned i = 0; i < count; i++) {
Craig Tiller136698c2016-05-19 11:49:44 -0700521 int fd = -1;
522 int port = -1;
Craig Tilleref962642016-05-18 22:57:17 -0700523 grpc_dualstack_mode dsmode;
murgatroid99dedb9232016-09-26 13:54:04 -0700524 err = grpc_create_dualstack_socket(&listener->addr, SOCK_STREAM, 0, &dsmode,
525 &fd);
Craig Tilleref962642016-05-18 22:57:17 -0700526 if (err != GRPC_ERROR_NONE) return err;
murgatroid997871f732016-09-23 13:49:05 -0700527 err = prepare_socket(fd, &listener->addr, true, &port);
Craig Tilleref962642016-05-18 22:57:17 -0700528 if (err != GRPC_ERROR_NONE) return err;
Craig Tiller644da982016-05-19 09:19:28 -0700529 listener->server->nports++;
murgatroid997871f732016-09-23 13:49:05 -0700530 grpc_sockaddr_to_string(&addr_str, &listener->addr, 1);
Craig Tilleref962642016-05-18 22:57:17 -0700531 gpr_asprintf(&name, "tcp-server-listener:%s/clone-%d", addr_str, i);
532 sp = gpr_malloc(sizeof(grpc_tcp_listener));
533 sp->next = listener->next;
534 listener->next = sp;
Dan Bornad1f31f2016-07-08 13:24:49 -0700535 /* sp (the new listener) is a sibling of 'listener' (the original
536 listener). */
537 sp->is_sibling = 1;
538 sp->sibling = listener->sibling;
539 listener->sibling = sp;
Craig Tilleref962642016-05-18 22:57:17 -0700540 sp->server = listener->server;
541 sp->fd = fd;
542 sp->emfd = grpc_fd_create(fd, name);
murgatroid997871f732016-09-23 13:49:05 -0700543 memcpy(&sp->addr, &listener->addr, sizeof(grpc_resolved_address));
Craig Tilleref962642016-05-18 22:57:17 -0700544 sp->port = port;
545 sp->port_index = listener->port_index;
546 sp->fd_index = listener->fd_index + count - i;
Craig Tilleref962642016-05-18 22:57:17 -0700547 GPR_ASSERT(sp->emfd);
548 while (listener->server->tail->next != NULL) {
549 listener->server->tail = listener->server->tail->next;
550 }
551 gpr_free(addr_str);
552 gpr_free(name);
553 }
554
555 return GRPC_ERROR_NONE;
556}
557
murgatroid997871f732016-09-23 13:49:05 -0700558grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s,
559 const grpc_resolved_address *addr,
560 int *out_port) {
Nicolas Noble8f714622015-11-19 11:16:54 -0800561 grpc_tcp_listener *sp;
562 grpc_tcp_listener *sp2 = NULL;
nnoble0c475f02014-12-05 15:37:39 -0800563 int fd;
564 grpc_dualstack_mode dsmode;
murgatroid997871f732016-09-23 13:49:05 -0700565 grpc_resolved_address addr6_v4mapped;
566 grpc_resolved_address wild4;
567 grpc_resolved_address wild6;
568 grpc_resolved_address addr4_copy;
569 grpc_resolved_address *allocated_addr = NULL;
570 grpc_resolved_address sockname_temp;
nnoble0c475f02014-12-05 15:37:39 -0800571 int port;
Dan Bornfa6b6062016-01-08 21:01:59 -0800572 unsigned port_index = 0;
573 unsigned fd_index = 0;
Craig Tillerc027e772016-05-03 16:27:00 -0700574 grpc_error *errs[2] = {GRPC_ERROR_NONE, GRPC_ERROR_NONE};
Dan Bornfa6b6062016-01-08 21:01:59 -0800575 if (s->tail != NULL) {
576 port_index = s->tail->port_index + 1;
577 }
murgatroid997871f732016-09-23 13:49:05 -0700578 grpc_unlink_if_unix_domain_socket(addr);
Craig Tilleraa31da42015-02-17 16:33:35 -0800579
ctiller570d1f42015-01-12 16:29:52 -0800580 /* Check if this is a wildcard port, and if so, try to keep the port the same
581 as some previously created listener. */
Craig Tillera82950e2015-09-22 12:33:20 -0700582 if (grpc_sockaddr_get_port(addr) == 0) {
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800583 for (sp = s->head; sp; sp = sp->next) {
murgatroid997871f732016-09-23 13:49:05 -0700584 sockname_temp.len = sizeof(struct sockaddr_storage);
585 if (0 == getsockname(sp->fd, (struct sockaddr *)sockname_temp.addr,
586 (socklen_t *)&sockname_temp.len)) {
587 port = grpc_sockaddr_get_port(&sockname_temp);
Craig Tillera82950e2015-09-22 12:33:20 -0700588 if (port > 0) {
murgatroid997871f732016-09-23 13:49:05 -0700589 allocated_addr = gpr_malloc(sizeof(grpc_resolved_address));
590 memcpy(allocated_addr, addr, addr->len);
Craig Tillera82950e2015-09-22 12:33:20 -0700591 grpc_sockaddr_set_port(allocated_addr, port);
592 addr = allocated_addr;
593 break;
594 }
595 }
ctiller570d1f42015-01-12 16:29:52 -0800596 }
Craig Tillera82950e2015-09-22 12:33:20 -0700597 }
ctiller570d1f42015-01-12 16:29:52 -0800598
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800599 sp = NULL;
600
Craig Tillera82950e2015-09-22 12:33:20 -0700601 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
murgatroid997871f732016-09-23 13:49:05 -0700602 addr = &addr6_v4mapped;
Craig Tillera82950e2015-09-22 12:33:20 -0700603 }
nnoble0c475f02014-12-05 15:37:39 -0800604
605 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
Craig Tillera82950e2015-09-22 12:33:20 -0700606 if (grpc_sockaddr_is_wildcard(addr, &port)) {
607 grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
nnoble0c475f02014-12-05 15:37:39 -0800608
Craig Tillera82950e2015-09-22 12:33:20 -0700609 /* Try listening on IPv6 first. */
murgatroid997871f732016-09-23 13:49:05 -0700610 addr = &wild6;
Craig Tillerc027e772016-05-03 16:27:00 -0700611 errs[0] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
612 if (errs[0] == GRPC_ERROR_NONE) {
murgatroid997871f732016-09-23 13:49:05 -0700613 errs[0] = add_socket_to_server(s, fd, addr, port_index, fd_index, &sp);
Craig Tillerc027e772016-05-03 16:27:00 -0700614 if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
615 goto done;
616 }
617 if (sp != NULL) {
618 ++fd_index;
619 }
620 /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
621 if (port == 0 && sp != NULL) {
murgatroid997871f732016-09-23 13:49:05 -0700622 grpc_sockaddr_set_port(&wild4, sp->port);
Craig Tillerc027e772016-05-03 16:27:00 -0700623 }
nnoble0c475f02014-12-05 15:37:39 -0800624 }
murgatroid997871f732016-09-23 13:49:05 -0700625 addr = &wild4;
Craig Tillera82950e2015-09-22 12:33:20 -0700626 }
627
Craig Tillerc027e772016-05-03 16:27:00 -0700628 errs[1] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
629 if (errs[1] == GRPC_ERROR_NONE) {
yang-g63460412016-03-22 14:58:15 -0700630 if (dsmode == GRPC_DSMODE_IPV4 &&
631 grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
murgatroid997871f732016-09-23 13:49:05 -0700632 addr = &addr4_copy;
yang-g63460412016-03-22 14:58:15 -0700633 }
yang-gb7921c72016-03-23 10:16:45 -0700634 sp2 = sp;
murgatroid997871f732016-09-23 13:49:05 -0700635 errs[1] = add_socket_to_server(s, fd, addr, port_index, fd_index, &sp);
yang-g63460412016-03-22 14:58:15 -0700636 if (sp2 != NULL && sp != NULL) {
637 sp2->sibling = sp;
638 sp->is_sibling = 1;
639 }
Dan Bornfa6b6062016-01-08 21:01:59 -0800640 }
ctiller570d1f42015-01-12 16:29:52 -0800641
642done:
Craig Tillera82950e2015-09-22 12:33:20 -0700643 gpr_free(allocated_addr);
Dan Bornfa6b6062016-01-08 21:01:59 -0800644 if (sp != NULL) {
Craig Tillerc027e772016-05-03 16:27:00 -0700645 *out_port = sp->port;
Craig Tillerf707d622016-05-06 14:26:12 -0700646 GRPC_ERROR_UNREF(errs[0]);
647 GRPC_ERROR_UNREF(errs[1]);
Craig Tillerc027e772016-05-03 16:27:00 -0700648 return GRPC_ERROR_NONE;
Dan Bornfa6b6062016-01-08 21:01:59 -0800649 } else {
Craig Tillerc027e772016-05-03 16:27:00 -0700650 *out_port = -1;
651 char *addr_str = grpc_sockaddr_to_uri(addr);
652 grpc_error *err = grpc_error_set_str(
653 GRPC_ERROR_CREATE_REFERENCING("Failed to add port to server", errs,
654 GPR_ARRAY_SIZE(errs)),
655 GRPC_ERROR_STR_TARGET_ADDRESS, addr_str);
David Garcia Quintas32ec1332016-05-11 12:22:53 -0700656 GRPC_ERROR_UNREF(errs[0]);
657 GRPC_ERROR_UNREF(errs[1]);
Craig Tillerc027e772016-05-03 16:27:00 -0700658 gpr_free(addr_str);
659 return err;
Dan Bornfa6b6062016-01-08 21:01:59 -0800660 }
nnoble0c475f02014-12-05 15:37:39 -0800661}
662
Dan Born19e01fd2016-10-18 11:49:45 -0700663/* Return listener at port_index or NULL. Should only be called with s->mu
664 locked. */
Dan Born4e826be2016-10-03 20:33:25 -0700665static grpc_tcp_listener *get_port_index(grpc_tcp_server *s,
666 unsigned port_index) {
667 unsigned num_ports = 0;
668 grpc_tcp_listener *sp;
669 for (sp = s->head; sp; sp = sp->next) {
670 if (!sp->is_sibling) {
671 if (++num_ports > port_index) {
672 return sp;
673 }
674 }
675 }
676 return NULL;
677}
678
Dan Born5d81d152016-01-12 20:29:29 -0800679unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
680 unsigned port_index) {
Dan Bornfa6b6062016-01-08 21:01:59 -0800681 unsigned num_fds = 0;
Dan Born930c2982016-09-08 19:12:18 -0700682 gpr_mu_lock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700683 grpc_tcp_listener *sp = get_port_index(s, port_index);
684 for (; sp; sp = sp->sibling) {
685 ++num_fds;
Dan Bornfa6b6062016-01-08 21:01:59 -0800686 }
Dan Born930c2982016-09-08 19:12:18 -0700687 gpr_mu_unlock(&s->mu);
Dan Bornfa6b6062016-01-08 21:01:59 -0800688 return num_fds;
689}
690
Dan Born5d81d152016-01-12 20:29:29 -0800691int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
692 unsigned fd_index) {
Dan Born930c2982016-09-08 19:12:18 -0700693 gpr_mu_lock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700694 grpc_tcp_listener *sp = get_port_index(s, port_index);
695 for (; sp; sp = sp->sibling, --fd_index) {
696 if (fd_index == 0) {
Dan Bornd9b763b2016-10-17 15:00:20 -0700697 gpr_mu_unlock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700698 return sp->fd;
Dan Bornfa6b6062016-01-08 21:01:59 -0800699 }
700 }
Dan Born930c2982016-09-08 19:12:18 -0700701 gpr_mu_unlock(&s->mu);
Dan Born4e826be2016-10-03 20:33:25 -0700702 return -1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800703}
704
Craig Tillera82950e2015-09-22 12:33:20 -0700705void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
706 grpc_pollset **pollsets, size_t pollset_count,
707 grpc_tcp_server_cb on_accept_cb,
708 void *on_accept_cb_arg) {
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800709 size_t i;
Nicolas Noble8f714622015-11-19 11:16:54 -0800710 grpc_tcp_listener *sp;
Craig Tillera82950e2015-09-22 12:33:20 -0700711 GPR_ASSERT(on_accept_cb);
712 gpr_mu_lock(&s->mu);
713 GPR_ASSERT(!s->on_accept_cb);
714 GPR_ASSERT(s->active_ports == 0);
Robbie Shade3cd2d182015-08-28 14:30:35 -0400715 s->on_accept_cb = on_accept_cb;
716 s->on_accept_cb_arg = on_accept_cb_arg;
Craig Tiller0189ac02015-05-11 14:59:19 -0700717 s->pollsets = pollsets;
718 s->pollset_count = pollset_count;
Craig Tilleref962642016-05-18 22:57:17 -0700719 sp = s->head;
720 while (sp != NULL) {
murgatroid997871f732016-09-23 13:49:05 -0700721 if (s->so_reuseport && !grpc_is_unix_socket(&sp->addr) &&
Yuchen Zengd745a6f2016-08-08 20:44:36 -0700722 pollset_count > 1) {
Craig Tilleref962642016-05-18 22:57:17 -0700723 GPR_ASSERT(GRPC_LOG_IF_ERROR(
724 "clone_port", clone_port(sp, (unsigned)(pollset_count - 1))));
725 for (i = 0; i < pollset_count; i++) {
726 grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
Craig Tiller3cb34472016-12-28 16:11:38 -0800727 grpc_closure_init(&sp->read_closure, on_read, sp,
728 grpc_schedule_on_exec_ctx);
Craig Tilleref962642016-05-18 22:57:17 -0700729 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
730 s->active_ports++;
731 sp = sp->next;
732 }
733 } else {
734 for (i = 0; i < pollset_count; i++) {
735 grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
736 }
Craig Tiller3cb34472016-12-28 16:11:38 -0800737 grpc_closure_init(&sp->read_closure, on_read, sp,
738 grpc_schedule_on_exec_ctx);
Craig Tilleref962642016-05-18 22:57:17 -0700739 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
740 s->active_ports++;
741 sp = sp->next;
ctiller58393c22015-01-07 14:03:30 -0800742 }
Craig Tillera82950e2015-09-22 12:33:20 -0700743 }
744 gpr_mu_unlock(&s->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800745}
Craig Tiller0c0b60c2015-01-21 15:49:28 -0800746
Dan Bornfa6b6062016-01-08 21:01:59 -0800747grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
Dan Born930c2982016-09-08 19:12:18 -0700748 gpr_ref_non_zero(&s->refs);
Dan Bornfa6b6062016-01-08 21:01:59 -0800749 return s;
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800750}
751
Dan Born9c12bc22016-01-13 16:52:20 -0800752void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
753 grpc_closure *shutdown_starting) {
754 gpr_mu_lock(&s->mu);
Craig Tillerc027e772016-05-03 16:27:00 -0700755 grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
756 GRPC_ERROR_NONE);
Dan Born9c12bc22016-01-13 16:52:20 -0800757 gpr_mu_unlock(&s->mu);
758}
759
Dan Bornfa6b6062016-01-08 21:01:59 -0800760void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
761 if (gpr_unref(&s->refs)) {
Dan Born930c2982016-09-08 19:12:18 -0700762 grpc_tcp_server_shutdown_listeners(exec_ctx, s);
Dan Born9c12bc22016-01-13 16:52:20 -0800763 gpr_mu_lock(&s->mu);
Craig Tiller91031da2016-12-28 15:44:25 -0800764 grpc_closure_list_sched(exec_ctx, &s->shutdown_starting);
Dan Born9c12bc22016-01-13 16:52:20 -0800765 gpr_mu_unlock(&s->mu);
Dan Born930c2982016-09-08 19:12:18 -0700766 tcp_server_destroy(exec_ctx, s);
Nicolas Noble5eb4e1c2015-11-18 17:19:45 -0800767 }
768}
769
yang-g9275d402016-07-11 16:51:39 -0700770void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
771 grpc_tcp_server *s) {
772 gpr_mu_lock(&s->mu);
773 /* shutdown all fd's */
774 if (s->active_ports) {
775 grpc_tcp_listener *sp;
776 for (sp = s->head; sp; sp = sp->next) {
Craig Tillercda759d2017-01-27 11:37:37 -0800777 grpc_fd_shutdown(exec_ctx, sp->emfd,
778 GRPC_ERROR_CREATE("Server shutdown"));
yang-g9275d402016-07-11 16:51:39 -0700779 }
780 }
781 gpr_mu_unlock(&s->mu);
782}
783
Craig Tiller190d3602015-02-18 09:23:38 -0800784#endif