blob: a828bee074a97a08391201dc0187ce3b0b0c7ebd [file] [log] [blame]
Yuchen Zeng68745bb2017-03-14 17:51:07 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2017 gRPC authors.
Yuchen Zeng68745bb2017-03-14 17:51:07 -07004 *
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
Yuchen Zeng68745bb2017-03-14 17:51:07 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Yuchen Zeng68745bb2017-03-14 17:51:07 -070010 *
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.
Yuchen Zeng68745bb2017-03-14 17:51:07 -070016 *
17 */
18
19#include "src/core/lib/iomgr/port.h"
20
Yuchen Zengb1290952017-03-23 10:37:02 -070021#ifdef GRPC_POSIX_SOCKET
Yuchen Zeng68745bb2017-03-14 17:51:07 -070022
23#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
24
25#include <errno.h>
26#include <limits.h>
27#include <stdio.h>
28#include <string.h>
29
30#include <grpc/support/alloc.h>
31#include <grpc/support/log.h>
32#include <grpc/support/string_util.h>
33#include <grpc/support/sync.h>
34
35#include "src/core/lib/iomgr/error.h"
36#include "src/core/lib/iomgr/sockaddr.h"
37#include "src/core/lib/iomgr/sockaddr_utils.h"
38#include "src/core/lib/iomgr/unix_sockets_posix.h"
39
40#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
41
Peter Gonda19012542017-07-31 08:57:04 -070042static gpr_once s_init_max_accept_queue_size = GPR_ONCE_INIT;
Yuchen Zeng68745bb2017-03-14 17:51:07 -070043static int s_max_accept_queue_size;
44
45/* get max listen queue size on linux */
46static void init_max_accept_queue_size(void) {
47 int n = SOMAXCONN;
48 char buf[64];
49 FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
50 if (fp == NULL) {
51 /* 2.4 kernel. */
52 s_max_accept_queue_size = SOMAXCONN;
53 return;
54 }
55 if (fgets(buf, sizeof buf, fp)) {
56 char *end;
57 long i = strtol(buf, &end, 10);
58 if (i > 0 && i <= INT_MAX && end && *end == 0) {
59 n = (int)i;
60 }
61 }
62 fclose(fp);
63 s_max_accept_queue_size = n;
64
65 if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
66 gpr_log(GPR_INFO,
67 "Suspiciously small accept queue (%d) will probably lead to "
68 "connection drops",
69 s_max_accept_queue_size);
70 }
71}
72
73static int get_max_accept_queue_size(void) {
74 gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
75 return s_max_accept_queue_size;
76}
77
78static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
79 const grpc_resolved_address *addr,
80 unsigned port_index, unsigned fd_index,
81 grpc_tcp_listener **listener) {
82 grpc_tcp_listener *sp = NULL;
83 int port = -1;
84 char *addr_str;
85 char *name;
86
87 grpc_error *err =
88 grpc_tcp_server_prepare_socket(fd, addr, s->so_reuseport, &port);
89 if (err == GRPC_ERROR_NONE) {
90 GPR_ASSERT(port > 0);
91 grpc_sockaddr_to_string(&addr_str, addr, 1);
92 gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
93 gpr_mu_lock(&s->mu);
94 s->nports++;
95 GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070096 sp = (grpc_tcp_listener *)gpr_malloc(sizeof(grpc_tcp_listener));
Yuchen Zeng68745bb2017-03-14 17:51:07 -070097 sp->next = NULL;
98 if (s->head == NULL) {
99 s->head = sp;
100 } else {
101 s->tail->next = sp;
102 }
103 s->tail = sp;
104 sp->server = s;
105 sp->fd = fd;
106 sp->emfd = grpc_fd_create(fd, name);
107 memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
108 sp->port = port;
109 sp->port_index = port_index;
110 sp->fd_index = fd_index;
111 sp->is_sibling = 0;
112 sp->sibling = NULL;
113 GPR_ASSERT(sp->emfd);
114 gpr_mu_unlock(&s->mu);
115 gpr_free(addr_str);
116 gpr_free(name);
117 }
118
119 *listener = sp;
120 return err;
121}
122
123/* If successful, add a listener to s for addr, set *dsmode for the socket, and
124 return the *listener. */
125grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s,
126 const grpc_resolved_address *addr,
127 unsigned port_index, unsigned fd_index,
128 grpc_dualstack_mode *dsmode,
129 grpc_tcp_listener **listener) {
130 grpc_resolved_address addr4_copy;
131 int fd;
132 grpc_error *err =
133 grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
134 if (err != GRPC_ERROR_NONE) {
135 return err;
136 }
137 if (*dsmode == GRPC_DSMODE_IPV4 &&
138 grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
139 addr = &addr4_copy;
140 }
141 return add_socket_to_server(s, fd, addr, port_index, fd_index, listener);
142}
143
144/* Prepare a recently-created socket for listening. */
145grpc_error *grpc_tcp_server_prepare_socket(int fd,
146 const grpc_resolved_address *addr,
147 bool so_reuseport, int *port) {
148 grpc_resolved_address sockname_temp;
149 grpc_error *err = GRPC_ERROR_NONE;
150
151 GPR_ASSERT(fd >= 0);
152
153 if (so_reuseport && !grpc_is_unix_socket(addr)) {
154 err = grpc_set_socket_reuse_port(fd, 1);
155 if (err != GRPC_ERROR_NONE) goto error;
156 }
157
158 err = grpc_set_socket_nonblocking(fd, 1);
159 if (err != GRPC_ERROR_NONE) goto error;
160 err = grpc_set_socket_cloexec(fd, 1);
161 if (err != GRPC_ERROR_NONE) goto error;
162 if (!grpc_is_unix_socket(addr)) {
163 err = grpc_set_socket_low_latency(fd, 1);
164 if (err != GRPC_ERROR_NONE) goto error;
165 err = grpc_set_socket_reuse_addr(fd, 1);
166 if (err != GRPC_ERROR_NONE) goto error;
167 }
168 err = grpc_set_socket_no_sigpipe_if_possible(fd);
169 if (err != GRPC_ERROR_NONE) goto error;
170
171 GPR_ASSERT(addr->len < ~(socklen_t)0);
172 if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) {
173 err = GRPC_OS_ERROR(errno, "bind");
174 goto error;
175 }
176
177 if (listen(fd, get_max_accept_queue_size()) < 0) {
178 err = GRPC_OS_ERROR(errno, "listen");
179 goto error;
180 }
181
182 sockname_temp.len = sizeof(struct sockaddr_storage);
183
184 if (getsockname(fd, (struct sockaddr *)sockname_temp.addr,
185 (socklen_t *)&sockname_temp.len) < 0) {
186 err = GRPC_OS_ERROR(errno, "getsockname");
187 goto error;
188 }
189
190 *port = grpc_sockaddr_get_port(&sockname_temp);
191 return GRPC_ERROR_NONE;
192
193error:
194 GPR_ASSERT(err != GRPC_ERROR_NONE);
195 if (fd >= 0) {
196 close(fd);
197 }
Noah Eisen3d194ad2017-03-22 14:34:42 -0700198 grpc_error *ret =
199 grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
200 "Unable to configure socket", &err, 1),
201 GRPC_ERROR_INT_FD, fd);
Yuchen Zeng68745bb2017-03-14 17:51:07 -0700202 GRPC_ERROR_UNREF(err);
203 return ret;
204}
205
Yuchen Zengb1290952017-03-23 10:37:02 -0700206#endif /* GRPC_POSIX_SOCKET */