tcp_server_utils_posix_common.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * 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
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * 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.
16  *
17  */
18 
20 
22 
23 #ifdef GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON
24 
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 
31 #include <string>
32 
33 #include "absl/strings/str_cat.h"
34 
35 #include <grpc/support/alloc.h>
36 #include <grpc/support/log.h>
37 #include <grpc/support/sync.h>
38 
44 
45 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
46 
47 static gpr_once s_init_max_accept_queue_size = GPR_ONCE_INIT;
48 static int s_max_accept_queue_size;
49 
50 /* get max listen queue size on linux */
51 static void init_max_accept_queue_size(void) {
52  int n = SOMAXCONN;
53  char buf[64];
54  FILE* fp = fopen("/proc/sys/net/core/somaxconn", "r");
55  if (fp == nullptr) {
56  /* 2.4 kernel. */
57  s_max_accept_queue_size = SOMAXCONN;
58  return;
59  }
60  if (fgets(buf, sizeof buf, fp)) {
61  char* end;
62  long i = strtol(buf, &end, 10);
63  if (i > 0 && i <= INT_MAX && end && *end == '\n') {
64  n = static_cast<int>(i);
65  }
66  }
67  fclose(fp);
68  s_max_accept_queue_size = n;
69 
70  if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
72  "Suspiciously small accept queue (%d) will probably lead to "
73  "connection drops",
74  s_max_accept_queue_size);
75  }
76 }
77 
78 static int get_max_accept_queue_size(void) {
79  gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
80  return s_max_accept_queue_size;
81 }
82 
83 static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
85  unsigned port_index,
86  unsigned fd_index,
87  grpc_tcp_listener** listener) {
88  *listener = nullptr;
89  int port = -1;
90 
92  grpc_tcp_server_prepare_socket(s, fd, addr, s->so_reuseport, &port);
93  if (!GRPC_ERROR_IS_NONE(err)) return err;
94  GPR_ASSERT(port > 0);
96  if (!addr_str.ok()) {
98  }
99  std::string name = absl::StrCat("tcp-server-listener:", addr_str.value());
100  gpr_mu_lock(&s->mu);
101  s->nports++;
102  GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
103  grpc_tcp_listener* sp =
104  static_cast<grpc_tcp_listener*>(gpr_malloc(sizeof(grpc_tcp_listener)));
105  sp->next = nullptr;
106  if (s->head == nullptr) {
107  s->head = sp;
108  } else {
109  s->tail->next = sp;
110  }
111  s->tail = sp;
112  sp->server = s;
113  sp->fd = fd;
114  sp->emfd = grpc_fd_create(fd, name.c_str(), true);
115  memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
116  sp->port = port;
117  sp->port_index = port_index;
118  sp->fd_index = fd_index;
119  sp->is_sibling = 0;
120  sp->sibling = nullptr;
121  GPR_ASSERT(sp->emfd);
122  gpr_mu_unlock(&s->mu);
123 
124  *listener = sp;
125  return err;
126 }
127 
128 /* If successful, add a listener to s for addr, set *dsmode for the socket, and
129  return the *listener. */
132  unsigned port_index,
133  unsigned fd_index,
134  grpc_dualstack_mode* dsmode,
135  grpc_tcp_listener** listener) {
136  grpc_resolved_address addr4_copy;
137  int fd;
139  grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
140  if (!GRPC_ERROR_IS_NONE(err)) {
141  return err;
142  }
143  if (*dsmode == GRPC_DSMODE_IPV4 &&
144  grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
145  addr = &addr4_copy;
146  }
147  return add_socket_to_server(s, fd, addr, port_index, fd_index, listener);
148 }
149 
150 /* Prepare a recently-created socket for listening. */
152  grpc_tcp_server* s, int fd, const grpc_resolved_address* addr,
153  bool so_reuseport, int* port) {
154  grpc_resolved_address sockname_temp;
156 
157  GPR_ASSERT(fd >= 0);
158 
159  if (so_reuseport && !grpc_is_unix_socket(addr)) {
161  if (!GRPC_ERROR_IS_NONE(err)) goto error;
162  }
163 
164 #ifdef GRPC_LINUX_ERRQUEUE
166  if (!GRPC_ERROR_IS_NONE(err)) {
167  /* it's not fatal, so just log it. */
168  gpr_log(GPR_DEBUG, "Node does not support SO_ZEROCOPY, continuing.");
170  }
171 #endif
173  if (!GRPC_ERROR_IS_NONE(err)) goto error;
174  err = grpc_set_socket_cloexec(fd, 1);
175  if (!GRPC_ERROR_IS_NONE(err)) goto error;
176  if (!grpc_is_unix_socket(addr)) {
178  if (!GRPC_ERROR_IS_NONE(err)) goto error;
180  if (!GRPC_ERROR_IS_NONE(err)) goto error;
181  err = grpc_set_socket_tcp_user_timeout(fd, s->channel_args,
182  false /* is_client */);
183  if (!GRPC_ERROR_IS_NONE(err)) goto error;
184  }
186  if (!GRPC_ERROR_IS_NONE(err)) goto error;
187 
189  s->channel_args);
190  if (!GRPC_ERROR_IS_NONE(err)) goto error;
191 
192  if (bind(fd, reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr)),
193  addr->len) < 0) {
194  err = GRPC_OS_ERROR(errno, "bind");
195  goto error;
196  }
197 
198  if (listen(fd, get_max_accept_queue_size()) < 0) {
199  err = GRPC_OS_ERROR(errno, "listen");
200  goto error;
201  }
202 
203  sockname_temp.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
204 
205  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
206  &sockname_temp.len) < 0) {
207  err = GRPC_OS_ERROR(errno, "getsockname");
208  goto error;
209  }
210 
211  *port = grpc_sockaddr_get_port(&sockname_temp);
212  return GRPC_ERROR_NONE;
213 
214 error:
216  if (fd >= 0) {
217  close(fd);
218  }
221  "Unable to configure socket", &err, 1),
222  GRPC_ERROR_INT_FD, fd);
224  return ret;
225 }
226 
227 #endif /* GRPC_POSIX_SOCKET_TCP_SERVER_UTILS_COMMON */
grpc_set_socket_reuse_addr
grpc_error_handle grpc_set_socket_reuse_addr(int fd, int reuse)
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
gpr_mu_unlock
GPRAPI void gpr_mu_unlock(gpr_mu *mu)
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
grpc_tcp_listener::sibling
struct grpc_tcp_listener * sibling
Definition: tcp_server_utils_posix.h:48
sockaddr_utils.h
absl::Status::ToString
std::string ToString(StatusToStringMode mode=StatusToStringMode::kDefault) const
Definition: third_party/abseil-cpp/absl/status/status.h:821
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
grpc_set_socket_low_latency
grpc_error_handle grpc_set_socket_low_latency(int fd, int low_latency)
gpr_once
pthread_once_t gpr_once
Definition: impl/codegen/sync_posix.h:50
grpc_set_socket_zerocopy
grpc_error_handle grpc_set_socket_zerocopy(int fd)
string.h
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
grpc_set_socket_no_sigpipe_if_possible
grpc_error_handle grpc_set_socket_no_sigpipe_if_possible(int fd)
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
error_ref_leak.err
err
Definition: error_ref_leak.py:35
grpc_resolved_address
Definition: resolved_address.h:34
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count)
Definition: error.h:307
grpc_tcp_server
Definition: tcp_server_utils_posix.h:53
GPR_ONCE_INIT
#define GPR_ONCE_INIT
Definition: impl/codegen/sync_posix.h:52
setup.name
name
Definition: setup.py:542
absl::FormatConversionChar::s
@ s
GRPC_ERROR_INT_FD
@ GRPC_ERROR_INT_FD
File descriptor associated with this error.
Definition: error.h:86
grpc_tcp_listener::server
grpc_tcp_server * server
Definition: tcp_server_utils_posix.h:34
grpc_sockaddr_to_string
absl::StatusOr< std::string > grpc_sockaddr_to_string(const grpc_resolved_address *resolved_addr, bool normalize)
Definition: sockaddr_utils.cc:194
sockaddr.h
grpc_tcp_listener::next
struct grpc_tcp_listener * next
Definition: tcp_server_utils_posix.h:41
grpc_is_unix_socket
int grpc_is_unix_socket(const grpc_resolved_address *resolved_addr)
Definition: unix_sockets_posix_noop.cc:46
gpr_once_init
GPRAPI void gpr_once_init(gpr_once *once, void(*init_function)(void))
grpc_tcp_listener::emfd
grpc_fd * emfd
Definition: tcp_server_utils_posix.h:33
grpc_tcp_server_add_addr
grpc_error_handle grpc_tcp_server_add_addr(grpc_tcp_server *s, const grpc_resolved_address *addr, unsigned port_index, unsigned fd_index, grpc_dualstack_mode *dsmode, grpc_tcp_listener **listener)
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
grpc_set_socket_cloexec
grpc_error_handle grpc_set_socket_cloexec(int fd, int close_on_exec)
GRPC_OS_ERROR
#define GRPC_OS_ERROR(err, call_name)
create an error associated with errno!=0 (an 'operating system' error)
Definition: error.h:352
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
grpc_fd_create
grpc_fd * grpc_fd_create(int fd, const char *name, bool track_err)
grpc_tcp_listener::addr
grpc_resolved_address addr
Definition: tcp_server_utils_posix.h:35
close
#define close
Definition: test-fs.c:48
grpc_tcp_listener
Definition: tcp_server_utils_posix.h:31
gpr_mu_lock
GPRAPI void gpr_mu_lock(gpr_mu *mu)
grpc_resolved_address::len
socklen_t len
Definition: resolved_address.h:36
grpc_tcp_listener::fd
int fd
Definition: tcp_server_utils_posix.h:32
error.h
tcp_server_utils_posix.h
grpc_set_socket_reuse_port
grpc_error_handle grpc_set_socket_reuse_port(int fd, int reuse)
grpc_create_dualstack_socket
grpc_error_handle grpc_create_dualstack_socket(const grpc_resolved_address *addr, int type, int protocol, grpc_dualstack_mode *dsmode, int *newfd)
grpc_tcp_listener::fd_index
unsigned fd_index
Definition: tcp_server_utils_posix.h:38
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
grpc_tcp_listener::port_index
unsigned port_index
Definition: tcp_server_utils_posix.h:37
unix_sockets_posix.h
grpc_sockaddr_get_port
int grpc_sockaddr_get_port(const grpc_resolved_address *resolved_addr)
Definition: sockaddr_utils.cc:303
absl::StatusOr::ok
ABSL_MUST_USE_RESULT bool ok() const
Definition: abseil-cpp/absl/status/statusor.h:491
benchmark.FILE
FILE
Definition: benchmark.py:21
grpc_error_set_int
grpc_error_handle grpc_error_set_int(grpc_error_handle src, grpc_error_ints which, intptr_t value)
Definition: error.cc:613
GRPC_DSMODE_IPV4
@ GRPC_DSMODE_IPV4
Definition: socket_utils_posix.h:120
port.h
http2_test_server.listen
def listen(endpoint, test_case)
Definition: http2_test_server.py:87
grpc::fclose
fclose(creds_file)
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
GRPC_ERROR_CREATE_FROM_CPP_STRING
#define GRPC_ERROR_CREATE_FROM_CPP_STRING(desc)
Definition: error.h:297
alloc.h
grpc_tcp_server_prepare_socket
grpc_error_handle grpc_tcp_server_prepare_socket(grpc_tcp_server *, int fd, const grpc_resolved_address *addr, bool so_reuseport, int *port)
grpc_tcp_listener::is_sibling
int is_sibling
Definition: tcp_server_utils_posix.h:49
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
grpc_dualstack_mode
grpc_dualstack_mode
Definition: socket_utils_posix.h:116
GPR_DEBUG
#define GPR_DEBUG
Definition: include/grpc/impl/codegen/log.h:55
absl::StatusOr::value
const T & value() const &ABSL_ATTRIBUTE_LIFETIME_BOUND
Definition: abseil-cpp/absl/status/statusor.h:687
absl::StatusOr< std::string >
grpc_set_socket_nonblocking
grpc_error_handle grpc_set_socket_nonblocking(int fd, int non_blocking)
grpc_error
Definition: error_internal.h:42
grpc_set_socket_tcp_user_timeout
grpc_error_handle grpc_set_socket_tcp_user_timeout(int fd, const grpc_channel_args *channel_args, bool is_client)
grpc_sockaddr_is_v4mapped
int grpc_sockaddr_is_v4mapped(const grpc_resolved_address *resolved_addr, grpc_resolved_address *resolved_addr4_out)
Definition: sockaddr_utils.cc:81
grpc_apply_socket_mutator_in_args
grpc_error_handle grpc_apply_socket_mutator_in_args(int fd, grpc_fd_usage usage, const grpc_channel_args *args)
sync.h
grpc_resolved_address::addr
char addr[GRPC_MAX_SOCKADDR_SIZE]
Definition: resolved_address.h:35
GRPC_FD_SERVER_LISTENER_USAGE
@ GRPC_FD_SERVER_LISTENER_USAGE
Definition: socket_mutator.h:34
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
grpc_tcp_listener::port
int port
Definition: tcp_server_utils_posix.h:36
errno.h
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
absl::StatusOr::status
const Status & status() const &
Definition: abseil-cpp/absl/status/statusor.h:678
GRPC_ERROR_IS_NONE
#define GRPC_ERROR_IS_NONE(err)
Definition: error.h:241
port_platform.h


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:29