Built motion from commit 44377920.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / lib / iomgr / tcp_server_utils_posix_ifaddrs.cc
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
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/iomgr/port.h"
22
23 #ifdef GRPC_HAVE_IFADDRS
24
25 #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
26
27 #include <errno.h>
28 #include <ifaddrs.h>
29 #include <stddef.h>
30 #include <string.h>
31
32 #include <grpc/support/alloc.h>
33 #include <grpc/support/log.h>
34 #include <grpc/support/string_util.h>
35
36 #include "src/core/lib/iomgr/error.h"
37 #include "src/core/lib/iomgr/sockaddr.h"
38 #include "src/core/lib/iomgr/sockaddr_utils.h"
39
40 /* Return the listener in s with address addr or NULL. */
41 static grpc_tcp_listener* find_listener_with_addr(grpc_tcp_server* s,
42                                                   grpc_resolved_address* addr) {
43   grpc_tcp_listener* l;
44   gpr_mu_lock(&s->mu);
45   for (l = s->head; l != nullptr; l = l->next) {
46     if (l->addr.len != addr->len) {
47       continue;
48     }
49     if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) {
50       break;
51     }
52   }
53   gpr_mu_unlock(&s->mu);
54   return l;
55 }
56
57 /* Bind to "::" to get a port number not used by any address. */
58 static grpc_error* get_unused_port(int* port) {
59   grpc_resolved_address wild;
60   grpc_sockaddr_make_wildcard6(0, &wild);
61   grpc_dualstack_mode dsmode;
62   int fd;
63   grpc_error* err =
64       grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
65   if (err != GRPC_ERROR_NONE) {
66     return err;
67   }
68   if (dsmode == GRPC_DSMODE_IPV4) {
69     grpc_sockaddr_make_wildcard4(0, &wild);
70   }
71   if (bind(fd, reinterpret_cast<const grpc_sockaddr*>(wild.addr), wild.len) !=
72       0) {
73     err = GRPC_OS_ERROR(errno, "bind");
74     close(fd);
75     return err;
76   }
77   if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(wild.addr), &wild.len) !=
78       0) {
79     err = GRPC_OS_ERROR(errno, "getsockname");
80     close(fd);
81     return err;
82   }
83   close(fd);
84   *port = grpc_sockaddr_get_port(&wild);
85   return *port <= 0 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad port")
86                     : GRPC_ERROR_NONE;
87 }
88
89 grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
90                                                 unsigned port_index,
91                                                 int requested_port,
92                                                 int* out_port) {
93   struct ifaddrs* ifa = nullptr;
94   struct ifaddrs* ifa_it;
95   unsigned fd_index = 0;
96   grpc_tcp_listener* sp = nullptr;
97   grpc_error* err = GRPC_ERROR_NONE;
98   if (requested_port == 0) {
99     /* Note: There could be a race where some local addrs can listen on the
100        selected port and some can't. The sane way to handle this would be to
101        retry by recreating the whole grpc_tcp_server. Backing out individual
102        listeners and orphaning the FDs looks like too much trouble. */
103     if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
104       return err;
105     } else if (requested_port <= 0) {
106       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad get_unused_port()");
107     }
108     gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
109   }
110   if (getifaddrs(&ifa) != 0 || ifa == nullptr) {
111     return GRPC_OS_ERROR(errno, "getifaddrs");
112   }
113   for (ifa_it = ifa; ifa_it != nullptr; ifa_it = ifa_it->ifa_next) {
114     grpc_resolved_address addr;
115     char* addr_str = nullptr;
116     grpc_dualstack_mode dsmode;
117     grpc_tcp_listener* new_sp = nullptr;
118     const char* ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
119     if (ifa_it->ifa_addr == nullptr) {
120       continue;
121     } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
122       addr.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
123     } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
124       addr.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
125     } else {
126       continue;
127     }
128     memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
129     if (!grpc_sockaddr_set_port(&addr, requested_port)) {
130       /* Should never happen, because we check sa_family above. */
131       err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set port");
132       break;
133     }
134     if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) {
135       addr_str = gpr_strdup("<error>");
136     }
137     gpr_log(GPR_DEBUG,
138             "Adding local addr from interface %s flags 0x%x to server: %s",
139             ifa_name, ifa_it->ifa_flags, addr_str);
140     /* We could have multiple interfaces with the same address (e.g., bonding),
141        so look for duplicates. */
142     if (find_listener_with_addr(s, &addr) != nullptr) {
143       gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str,
144               ifa_name);
145       gpr_free(addr_str);
146       continue;
147     }
148     if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
149                                         &new_sp)) != GRPC_ERROR_NONE) {
150       char* err_str = nullptr;
151       grpc_error* root_err;
152       if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) {
153         err_str = gpr_strdup("Failed to add listener");
154       }
155       root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_str);
156       gpr_free(err_str);
157       gpr_free(addr_str);
158       err = grpc_error_add_child(root_err, err);
159       break;
160     } else {
161       GPR_ASSERT(requested_port == new_sp->port);
162       ++fd_index;
163       if (sp != nullptr) {
164         new_sp->is_sibling = 1;
165         sp->sibling = new_sp;
166       }
167       sp = new_sp;
168     }
169     gpr_free(addr_str);
170   }
171   freeifaddrs(ifa);
172   if (err != GRPC_ERROR_NONE) {
173     return err;
174   } else if (sp == nullptr) {
175     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No local addresses");
176   } else {
177     *out_port = sp->port;
178     return GRPC_ERROR_NONE;
179   }
180 }
181
182 bool grpc_tcp_server_have_ifaddrs(void) { return true; }
183
184 #endif /* GRPC_HAVE_IFADDRS */