Flutter Engine
The Flutter Engine
ifaddrs.cc
Go to the documentation of this file.
1// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#if defined(ANDROID) && __ANDROID_API__ < 24
6
7#include "bin/ifaddrs.h"
8
9#include <errno.h>
10#include <linux/netlink.h>
11#include <linux/rtnetlink.h>
12#include <net/if.h>
13#include <netinet/in.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/ioctl.h>
17#include <sys/socket.h>
18#include <sys/types.h>
19#include <sys/utsname.h>
20#include <unistd.h>
21
22#include "bin/fdutils.h"
24
25namespace dart {
26namespace bin {
27
28const int kMaxReadSize = 2048;
29
30static bool SetIfName(struct ifaddrs* ifaddr, int interface) {
31 char buf[IFNAMSIZ] = {0};
32 char* name = if_indextoname(interface, buf);
33 if (name == nullptr) {
34 return false;
35 }
36 ifaddr->ifa_name = new char[strlen(name) + 1];
37 strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
38 return true;
39}
40
41static void SetFlags(struct ifaddrs* ifaddr, int flag) {
42 ifaddr->ifa_flags = flag;
43}
44
45static void SetAddresses(struct ifaddrs* ifaddr,
46 int family,
47 int index,
48 void* data,
49 size_t len) {
50 if (family == AF_INET6) {
51 sockaddr_in6* socketaddr = new sockaddr_in6;
52 socketaddr->sin6_family = AF_INET6;
53 socketaddr->sin6_scope_id = index;
54 memmove(&socketaddr->sin6_addr, data, len);
55 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(socketaddr);
56 return;
57 }
58 ASSERT(family == AF_INET);
59 sockaddr_in* socketaddr = new sockaddr_in;
60 socketaddr->sin_family = AF_INET;
61 memmove(&socketaddr->sin_addr, data, len);
62 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(socketaddr);
63}
64
65static void SetNetmask(struct ifaddrs* ifaddr, int family) {
66 if (family == AF_INET6) {
67 sockaddr_in6* mask = new sockaddr_in6;
68 mask->sin6_family = AF_INET6;
69 memset(&mask->sin6_addr, 0, sizeof(mask->sin6_addr));
70 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
71 return;
72 }
73 ASSERT(family == AF_INET);
74 sockaddr_in* mask = new sockaddr_in;
75 mask->sin_family = AF_INET;
76 memset(&mask->sin_addr, 0, sizeof(mask->sin_addr));
77 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
78}
79
80static bool SetIfAddrsFromAddrMsg(struct ifaddrs* ifaddr,
81 ifaddrmsg* msg,
82 void* bytes,
83 size_t len,
84 nlmsghdr* header) {
85 SetAddresses(ifaddr, msg->ifa_family, msg->ifa_index, bytes, len);
86 SetNetmask(ifaddr, msg->ifa_family);
87 SetFlags(ifaddr, msg->ifa_flags);
88 return SetIfName(ifaddr, msg->ifa_index);
89}
90
91static bool SetIfAddrsFromInfoMsg(struct ifaddrs* ifaddr,
92 ifinfomsg* ifi,
93 void* bytes,
94 size_t len,
95 nlmsghdr* header) {
96 SetAddresses(ifaddr, ifi->ifi_family, ifi->ifi_index, bytes, len);
97 SetNetmask(ifaddr, ifi->ifi_family);
98 SetFlags(ifaddr, ifi->ifi_flags);
99 return SetIfName(ifaddr, ifi->ifi_index);
100}
101
102static int SendRequest() {
103 int file_descriptor =
104 NO_RETRY_EXPECTED(socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
105 if (file_descriptor < 0) {
106 return -1;
107 }
108 nlmsghdr header;
109 memset(&header, 0, sizeof(header));
110 header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
111 header.nlmsg_type = RTM_GETADDR;
112 header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
113 ssize_t num =
114 TEMP_FAILURE_RETRY(send(file_descriptor, &header, header.nlmsg_len, 0));
115 if (static_cast<size_t>(num) != header.nlmsg_len) {
116 FDUtils::SaveErrorAndClose(file_descriptor);
117 return -1;
118 }
119 return file_descriptor;
120}
121
122static int FailAndExit(int fd, ifaddrs* head) {
124 freeifaddrs(head);
125 return -1;
126}
127
128int getifaddrs(struct ifaddrs** result) {
129 int file_descriptor = SendRequest();
130 if (file_descriptor < 0) {
131 return -1;
132 }
133 struct ifaddrs* head = nullptr;
134 struct ifaddrs* cur = nullptr;
135 char buf[kMaxReadSize];
136 ssize_t amount_read;
137 while (true) {
138 amount_read =
139 TEMP_FAILURE_RETRY(recv(file_descriptor, &buf, kMaxReadSize, 0));
140 if (amount_read <= 0) {
141 break;
142 }
143 nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
144 size_t header_size = static_cast<size_t>(amount_read);
145 for (; NLMSG_OK(header, header_size);
146 header = NLMSG_NEXT(header, header_size)) {
147 switch (header->nlmsg_type) {
148 case RTM_NEWADDR: {
149 ifaddrmsg* address_msg =
150 reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
151 ssize_t payload_len = IFA_PAYLOAD(header);
152 for (rtattr* rta = IFA_RTA(address_msg); RTA_OK(rta, payload_len);
153 rta = RTA_NEXT(rta, payload_len)) {
154 if (rta->rta_type != IFA_ADDRESS) {
155 continue;
156 }
157 int family = address_msg->ifa_family;
158 if (family != AF_INET && family != AF_INET6) {
159 continue;
160 }
161 ifaddrs* next = new ifaddrs;
162 memset(next, 0, sizeof(*next));
163 if (cur != nullptr) {
164 cur->ifa_next = next;
165 } else {
166 head = next;
167 }
168 if (!SetIfAddrsFromAddrMsg(next, address_msg, RTA_DATA(rta),
169 RTA_PAYLOAD(rta), header)) {
170 return FailAndExit(file_descriptor, head);
171 }
172 cur = next;
173 }
174 break;
175 }
176 case RTM_NEWLINK: {
177 ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(header));
178 ssize_t payload_len = IFLA_PAYLOAD(header);
179 for (rtattr* rta = IFLA_RTA(ifi); RTA_OK(rta, payload_len);
180 rta = RTA_NEXT(rta, payload_len)) {
181 if (rta->rta_type != IFA_ADDRESS) {
182 continue;
183 }
184 int family = ifi->ifi_family;
185 if (family != AF_INET && family != AF_INET6) {
186 continue;
187 }
188 ifaddrs* next = new ifaddrs;
189 memset(next, 0, sizeof(*next));
190 if (cur != nullptr) {
191 cur->ifa_next = next;
192 } else {
193 head = next;
194 }
195 if (!SetIfAddrsFromInfoMsg(next, ifi, RTA_DATA(rta),
196 RTA_PAYLOAD(rta), header)) {
197 return FailAndExit(file_descriptor, head);
198 }
199 cur = next;
200 }
201 break;
202 }
203 case NLMSG_DONE:
204 *result = head;
205 FDUtils::SaveErrorAndClose(file_descriptor);
206 return 0;
207 case NLMSG_ERROR:
208 return FailAndExit(file_descriptor, head);
209 }
210 }
211 }
212 return FailAndExit(file_descriptor, head);
213}
214
215void freeifaddrs(struct ifaddrs* addrs) {
216 int err = errno;
217 struct ifaddrs* previous = nullptr;
218 while (addrs != nullptr) {
219 delete[] addrs->ifa_name;
220 delete addrs->ifa_addr;
221 delete addrs->ifa_netmask;
222 previous = addrs;
223 addrs = addrs->ifa_next;
224 delete previous;
225 }
226 errno = err;
227}
228
229} // namespace bin
230} // namespace dart
231
232#endif // defined(ANDROID) && __ANDROID_API__ < 24
static float next(float f)
static void SaveErrorAndClose(intptr_t fd)
#define ASSERT(E)
FlutterSemanticsFlag flag
GAsyncResult * result
Definition: dart_vm.cc:33
const char *const name
static int8_t data[kExtLength]
#define NO_RETRY_EXPECTED(expression)
#define TEMP_FAILURE_RETRY(expression)
static const char header[]
Definition: skpbench.cpp:88