java.net.Inet6AddressImpl$_qbicc Maven / Gradle / Ivy
/*
* 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.posix.ArpaInet.*;
import static jdk.internal.sys.posix.Netdb.*;
import static jdk.internal.sys.posix.NetIf.*;
import static jdk.internal.sys.posix.NetinetIn.*;
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 java.nio.charset.StandardCharsets;
import org.qbicc.rt.annotation.Tracking;
import org.qbicc.runtime.Build;
@Tracking("src/java.base/unix/native/libnet/Inet6AddressImpl.c")
class Inet6AddressImpl$_qbicc {
static ptr getStringPlatformChars(final String str) throws OutOfMemoryError {
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
ptr ptr = malloc(word(bytes.length + 1));
if (ptr.isNull()) {
throw new OutOfMemoryError("malloc failed");
}
copy(ptr.cast(), bytes, 0, bytes.length);
ptr.asArray()[bytes.length] = zero();
return ptr;
}
static InetAddress[] lookupIfLocalhost(ptr<@c_const c_char> hostname, boolean includeV6) throws SocketException {
if (Build.Target.isMacOs()) {
InetAddress[] result = null;
c_char[] myhostname = new c_char[256];
ptr ifa = auto();
c_int familyOrder = word(0);
int count = 0;
int addrs4 = 0;
int addrs6 = 0;
int numV4Loopbacks = 0;
int numV6Loopbacks = 0;
boolean includeLoopback = false;
/* If the requested name matches this host's hostname, return IP addresses
* from all attached interfaces. (#2844683 et al) This prevents undesired
* PPP dialup, but may return addresses that don't actually correspond to
* the name (if the name actually matches something in DNS etc.
*/
myhostname[0] = word('\0');
if (gethostname(addr_of(myhostname[0]), word(myhostname.length)).intValue() == -1) {
/* Something went wrong, maybe networking is not setup? */
return null;
}
myhostname[myhostname.length-1] = word('\0');
if (strcmp(addr_of(myhostname[0]), hostname).intValue() != 0) {
// Non-self lookup
return null;
}
if (getifaddrs(addr_of(ifa).cast()).intValue() != 0) {
throw new SocketException("Can't get local interface addresses");
}
String name = utf8zToJavaString(hostname.cast());
/* Iterate over the interfaces, and total up the number of IPv4 and IPv6
* addresses we have. Also keep a count of loopback addresses. We need to
* exclude them in the normal case, but return them if we don't get an IP
* address.
*/
for (ptr iter = ifa; !iter.isNull(); iter = deref(iter).ifa_next) {
if (!iter.sel().ifa_addr.isNull()) {
int family = iter.sel().ifa_addr.sel().sa_family.intValue();
if (deref(iter).ifa_name.loadUnshared() != word('\0')) {
boolean isLoopback = (iter.sel().ifa_flags.intValue() & IFF_LOOPBACK.intValue()) != 0;
if (family == AF_INET.intValue()) {
addrs4++;
if (isLoopback) numV4Loopbacks++;
} else if (family == AF_INET6.intValue() && includeV6) {
addrs6++;
if (isLoopback) numV6Loopbacks++;
} // else we don't care, e.g. AF_LINK
}
}
}
if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
// We don't have a real IP address, just loopback. We need to include
// loopback in our results.
includeLoopback = true;
}
/* Create and fill the Java array. */
int arraySize = addrs4 + addrs6 - (includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
result = new InetAddress[arraySize];
int i, j;
if (InetAddress.preferIPv6Address != 0) {
i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
j = 0;
} else {
i = 0;
j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
}
// Now loop around the ifaddrs
for (ptr iter = ifa; !iter.isNull(); iter = deref(iter).ifa_next) {
if (!iter.sel().ifa_addr.isNull()) {
int family = iter.sel().ifa_addr.sel().sa_family.intValue();
boolean isLoopback = (iter.sel().ifa_flags.intValue() & IFF_LOOPBACK.intValue()) != 0;
if (deref(iter).ifa_name.loadUnshared() != word('\0') &&
(family == AF_INET.intValue() || (family == AF_INET6.intValue() && includeV6)) &&
(!isLoopback || includeLoopback)) {
c_int port = auto();
int index = (family == AF_INET.intValue()) ? i++ : j++;
InetAddress o = NetUtil.sockaddrToInetAddress(iter.sel().ifa_addr.cast(), addr_of(port));
o.holder().hostName = name;
result[index] = o;
}
}
}
freeifaddrs(ifa.cast());
return result;
} else {
return null;
}
}
static InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException {
if (host == null) {
throw new NullPointerException("host argument is null");
}
InetAddress[] ret = null;
ptr res = auto();
ptr resNew = word(0);
ptr last = word(0);
ptr iterator = word(0);
ptr<@c_const c_char> hostname = getStringPlatformChars(host).cast();
try {
struct_addrinfo hints = auto();
memset(addr_of(hints).cast(), word(0), sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
c_int error = getaddrinfo(hostname, word(0), addr_of(hints).cast(), addr_of(res));
if (error.intValue() != 0) {
if (Build.Target.isMacOs()) {
try {
ret = lookupIfLocalhost(hostname, true);
if (ret != null) {
return ret;
}
} catch (SocketException e) {
// JDK supresses SocketException in favor of UnknownHostException
}
}
// TODO: strerror in detailed message.
throw new UnknownHostException(host);
} else {
int i = 0;
int inetCount = 0;
int inet6Count = 0;
int inetIndex = 0;
int inet6Index = 0;
int originalIndex = 0;
int addressPreference = InetAddress.preferIPv6Address;
iterator = res;
while (!iterator.isNull()) {
// skip duplicates
boolean skip = false;
ptr iteratorNew = resNew;
while (!iteratorNew.isNull()) {
if (iterator.sel().ai_family == iteratorNew.sel().ai_family &&
iterator.sel().ai_addrlen == iteratorNew.sel().ai_addrlen) {
if (iteratorNew.sel().ai_family == AF_INET) { /* AF_INET */
ptr addr1 = iterator.sel().ai_addr.cast();
ptr addr2 = iteratorNew.sel().ai_addr.cast();
if (addr1.sel().sin_addr.s_addr == addr2.sel().sin_addr.s_addr) {
skip = true;
break;
}
} else {
int t;
ptr addr1 = iterator.sel().ai_addr.cast();
ptr addr2 = iteratorNew.sel().ai_addr.cast();
for (t = 0; t < 16; t++) {
if (addr1.sel().sin6_addr.s6_addr[t] != addr2.sel().sin6_addr.s6_addr[t]) {
break;
}
}
if (t < 16) {
iteratorNew = iteratorNew.sel().ai_next.cast();
continue;
} else {
skip = true;
break;
}
}
} else if (iterator.sel().ai_family != AF_INET && iterator.sel().ai_family != AF_INET6) {
// we can't handle other family types
skip = true;
break;
}
iteratorNew = iteratorNew.sel().ai_next.cast();
}
if (!skip) {
ptr next = malloc(sizeof(struct_addrinfo.class));
if (next.isNull()) {
throw new OutOfMemoryError("Native heap allocation failed");
}
memcpy(next.cast(), iterator.cast(), sizeof(struct_addrinfo.class));
next.sel().ai_next = word(0);
if (resNew.isNull()) {
resNew = next;
} else {
last.sel().ai_next = next;
}
last = next;
i++;
if (iterator.sel().ai_family == AF_INET) {
inetCount++;
} else if (iterator.sel().ai_family == AF_INET6) {
inet6Count++;
}
}
iterator = iterator.sel().ai_next.cast();
}
// allocate array - at this point i contains the number of addresses
ret = new InetAddress[i];
if (addressPreference == InetAddress.PREFER_IPV6_VALUE) {
inetIndex = inet6Count;
inet6Index = 0;
} else if (addressPreference == InetAddress.PREFER_IPV4_VALUE) {
inetIndex = 0;
inet6Index = inetCount;
} else if (addressPreference == InetAddress.PREFER_SYSTEM_VALUE) {
inetIndex = inet6Index = originalIndex = 0;
}
iterator = resNew;
while (!iterator.isNull()) {
if (iterator.sel().ai_family == AF_INET) {
Inet4Address iaObj = new Inet4Address();
ptr addr1 = iterator.sel().ai_addr.cast();
iaObj.holder().address = ntohl(addr1.sel().sin_addr.s_addr.cast()).intValue();
iaObj.holder().hostName = host;
iaObj.holder().originalHostName = host;
ret[inetIndex | originalIndex] = iaObj;
inetIndex++;
} else if (iterator.sel().ai_family == AF_INET6) {
Inet6Address iaObj = new Inet6Address();
Inet6Address$_patch ia6Obj = (Inet6Address$_patch)(Object)iaObj;
ptr addr6 = iterator.sel().ai_addr.cast();
ptr addr = addr_of(addr6.sel().sin6_addr.s6_addr[0]);
ia6Obj.setInet6Address_ipaddress(addr);
int scope = addr6.sel().sin6_scope_id.intValue();
if (scope != 0) {
ia6Obj.setInet6Address_scopeid(scope);
}
iaObj.holder().hostName = host;
iaObj.holder().originalHostName = host;
ret[inet6Index | originalIndex] = iaObj;
inet6Index++;
}
if (addressPreference == InetAddress.PREFER_SYSTEM_VALUE) {
originalIndex++;
inetIndex = inet6Index = 0;
}
iterator = iterator.sel().ai_next.cast();
}
return ret;
}
} finally {
// cleanup native memory
free(hostname);
while (!resNew.isNull()) {
ptr toFree = resNew;
resNew = addr_of(resNew.sel().ai_next).loadUnshared().cast();
free(toFree);
}
if (!res.isNull()) {
freeaddrinfo(res);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy