ifaddrs-android.h revision 5d26339aed33942ba82bfdb79e1b7e9a832c96a7
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#include <stdio.h> 25#include <linux/netlink.h> 26#include <linux/rtnetlink.h> 27 28#include "LocalArray.h" 29#include "ScopedFd.h" 30 31// NOTE: this in JNIHelp.h in later releases. 32const char* jniStrError(int errnum, char* buf, size_t buflen) { 33 // note: glibc has a nonstandard strerror_r that returns char* rather 34 // than POSIX's int. 35 // char *strerror_r(int errnum, char *buf, size_t n); 36 char* ret = (char*) strerror_r(errnum, buf, buflen); 37 if (((int)ret) == 0) { 38 //POSIX strerror_r, success 39 return buf; 40 } else if (((int)ret) == -1) { 41 //POSIX strerror_r, failure 42 // (Strictly, POSIX only guarantees a value other than 0. The safest 43 // way to implement this function is to use C++ and overload on the 44 // type of strerror_r to accurately distinguish GNU from POSIX. But 45 // realistic implementations will always return -1.) 46 snprintf(buf, buflen, "errno %d", errnum); 47 return buf; 48 } else { 49 //glibc strerror_r returning a string 50 return ret; 51 } 52} 53 54// NOTE: this in bionic's stdlib.h in later releases. 55#define TEMP_FAILURE_RETRY(exp) ({ \ 56 typeof (exp) _rc; \ 57 do { \ 58 _rc = (exp); \ 59 } while (_rc == -1 && errno == EINTR); \ 60 _rc; }) 61 62// Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3). 63// We fake it here, so java_net_NetworkInterface.cpp can use that API 64// with all the non-portable code being in this file. 65 66// Source-compatible subset of the BSD struct. 67struct ifaddrs { 68 // Pointer to next struct in list, or NULL at end. 69 ifaddrs* ifa_next; 70 71 // Interface name. 72 char* ifa_name; 73 74 // Interface flags. 75 unsigned int ifa_flags; 76 77 // Interface address. 78 sockaddr* ifa_addr; 79 80 ifaddrs(ifaddrs* next) 81 : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL) 82 { 83 } 84 85 ~ifaddrs() { 86 delete ifa_next; 87 delete[] ifa_name; 88 delete ifa_addr; 89 } 90 91 // Sadly, we can't keep the interface index for portability with BSD. 92 // We'll have to keep the name instead, and re-query the index when 93 // we need it later. 94 bool setNameAndFlagsByIndex(int interfaceIndex) { 95 // Get the name. 96 char buf[IFNAMSIZ]; 97 char* name = if_indextoname(interfaceIndex, buf); 98 if (name == NULL) { 99 return false; 100 } 101 ifa_name = new char[strlen(name) + 1]; 102 strcpy(ifa_name, name); 103 104 // Get the flags. 105 ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0)); 106 if (fd.get() == -1) { 107 return false; 108 } 109 ifreq ifr; 110 memset(&ifr, 0, sizeof(ifr)); 111 strcpy(ifr.ifr_name, name); 112 int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr); 113 if (rc == -1) { 114 return false; 115 } 116 ifa_flags = ifr.ifr_flags; 117 return true; 118 } 119 120 // Netlink gives us the address family in the header, and the 121 // sockaddr_in or sockaddr_in6 bytes as the payload. We need to 122 // stitch the two bits together into the sockaddr that's part of 123 // our portable interface. 124 void setAddress(int family, void* data, size_t byteCount) { 125 sockaddr_storage* ss = new sockaddr_storage; 126 ss->ss_family = family; 127 if (family == AF_INET) { 128 void* dst = &reinterpret_cast<sockaddr_in*>(ss)->sin_addr; 129 memcpy(dst, data, byteCount); 130 } else if (family == AF_INET6) { 131 void* dst = &reinterpret_cast<sockaddr_in6*>(ss)->sin6_addr; 132 memcpy(dst, data, byteCount); 133 } 134 ifa_addr = reinterpret_cast<sockaddr*>(ss); 135 } 136}; 137 138// FIXME: use iovec instead. 139struct addrReq_struct { 140 nlmsghdr netlinkHeader; 141 ifaddrmsg msg; 142}; 143 144inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) { 145 ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0)); 146 return (sentByteCount == static_cast<ssize_t>(byteCount)); 147} 148 149inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) { 150 return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0)); 151} 152 153// Source-compatible with the BSD function. 154inline int getifaddrs(ifaddrs** result) { 155 // Simplify cleanup for callers. 156 *result = NULL; 157 158 // Create a netlink socket. 159 ScopedFd fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)); 160 if (fd.get() < 0) { 161 return -1; 162 } 163 164 // Ask for the address information. 165 addrReq_struct addrRequest; 166 memset(&addrRequest, 0, sizeof(addrRequest)); 167 addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; 168 addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR; 169 addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest))); 170 addrRequest.msg.ifa_family = AF_UNSPEC; // All families. 171 addrRequest.msg.ifa_index = 0; // All interfaces. 172 if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) { 173 return -1; 174 } 175 176 // Read the responses. 177 LocalArray<0> buf(65536); // We don't necessarily have std::vector. 178 ssize_t bytesRead; 179 while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) { 180 nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]); 181 for (; NLMSG_OK(hdr, bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) { 182 switch (hdr->nlmsg_type) { 183 case NLMSG_DONE: 184 return 0; 185 case NLMSG_ERROR: 186 return -1; 187 case RTM_NEWADDR: 188 { 189 ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); 190 rtattr* rta = IFA_RTA(address); 191 size_t ifaPayloadLength = IFA_PAYLOAD(hdr); 192 while (RTA_OK(rta, ifaPayloadLength)) { 193 if (rta->rta_type == IFA_ADDRESS) { 194 int family = address->ifa_family; 195 if (family == AF_INET || family == AF_INET6) { 196 *result = new ifaddrs(*result); 197 if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) { 198 return -1; 199 } 200 (*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta)); 201 } 202 } 203 rta = RTA_NEXT(rta, ifaPayloadLength); 204 } 205 } 206 break; 207 } 208 } 209 } 210 // We only get here if recv fails before we see a NLMSG_DONE. 211 return -1; 212} 213 214// Source-compatible with the BSD function. 215inline void freeifaddrs(ifaddrs* addresses) { 216 delete addresses; 217} 218 219#endif // IFADDRS_ANDROID_H_included 220