Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/linux/vm/ifaddrs/ifaddrs-android.h
48454 views
// From https://android.googlesource.com/platform/libcore/+/f3afb1b6a4ace33bd60e5801bdb2fcb2e935d486/luni/src/main/native/ifaddrs-android.h12/*3* Copyright (C) 2009 The Android Open Source Project4*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 at8*9* http://www.apache.org/licenses/LICENSE-2.010*11* Unless required by applicable law or agreed to in writing, software12* 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 and15* limitations under the License.16*/17#ifndef IFADDRS_ANDROID_H_included18#define IFADDRS_ANDROID_H_included19#include <arpa/inet.h>20#include <cstring>21#include <errno.h>22#include <net/if.h>23#include <netinet/in.h>24#include <new>25#include <sys/ioctl.h>26#include <sys/types.h>27#include <sys/socket.h>28#include <stdio.h>29#include <linux/netlink.h>30#include <linux/rtnetlink.h>31#include "LocalArray.h"32#include "ScopedFd.h"33// Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3).34// We fake it here, so java_net_NetworkInterface.cpp can use that API35// with all the non-portable code being in this file.36// Source-compatible subset of the BSD struct.37struct ifaddrs {38// Pointer to next struct in list, or NULL at end.39ifaddrs* ifa_next;40// Interface name.41char* ifa_name;42// Interface flags.43unsigned int ifa_flags;44// Interface network address.45sockaddr* ifa_addr;46// Interface netmask.47sockaddr* ifa_netmask;48ifaddrs(ifaddrs* next)49: ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL), ifa_netmask(NULL)50{51}52~ifaddrs() {53delete ifa_next;54delete[] ifa_name;55delete ifa_addr;56delete ifa_netmask;57}58// Sadly, we can't keep the interface index for portability with BSD.59// We'll have to keep the name instead, and re-query the index when60// we need it later.61bool setNameAndFlagsByIndex(int interfaceIndex) {62// Get the name.63char buf[IFNAMSIZ];64char* name = if_indextoname(interfaceIndex, buf);65if (name == NULL) {66return false;67}68ifa_name = new char[strlen(name) + 1];69strcpy(ifa_name, name);70// Get the flags.71ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));72if (fd.get() == -1) {73return false;74}75ifreq ifr;76memset(&ifr, 0, sizeof(ifr));77strcpy(ifr.ifr_name, name);78int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);79if (rc == -1) {80return false;81}82ifa_flags = ifr.ifr_flags;83return true;84}85// Netlink gives us the address family in the header, and the86// sockaddr_in or sockaddr_in6 bytes as the payload. We need to87// stitch the two bits together into the sockaddr that's part of88// our portable interface.89void setAddress(int family, void* data, size_t byteCount) {90// Set the address proper...91sockaddr_storage* ss = new sockaddr_storage;92memset(ss, 0, sizeof(*ss));93ifa_addr = reinterpret_cast<sockaddr*>(ss);94ss->ss_family = family;95uint8_t* dst = sockaddrBytes(family, ss);96memcpy(dst, data, byteCount);97}98// Netlink gives us the prefix length as a bit count. We need to turn99// that into a BSD-compatible netmask represented by a sockaddr*.100void setNetmask(int family, size_t prefixLength) {101// ...and work out the netmask from the prefix length.102sockaddr_storage* ss = new sockaddr_storage;103memset(ss, 0, sizeof(*ss));104ifa_netmask = reinterpret_cast<sockaddr*>(ss);105ss->ss_family = family;106uint8_t* dst = sockaddrBytes(family, ss);107memset(dst, 0xff, prefixLength / 8);108if ((prefixLength % 8) != 0) {109dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8)));110}111}112// Returns a pointer to the first byte in the address data (which is113// stored in network byte order).114uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) {115if (family == AF_INET) {116sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);117return reinterpret_cast<uint8_t*>(&ss4->sin_addr);118} else if (family == AF_INET6) {119sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);120return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);121}122return NULL;123}124private:125// Disallow copy and assignment.126ifaddrs(const ifaddrs&);127void operator=(const ifaddrs&);128};129// FIXME: use iovec instead.130struct addrReq_struct {131nlmsghdr netlinkHeader;132ifaddrmsg msg;133};134inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {135ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));136return (sentByteCount == static_cast<ssize_t>(byteCount));137}138inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {139return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));140}141// Source-compatible with the BSD function.142inline int getifaddrs(ifaddrs** result) {143// Simplify cleanup for callers.144*result = NULL;145// Create a netlink socket.146ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));147if (fd.get() < 0) {148return -1;149}150// Ask for the address information.151addrReq_struct addrRequest;152memset(&addrRequest, 0, sizeof(addrRequest));153addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;154addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;155addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));156addrRequest.msg.ifa_family = AF_UNSPEC; // All families.157addrRequest.msg.ifa_index = 0; // All interfaces.158if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {159return -1;160}161// Read the responses.162LocalArray<0> buf(65536); // We don't necessarily have std::vector.163ssize_t bytesRead;164while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {165nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]);166for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {167switch (hdr->nlmsg_type) {168case NLMSG_DONE:169return 0;170case NLMSG_ERROR:171return -1;172case RTM_NEWADDR:173{174ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));175rtattr* rta = IFA_RTA(address);176size_t ifaPayloadLength = IFA_PAYLOAD(hdr);177while (RTA_OK(rta, ifaPayloadLength)) {178if (rta->rta_type == IFA_LOCAL) {179int family = address->ifa_family;180if (family == AF_INET || family == AF_INET6) {181*result = new ifaddrs(*result);182if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) {183return -1;184}185(*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta));186(*result)->setNetmask(family, address->ifa_prefixlen);187}188}189rta = RTA_NEXT(rta, ifaPayloadLength);190}191}192break;193}194}195}196// We only get here if recv fails before we see a NLMSG_DONE.197return -1;198}199// Source-compatible with the BSD function.200inline void freeifaddrs(ifaddrs* addresses) {201delete addresses;202}203#endif // IFADDRS_ANDROID_H_included204205206