ifaddrs-android.h revision 18090720f97d2fe718f11d0944b623676bf6b78b
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef IFADDRS_ANDROID_H_included 18#define IFADDRS_ANDROID_H_included 19 20#include <cstring> 21#include <new> 22#include <sys/types.h> 23#include <sys/socket.h> 24 25#include <linux/netlink.h> 26#include <linux/rtnetlink.h> 27 28#include "LocalArray.h" 29#include "ScopedFd.h" 30 31// Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3). 32// We fake it here, so java_net_NetworkInterface.cpp can use that API 33// with all the non-portable code being in this file. 34 35// Source-compatible subset of the BSD struct. 36struct ifaddrs { 37 // Pointer to next struct in list, or NULL at end. 38 ifaddrs* ifa_next; 39 40 // Interface name. 41 char* ifa_name; 42 43 // Interface flags. 44 unsigned int ifa_flags; 45 46 // Interface address. 47 sockaddr* ifa_addr; 48 49 ifaddrs(ifaddrs* next) 50 : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL) 51 { 52 } 53 54 ~ifaddrs() { 55 delete ifa_next; 56 delete[] ifa_name; 57 delete ifa_addr; 58 } 59 60 // Sadly, we can't keep the interface index for portability with BSD. 61 // We'll have to keep the name instead, and re-query the index when 62 // we need it later. 63 bool setNameAndFlagsByIndex(int interfaceIndex) { 64 // Get the name. 65 char buf[IFNAMSIZ]; 66 char* name = if_indextoname(interfaceIndex, buf); 67 if (name == NULL) { 68 return false; 69 } 70 ifa_name = new char[strlen(name) + 1]; 71 strcpy(ifa_name, name); 72 73 // Get the flags. 74 ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0)); 75 if (fd.get() == -1) { 76 return false; 77 } 78 ifreq ifr; 79 memset(&ifr, 0, sizeof(ifr)); 80 strcpy(ifr.ifr_name, name); 81 int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr); 82 if (rc == -1) { 83 return false; 84 } 85 ifa_flags = ifr.ifr_flags; 86 return true; 87 } 88 89 // Netlink gives us the address family in the header, and the 90 // sockaddr_in or sockaddr_in6 bytes as the payload. We need to 91 // stitch the two bits together into the sockaddr that's part of 92 // our portable interface. 93 void setAddress(int family, void* data, size_t byteCount) { 94 sockaddr_storage* ss = new sockaddr_storage; 95 ss->ss_family = family; 96 if (family == AF_INET) { 97 void* dst = &reinterpret_cast<sockaddr_in*>(ss)->sin_addr; 98 memcpy(dst, data, byteCount); 99 } else if (family == AF_INET6) { 100 void* dst = &reinterpret_cast<sockaddr_in6*>(ss)->sin6_addr; 101 memcpy(dst, data, byteCount); 102 } 103 ifa_addr = reinterpret_cast<sockaddr*>(ss); 104 } 105}; 106 107// FIXME: use iovec instead. 108struct addrReq_struct { 109 nlmsghdr netlinkHeader; 110 ifaddrmsg msg; 111}; 112 113inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) { 114 ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0)); 115 return (sentByteCount == static_cast<ssize_t>(byteCount)); 116} 117 118inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) { 119 return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0)); 120} 121 122// Source-compatible with the BSD function. 123inline int getifaddrs(ifaddrs** result) { 124 // Simplify cleanup for callers. 125 *result = NULL; 126 127 // Create a netlink socket. 128 ScopedFd fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)); 129 if (fd.get() < 0) { 130 return -1; 131 } 132 133 // Ask for the address information. 134 addrReq_struct addrRequest; 135 memset(&addrRequest, 0, sizeof(addrRequest)); 136 addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; 137 addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR; 138 addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest))); 139 addrRequest.msg.ifa_family = AF_UNSPEC; // All families. 140 addrRequest.msg.ifa_index = 0; // All interfaces. 141 if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) { 142 return -1; 143 } 144 145 // Read the responses. 146 LocalArray<0> buf(65536); // We don't necessarily have std::vector. 147 ssize_t bytesRead; 148 while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) { 149 nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]); 150 for (; NLMSG_OK(hdr, bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) { 151 switch (hdr->nlmsg_type) { 152 case NLMSG_DONE: 153 return 0; 154 case NLMSG_ERROR: 155 return -1; 156 case RTM_NEWADDR: 157 { 158 ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); 159 rtattr* rta = IFA_RTA(address); 160 size_t ifaPayloadLength = IFA_PAYLOAD(hdr); 161 while (RTA_OK(rta, ifaPayloadLength)) { 162 if (rta->rta_type == IFA_ADDRESS) { 163 *result = new ifaddrs(*result); 164 if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) { 165 return -1; 166 } 167 (*result)->setAddress(address->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); 168 } 169 rta = RTA_NEXT(rta, ifaPayloadLength); 170 } 171 } 172 break; 173 } 174 } 175 } 176 // We only get here if recv fails before we see a NLMSG_DONE. 177 return -1; 178} 179 180// Source-compatible with the BSD function. 181inline void freeifaddrs(ifaddrs* addresses) { 182 delete addresses; 183} 184 185#endif // IFADDRS_ANDROID_H_included 186