| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #if defined(WEBRTC_ANDROID) | |
| 12 #include "webrtc/base/ifaddrs-android.h" | |
| 13 #include <stdlib.h> | |
| 14 #include <string.h> | |
| 15 #include <sys/types.h> | |
| 16 #include <sys/socket.h> | |
| 17 #include <sys/utsname.h> | |
| 18 #include <sys/ioctl.h> | |
| 19 #include <netinet/in.h> | |
| 20 #include <net/if.h> | |
| 21 #include <unistd.h> | |
| 22 #include <errno.h> | |
| 23 #include <linux/netlink.h> | |
| 24 #include <linux/rtnetlink.h> | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 struct netlinkrequest { | |
| 29 nlmsghdr header; | |
| 30 ifaddrmsg msg; | |
| 31 }; | |
| 32 | |
| 33 const int kMaxReadSize = 4096; | |
| 34 | |
| 35 } // namespace | |
| 36 | |
| 37 namespace rtc { | |
| 38 | |
| 39 int set_ifname(struct ifaddrs* ifaddr, int interface) { | |
| 40 char buf[IFNAMSIZ] = {0}; | |
| 41 char* name = if_indextoname(interface, buf); | |
| 42 if (name == nullptr) { | |
| 43 return -1; | |
| 44 } | |
| 45 ifaddr->ifa_name = new char[strlen(name) + 1]; | |
| 46 strncpy(ifaddr->ifa_name, name, strlen(name) + 1); | |
| 47 return 0; | |
| 48 } | |
| 49 | |
| 50 int set_flags(struct ifaddrs* ifaddr) { | |
| 51 int fd = socket(AF_INET, SOCK_DGRAM, 0); | |
| 52 if (fd == -1) { | |
| 53 return -1; | |
| 54 } | |
| 55 ifreq ifr; | |
| 56 memset(&ifr, 0, sizeof(ifr)); | |
| 57 strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1); | |
| 58 int rc = ioctl(fd, SIOCGIFFLAGS, &ifr); | |
| 59 close(fd); | |
| 60 if (rc == -1) { | |
| 61 return -1; | |
| 62 } | |
| 63 ifaddr->ifa_flags = ifr.ifr_flags; | |
| 64 return 0; | |
| 65 } | |
| 66 | |
| 67 int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data, | |
| 68 size_t len) { | |
| 69 if (msg->ifa_family == AF_INET) { | |
| 70 sockaddr_in* sa = new sockaddr_in; | |
| 71 sa->sin_family = AF_INET; | |
| 72 memcpy(&sa->sin_addr, data, len); | |
| 73 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); | |
| 74 } else if (msg->ifa_family == AF_INET6) { | |
| 75 sockaddr_in6* sa = new sockaddr_in6; | |
| 76 sa->sin6_family = AF_INET6; | |
| 77 sa->sin6_scope_id = msg->ifa_index; | |
| 78 memcpy(&sa->sin6_addr, data, len); | |
| 79 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); | |
| 80 } else { | |
| 81 return -1; | |
| 82 } | |
| 83 return 0; | |
| 84 } | |
| 85 | |
| 86 int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) { | |
| 87 char* prefix = nullptr; | |
| 88 if (family == AF_INET) { | |
| 89 sockaddr_in* mask = new sockaddr_in; | |
| 90 mask->sin_family = AF_INET; | |
| 91 memset(&mask->sin_addr, 0, sizeof(in_addr)); | |
| 92 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); | |
| 93 if (prefixlen > 32) { | |
| 94 prefixlen = 32; | |
| 95 } | |
| 96 prefix = reinterpret_cast<char*>(&mask->sin_addr); | |
| 97 } else if (family == AF_INET6) { | |
| 98 sockaddr_in6* mask = new sockaddr_in6; | |
| 99 mask->sin6_family = AF_INET6; | |
| 100 memset(&mask->sin6_addr, 0, sizeof(in6_addr)); | |
| 101 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); | |
| 102 if (prefixlen > 128) { | |
| 103 prefixlen = 128; | |
| 104 } | |
| 105 prefix = reinterpret_cast<char*>(&mask->sin6_addr); | |
| 106 } else { | |
| 107 return -1; | |
| 108 } | |
| 109 for (int i = 0; i < (prefixlen / 8); i++) { | |
| 110 *prefix++ = 0xFF; | |
| 111 } | |
| 112 char remainder = 0xff; | |
| 113 remainder <<= (8 - prefixlen % 8); | |
| 114 *prefix = remainder; | |
| 115 return 0; | |
| 116 } | |
| 117 | |
| 118 int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes, | |
| 119 size_t len) { | |
| 120 if (set_ifname(ifaddr, msg->ifa_index) != 0) { | |
| 121 return -1; | |
| 122 } | |
| 123 if (set_flags(ifaddr) != 0) { | |
| 124 return -1; | |
| 125 } | |
| 126 if (set_addresses(ifaddr, msg, bytes, len) != 0) { | |
| 127 return -1; | |
| 128 } | |
| 129 if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) { | |
| 130 return -1; | |
| 131 } | |
| 132 return 0; | |
| 133 } | |
| 134 | |
| 135 int getifaddrs(struct ifaddrs** result) { | |
| 136 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
| 137 if (fd < 0) { | |
| 138 return -1; | |
| 139 } | |
| 140 | |
| 141 netlinkrequest ifaddr_request; | |
| 142 memset(&ifaddr_request, 0, sizeof(ifaddr_request)); | |
| 143 ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST; | |
| 144 ifaddr_request.header.nlmsg_type = RTM_GETADDR; | |
| 145 ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); | |
| 146 | |
| 147 ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0); | |
| 148 if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) { | |
| 149 close(fd); | |
| 150 return -1; | |
| 151 } | |
| 152 struct ifaddrs* start = nullptr; | |
| 153 struct ifaddrs* current = nullptr; | |
| 154 char buf[kMaxReadSize]; | |
| 155 ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0); | |
| 156 while (amount_read > 0) { | |
| 157 nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]); | |
| 158 size_t header_size = static_cast<size_t>(amount_read); | |
| 159 for ( ; NLMSG_OK(header, header_size); | |
| 160 header = NLMSG_NEXT(header, header_size)) { | |
| 161 switch (header->nlmsg_type) { | |
| 162 case NLMSG_DONE: | |
| 163 // Success. Return. | |
| 164 *result = start; | |
| 165 close(fd); | |
| 166 return 0; | |
| 167 case NLMSG_ERROR: | |
| 168 close(fd); | |
| 169 freeifaddrs(start); | |
| 170 return -1; | |
| 171 case RTM_NEWADDR: { | |
| 172 ifaddrmsg* address_msg = | |
| 173 reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header)); | |
| 174 rtattr* rta = IFA_RTA(address_msg); | |
| 175 ssize_t payload_len = IFA_PAYLOAD(header); | |
| 176 while (RTA_OK(rta, payload_len)) { | |
| 177 if (rta->rta_type == IFA_ADDRESS) { | |
| 178 int family = address_msg->ifa_family; | |
| 179 if (family == AF_INET || family == AF_INET6) { | |
| 180 ifaddrs* newest = new ifaddrs; | |
| 181 memset(newest, 0, sizeof(ifaddrs)); | |
| 182 if (current) { | |
| 183 current->ifa_next = newest; | |
| 184 } else { | |
| 185 start = newest; | |
| 186 } | |
| 187 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta), | |
| 188 RTA_PAYLOAD(rta)) != 0) { | |
| 189 freeifaddrs(start); | |
| 190 *result = nullptr; | |
| 191 return -1; | |
| 192 } | |
| 193 current = newest; | |
| 194 } | |
| 195 } | |
| 196 rta = RTA_NEXT(rta, payload_len); | |
| 197 } | |
| 198 break; | |
| 199 } | |
| 200 } | |
| 201 } | |
| 202 amount_read = recv(fd, &buf, kMaxReadSize, 0); | |
| 203 } | |
| 204 close(fd); | |
| 205 freeifaddrs(start); | |
| 206 return -1; | |
| 207 } | |
| 208 | |
| 209 void freeifaddrs(struct ifaddrs* addrs) { | |
| 210 struct ifaddrs* last = nullptr; | |
| 211 struct ifaddrs* cursor = addrs; | |
| 212 while (cursor) { | |
| 213 delete[] cursor->ifa_name; | |
| 214 delete cursor->ifa_addr; | |
| 215 delete cursor->ifa_netmask; | |
| 216 last = cursor; | |
| 217 cursor = cursor->ifa_next; | |
| 218 delete last; | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 } // namespace rtc | |
| 223 #endif // defined(WEBRTC_ANDROID) | |
| OLD | NEW |