All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.net.NetworkInterface$_qbicc Maven / Gradle / Ivy

There is a newer version: 17.alpha.0.57
Show newest version
/*
 * This code is based on OpenJDK source file(s) which contain the following copyright notice:
 *
 * ------
 * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 * ------
 *
 * This file may contain additional modifications which are Copyright (c) Red Hat and other
 * contributors.
 */

package java.net;

import static org.qbicc.runtime.CNative.*;
import static jdk.internal.sys.bsd.Ifaddrs.*;
import static jdk.internal.sys.bsd.NetIf.*;
import static jdk.internal.sys.linux.SysIoctl.*;
import static jdk.internal.sys.posix.ArpaInet.*;
import static jdk.internal.sys.posix.Errno.*;
import static jdk.internal.sys.posix.SysIoctl.*;
import static jdk.internal.sys.posix.NetinetIn.*;
import static jdk.internal.sys.posix.NetIf.*;
import static jdk.internal.sys.posix.SysSocket.*;
import static jdk.internal.sys.posix.Unistd.*;
import static org.qbicc.runtime.stdc.Errno.*;
import static org.qbicc.runtime.stdc.Stddef.*;
import static org.qbicc.runtime.stdc.Stdint.*;
import static org.qbicc.runtime.stdc.Stdlib.*;
import static org.qbicc.runtime.stdc.String.*;

import org.qbicc.rt.annotation.Tracking;
import org.qbicc.runtime.Build;

@Tracking("src/java.base/unix/native/libnet/NetworkInterface.c")
@Tracking("src/java.base/windows/native/libnet/NetworkInterface.c")
class NetworkInterface$_qbicc {

    static class netaddr {
        ptr addr;
        ptr brdcast;
        c_short mask;
        c_int family;
        netaddr next;
    }

    static class netif {
        ptr name;
        c_int index;
        boolean virtual;
        netaddr addr;
        netif childs;
        netif next;
    }

    /*
     * Frees the malloced struct_sockaddrs and ptrs for an interface list (including any attached addresses).
     */
    private static void freeif(netif ifs) {
        for (netif currif = ifs; currif != null; currif = currif.next) {
            for (netaddr addrP = currif.addr; addrP != null; addrP = addrP.next) {
                free(addrP.addr.cast());
                free(addrP.brdcast.cast());
                addrP.addr = word(0);
                addrP.brdcast = word(0);
            }
            if (currif.childs != null) {
                freeif(currif.childs);
            }
            free(ifs.name.cast());
            ifs.name = word(0);
        }
    }

    static netif addif(c_int sock, ptr<@c_const c_char> if_name, netif ifs,
                       ptr ifr_addrP, ptr ifr_broadaddrP,
                       c_int family, c_short prefix) {
        netif currif = ifs;
        c_char[] name = new c_char[IF_NAMESIZE.intValue()];
        c_char[] vname = new c_char[IF_NAMESIZE.intValue()];
        boolean isVirtual = false;

        // If the interface name is a logical interface then we remove the unit
        // number so that we have the physical interface (eg: hme0:1 -> hme0).
        // NetworkInterface currently doesn't have any concept of physical vs.
        // logical interfaces.
        strncpy(addr_of(name[0]).cast(), if_name.cast(), IF_NAMESIZE.cast());
        name[IF_NAMESIZE.intValue() - 1] = word(0);
        vname[0] = word(0);

        // Create and populate the netaddr node.
        netaddr addrP = new netaddr();
        size_t addr_size = (family == AF_INET) ? sizeof(struct_sockaddr_in.class) : sizeof(struct_sockaddr_in6.class);
        addrP.addr = malloc(addr_size);
        if (addrP.addr.isNull()) {
            return ifs; // match OpenJDK behavior: if malloc fails just return the unmodified netif
        }
        memcpy(addrP.addr.cast(), ifr_addrP.cast(), addr_size);
        addrP.family = family;
        addrP.mask = prefix;
        addrP.next = null;

        // for IPv4 add broadcast address
        if (family == AF_INET && !ifr_broadaddrP.isNull()) {
            addrP.brdcast = malloc(addr_size);
            if (addrP.brdcast.isNull()) {
                return ifs; // match OpenJDK behavior: if malloc fails just return the unmodified netif
            }
            memcpy(addrP.brdcast.cast(), ifr_broadaddrP.cast(), addr_size);
        } else {
            addrP.brdcast = word(0);
        }

        // Deal with virtual interface with colon notation e.g. eth0:1
        int colonIdx = 0;
        for (int i=0; i addr) {
        if (addr.isNull()) {
            return word(0);
        }
        short prefix = 0;
        int mask = ntohl(addr.sel().sin_addr.s_addr.cast()).intValue();
        while (mask != 0) {
            mask = mask << 1;
            prefix++;
        }
        return word(prefix);
    }

    private static c_int openSocket(c_int proto) throws SocketException {
        c_int sock = socket(proto, SOCK_DGRAM, word(0));
        if (sock.intValue() < 0) {
            if (errno != EPROTONOTSUPPORT.intValue() && errno != EAFNOSUPPORT.intValue()) {
                throw new SocketException("Socket creation failed");
            }
            return word(-1);
        }
        return sock;
    }

    private static netif enumIPv4Interfaces(c_int sock, netif ifs) throws SocketException {
        if (Build.Target.isLinux()) {
            struct_ifconf ifc = auto();

            // do a dummy SIOCGIFCONF to determine the buffer size
            // SIOCGIFCOUNT doesn't work
            if (ioctl(sock, SIOCGIFCONF, addr_of(ifc.ifc_len)).intValue() < 0) {
                throw new SocketException("ioctl(SIOCGIFCONF) failed");
            }

            // call SIOCGIFCONF to enumerate the interfaces
            ptr buf = malloc(word(ifc.ifc_len.intValue()));
            if (buf.isNull()) {
                throw new OutOfMemoryError("Native heap allocation failed");
            }
            try {
                ifc.ifc_ifcu = buf.cast();
                if (ioctl(sock, SIOCGIFCONF, addr_of(ifc)).intValue() < 0) {
                    throw new SocketException("ioctl(SIOCGIFCONF) failed");
                }

                // iterate through each interface
                ptr ifreqP = ifc.ifc_ifcu.cast();
                for (int i = 0; i < ifc.ifc_len.intValue() / sizeof(struct_ifreq.class).intValue(); i++, ifreqP = ifreqP.plus(1)) {
                    struct_sockaddr addr = auto();
                    struct_sockaddr broadaddr = auto();
                    ptr broadaddrP = auto();
                    c_short prefix = word(0);

                    // ignore non IPv4 addresses
                    if (addr_of(ifreqP.sel().ifr_ifru).loadUnshared(struct_sockaddr.class).sa_family != AF_INET.cast()) {
                        continue;
                    }

                    // save socket address
                    memcpy(addr_of(addr).cast(), addr_of(ifreqP.sel().ifr_ifru).cast(), sizeof(struct_sockaddr.class));

                    // determine broadcast address, if applicable
                    if ((ioctl(sock, SIOCGIFFLAGS, ifreqP).intValue() == 0) && ((addr_of(ifreqP.sel().ifr_ifru).loadUnshared(c_short.class).intValue() & IFF_BROADCAST.intValue()) != 0)) {
                        // restore socket address to ifreqP
                        memcpy(addr_of(ifreqP.sel().ifr_ifru).cast(), addr_of(addr).cast(), sizeof(struct_sockaddr.class));

                        if (ioctl(sock, SIOCGIFBRDADDR, ifreqP).intValue() == 0) {
                            memcpy(addr_of(broadaddr).cast(), addr_of(ifreqP.sel().ifr_ifru).cast(), sizeof(struct_sockaddr.class));
                            broadaddrP = addr_of(broadaddr);
                        }
                    }

                    // restore socket address to ifreqP
                    memcpy(addr_of(ifreqP.sel().ifr_ifru).cast(), addr_of(addr).cast(), sizeof(struct_sockaddr.class));

                    // determine netmask
                    if (ioctl(sock, SIOCGIFNETMASK, ifreqP).intValue() == 0) {
                        prefix = translateIPv4AddressToPrefix(addr_of(ifreqP.sel().ifr_ifru).cast());
                    }

                    // add interface to the list
                    ifs = addif(sock, addr_of(ifreqP.sel().ifr_name[0]), ifs, addr_of(addr), broadaddrP, AF_INET, prefix);
                }
            } finally {
                free(buf);
            }
        } else if (Build.Target.isMacOs()) {
            ptr origifa = auto();

            if (getifaddrs(addr_of(origifa)).intValue() != 0) {
                throw new SocketException("getifaddrs() failed");
            }

            try {
                for (ptr ifa = origifa; !ifa.isNull(); ifa = deref(ifa).ifa_next) {
                    ptr broadaddrP = word(0);

                    // ignore non IPv4 addresses
                    if (ifa.sel().ifa_addr.isNull() || ifa.sel().ifa_addr.sel().sa_family.intValue() != AF_INET.intValue()) {
                        continue;
                    }

                    // set ifa_broadaddr, if there is one
                    if ((ifa.sel().ifa_flags.intValue() & IFF_POINTOPOINT.intValue()) == 0 &&
                            (ifa.sel().ifa_flags.intValue() & IFF_BROADCAST.intValue()) != 0) {
                        broadaddrP = ifa.sel().ifa_dstaddr;
                    }

                    ifs = addif(sock, ifa.sel().ifa_name.cast(), ifs, ifa.sel().ifa_addr,
                            broadaddrP, AF_INET, translateIPv4AddressToPrefix(ifa.sel().ifa_netmask.cast()));
                }
            } finally {
                freeifaddrs(origifa);
            }
        }

        return ifs;
    }

    private static netif enumIPv6Interfaces(c_int sock, netif ifs) throws SocketException {
        // TODO: implement me -- currently not reachable: ipv6_available is hardwired to return false.
        return ifs;
    }

    private static c_int getIndex(c_int sock, ptr<@c_const c_char> name) {
        if (Build.Target.isMacOs()) {
            unsigned_int index = if_nametoindex(name);
            return (index.intValue() == 0) ? word(-1) : index.cast();
        } else {
            struct_ifreq if2 = auto();
            strncpy(addr_of(if2.ifr_name[0]).cast(), name.cast(), word(IF_NAMESIZE.intValue() - 1));
            if (ioctl(sock, SIOCGIFINDEX, addr_of(if2)).intValue() <0){
                return word(-1);
            }
            return addr_of(addr_of(if2).sel().ifr_ifru).loadUnshared(c_int.class);
        }
    }

    private static c_int getFlags(c_int sock, ptr<@c_const c_char> ifname, ptr flags) {
        struct_ifreq if2 = auto();
        strncpy(addr_of(if2.ifr_name[0]).cast(), ifname.cast(), word(IF_NAMESIZE.intValue() - 1));

        if (ioctl(sock, SIOCGIFFLAGS, addr_of(if2)).intValue() < 0) {
            return word(-1);
        }
        // TODO: The OpenJDK code has a sizeof test on the ifreq.ifru.ifru_flags field to
        //       see if it has a size of 16 bits or not.  This was hard to translate, so for now we're
        //       just assuming that it is a c_short and is thus 16 bits.
        c_short f2 = addr_of(addr_of(if2).sel().ifr_ifru).loadUnshared(c_short.class);
        flags.storeUnshared(word(f2.intValue() & 0xffff));
        return word(0);
    }

    /*
     * Creates a NetworkInterface object, populates the name, the index, and
     * populates the InetAddress array based on the IP addresses for this
     * interface.
     */
    private static NetworkInterface createNetworkInterface(netif ifs) {
        // create a NetworkInterface object and populate it
        NetworkInterface$_patch netifObj = new NetworkInterface$_patch();
        String name = utf8zToJavaString(ifs.name.cast());
        netifObj.name = name;
        netifObj.displayName = name;
        netifObj.index = ifs.index.intValue();
        netifObj.virtual = ifs.virtual;

        // count the number of addresses on this interface
        int addr_count = 0;
        for (netaddr addrP = ifs.addr; addrP != null; addrP = addrP.next) {
            addr_count++;
        }

        InetAddress[] addrArr = new InetAddress[addr_count];
        InterfaceAddress[] bindArr = new InterfaceAddress[addr_count];
        int addr_index = 0;
        int bind_index = 0;
        for (netaddr addrP = ifs.addr; addrP != null; addrP = addrP.next) {
            InetAddress iaObj = null;
            if (addrP.family == AF_INET) {
                iaObj = new Inet4Address();
                ptr sinp = addrP.addr.cast();
                unsigned_int tmpAddr = htonl(sinp.sel().sin_addr.s_addr.cast()).cast();
                iaObj.holder().address = tmpAddr.intValue();
                InterfaceAddress ibObj = new InterfaceAddress();
                ((InterfaceAddress$_patch)(Object)ibObj).address = iaObj;
                if (!addrP.brdcast.isNull()) {
                    Inet4Address ia2Obj = new Inet4Address();
                    sinp = addrP.brdcast.cast();
                    unsigned_int tmpBAddr = htonl(sinp.sel().sin_addr.s_addr.cast()).cast();
                    ia2Obj.holder().address = tmpBAddr.intValue();
                    ((InterfaceAddress$_patch)(Object)ibObj).broadcast = ia2Obj;
                }
                ((InterfaceAddress$_patch)(Object)ibObj).maskLength = addrP.mask.shortValue();
                bindArr[bind_index++] = ibObj;
            }
            if (addrP.family == AF_INET6) {
                iaObj = new Inet6Address();
                Inet6Address$_patch ia6Obj = (Inet6Address$_patch)(Object)iaObj;
                ptr sin6p = addrP.addr.cast();
                ptr addr = addr_of(addr_of(sin6p.sel().sin6_addr).sel().s6_addr[0]);
                ia6Obj.setInet6Address_ipaddress(addr);
                uint32_t scope = sin6p.sel().sin6_scope_id.cast();
                if (scope.intValue() != 0) {
                    ia6Obj.setInet6Address_scopeid(scope.intValue());
                    ia6Obj.setInet6Address_scope_ifname((NetworkInterface)(Object)netifObj);
                }
                InterfaceAddress ibObj = new InterfaceAddress();
                ((InterfaceAddress$_patch)(Object)ibObj).address = iaObj;
                ((InterfaceAddress$_patch)(Object)ibObj).maskLength = addrP.mask.shortValue();
                bindArr[bind_index++] = ibObj;
            }
            addrArr[addr_index++] = iaObj;

        }

        // see if there is any virtual interface attached to this one.
        int childCount = 0;
        netif childP = ifs.childs;
        while (childP != null) {
            childCount++;
            childP = childP.next;
        }
        NetworkInterface[] childArr = new NetworkInterface[childCount];

        // create the NetworkInterface instances for the sub-interfaces as well
        int childIndex = 0;
        childP = ifs.childs;
        while(childP != null) {
            NetworkInterface tmp = createNetworkInterface(childP);
            if (tmp == null) {
                return null;
            }
            ((NetworkInterface$_patch)(Object)tmp).parent = (NetworkInterface)(Object)netifObj;
            childArr[childIndex++] = tmp;
            childP = childP.next;
        }

        netifObj.addrs = addrArr;
        netifObj.bindings = bindArr;
        netifObj.childs = childArr;

        return (NetworkInterface)(Object)netifObj;
    }

    static netif enumInterfaces() {
        netif ifs = null;
        try {
            c_int sock = openSocket(AF_INET);
            if (sock.intValue() >= 0) {
                ifs = enumIPv4Interfaces(sock, ifs);
                close(sock);
            }

            // If IPv6 is available then enumerate IPv6 addresses.
            // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
            // so we have to call ipv6_available()
            if (NetUtil.ipv6_available()) {
                sock = openSocket(AF_INET6);
                if (sock.intValue() < 0) {
                    freeif(ifs);
                    return null;
                }
                ifs = enumIPv6Interfaces(sock, ifs);
                close(sock);
            }
        } catch (SocketException e) {
            freeif(ifs);
            return null;
        }

        return ifs;
    }

    static NetworkInterface[] getAll() throws SocketException {
        netif ifs = enumInterfaces();
        if (ifs == null) {
            return null;
        }

        int ifCount = 0;
        netif curr = ifs;
        while (curr != null) {
            ifCount ++;
            curr = curr.next;
        }
        NetworkInterface[] netIFArr = new NetworkInterface[ifCount];

        curr = ifs;
        int arr_index = 0;
        while (curr != null) {
            NetworkInterface tmp = createNetworkInterface(curr);
            if (tmp == null) {
                freeif(ifs);
                return null;
            }
            netIFArr[arr_index++] = tmp;
            curr = curr.next;
        }

        freeif(ifs);
        return netIFArr;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy