tcp_server_utils_posix_ifaddrs.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_HAVE_IFADDRS
24 
25 #include <errno.h>
26 #include <ifaddrs.h>
27 #include <stddef.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 
42 
43 /* Return the listener in s with address addr or NULL. */
44 static grpc_tcp_listener* find_listener_with_addr(grpc_tcp_server* s,
47  gpr_mu_lock(&s->mu);
48  for (l = s->head; l != nullptr; l = l->next) {
49  if (l->addr.len != addr->len) {
50  continue;
51  }
52  if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) {
53  break;
54  }
55  }
56  gpr_mu_unlock(&s->mu);
57  return l;
58 }
59 
60 /* Bind to "::" to get a port number not used by any address. */
61 static grpc_error_handle get_unused_port(int* port) {
64  grpc_dualstack_mode dsmode;
65  int fd;
67  grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
68  if (!GRPC_ERROR_IS_NONE(err)) {
69  return err;
70  }
71  if (dsmode == GRPC_DSMODE_IPV4) {
73  }
74  if (bind(fd, reinterpret_cast<const grpc_sockaddr*>(wild.addr), wild.len) !=
75  0) {
76  err = GRPC_OS_ERROR(errno, "bind");
77  close(fd);
78  return err;
79  }
80  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(wild.addr), &wild.len) !=
81  0) {
82  err = GRPC_OS_ERROR(errno, "getsockname");
83  close(fd);
84  return err;
85  }
86  close(fd);
87  *port = grpc_sockaddr_get_port(&wild);
88  return *port <= 0 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad port")
90 }
91 
93  unsigned port_index,
94  int requested_port,
95  int* out_port) {
96  struct ifaddrs* ifa = nullptr;
97  struct ifaddrs* ifa_it;
98  unsigned fd_index = 0;
99  grpc_tcp_listener* sp = nullptr;
101  if (requested_port == 0) {
102  /* Note: There could be a race where some local addrs can listen on the
103  selected port and some can't. The sane way to handle this would be to
104  retry by recreating the whole grpc_tcp_server. Backing out individual
105  listeners and orphaning the FDs looks like too much trouble. */
106  if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
107  return err;
108  } else if (requested_port <= 0) {
109  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad get_unused_port()");
110  }
111  gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
112  }
113  if (getifaddrs(&ifa) != 0 || ifa == nullptr) {
114  return GRPC_OS_ERROR(errno, "getifaddrs");
115  }
116  for (ifa_it = ifa; ifa_it != nullptr; ifa_it = ifa_it->ifa_next) {
118  grpc_dualstack_mode dsmode;
119  grpc_tcp_listener* new_sp = nullptr;
120  const char* ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
121  if (ifa_it->ifa_addr == nullptr) {
122  continue;
123  } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
124  addr.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
125  } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
126  addr.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
127  } else {
128  continue;
129  }
130  memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
131  if (!grpc_sockaddr_set_port(&addr, requested_port)) {
132  /* Should never happen, because we check sa_family above. */
133  err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set port");
134  break;
135  }
136  auto addr_str = grpc_sockaddr_to_string(&addr, false);
137  if (!addr_str.ok()) {
138  return GRPC_ERROR_CREATE_FROM_CPP_STRING(addr_str.status().ToString());
139  }
141  "Adding local addr from interface %s flags 0x%x to server: %s",
142  ifa_name, ifa_it->ifa_flags, addr_str->c_str());
143  /* We could have multiple interfaces with the same address (e.g., bonding),
144  so look for duplicates. */
145  if (find_listener_with_addr(s, &addr) != nullptr) {
146  gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s",
147  addr_str->c_str(), ifa_name);
148  continue;
149  }
150  if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
151  &new_sp)) != GRPC_ERROR_NONE) {
153  absl::StrCat("Failed to add listener: ", addr_str.value()));
154  err = grpc_error_add_child(root_err, err);
155  break;
156  } else {
157  GPR_ASSERT(requested_port == new_sp->port);
158  ++fd_index;
159  if (sp != nullptr) {
160  new_sp->is_sibling = 1;
161  sp->sibling = new_sp;
162  }
163  sp = new_sp;
164  }
165  }
166  freeifaddrs(ifa);
167  if (!GRPC_ERROR_IS_NONE(err)) {
168  return err;
169  } else if (sp == nullptr) {
170  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No local addresses");
171  } else {
172  *out_port = sp->port;
173  return GRPC_ERROR_NONE;
174  }
175 }
176 
177 bool grpc_tcp_server_have_ifaddrs(void) { return true; }
178 
179 #endif /* GRPC_HAVE_IFADDRS */
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
AF_INET6
#define AF_INET6
Definition: ares_setup.h:208
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
string.h
error_ref_leak.err
err
Definition: error_ref_leak.py:35
grpc_resolved_address
Definition: resolved_address.h:34
grpc_tcp_server
Definition: tcp_server_utils_posix.h:53
absl::FormatConversionChar::s
@ s
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_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)
grpc_error_add_child
grpc_error_handle grpc_error_add_child(grpc_error_handle src, grpc_error_handle child)
Definition: error.cc:678
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
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
ifaddrs::ifa_addr
struct sockaddr * ifa_addr
Definition: android-ifaddrs.h:33
grpc_sockaddr_set_port
int grpc_sockaddr_set_port(grpc_resolved_address *resolved_addr, int port)
Definition: sockaddr_utils.cc:324
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
grpc_tcp_server_add_all_local_addrs
grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s, unsigned port_index, int requested_port, int *out_port)
ifaddrs::ifa_name
char * ifa_name
Definition: android-ifaddrs.h:31
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
error.h
tcp_server_utils_posix.h
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_ERROR_CREATE_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)
Definition: error.h:291
grpc_tcp_server_have_ifaddrs
bool grpc_tcp_server_have_ifaddrs(void)
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
grpc_sockaddr_get_port
int grpc_sockaddr_get_port(const grpc_resolved_address *resolved_addr)
Definition: sockaddr_utils.cc:303
grpc_sockaddr_make_wildcard4
void grpc_sockaddr_make_wildcard4(int port, grpc_resolved_address *resolved_wild_out)
Definition: sockaddr_utils.cc:172
GRPC_DSMODE_IPV4
@ GRPC_DSMODE_IPV4
Definition: socket_utils_posix.h:120
port.h
GRPC_ERROR_CREATE_FROM_CPP_STRING
#define GRPC_ERROR_CREATE_FROM_CPP_STRING(desc)
Definition: error.h:297
alloc.h
ifaddrs::ifa_flags
unsigned int ifa_flags
Definition: android-ifaddrs.h:32
grpc_sockaddr_make_wildcard6
void grpc_sockaddr_make_wildcard6(int port, grpc_resolved_address *resolved_wild_out)
Definition: sockaddr_utils.cc:183
grpc_tcp_listener::is_sibling
int is_sibling
Definition: tcp_server_utils_posix.h:49
grpc_dualstack_mode
grpc_dualstack_mode
Definition: socket_utils_posix.h:116
ifaddrs
Definition: android-ifaddrs.h:29
GPR_DEBUG
#define GPR_DEBUG
Definition: include/grpc/impl/codegen/log.h:55
ifaddrs::ifa_next
struct ifaddrs * ifa_next
Definition: android-ifaddrs.h:30
freeifaddrs
void freeifaddrs(struct ifaddrs *ifa)
Definition: android-ifaddrs.c:704
getifaddrs
__BEGIN_DECLS int getifaddrs(struct ifaddrs **ifap)
Definition: android-ifaddrs.c:655
grpc_error
Definition: error_internal.h:42
run_grpclb_interop_tests.l
dictionary l
Definition: run_grpclb_interop_tests.py:410
grpc_resolved_address::addr
char addr[GRPC_MAX_SOCKADDR_SIZE]
Definition: resolved_address.h:35
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
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