deep-c-rsc/JCGO/goclsp/vm/java/net/VMInetAddress.java
2021-07-16 17:12:20 -05:00

345 lines
8.3 KiB
Java

/*
* @(#) $(JCGO)/goclsp/vm/java/net/VMInetAddress.java --
* VM specific methods for "InetAddress" implementation.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2009 Ivan Maidanski <ivmai@ivmaisoft.com>
* All rights reserved.
**
* Class specification origin: GNU Classpath v0.93 vm/reference
*/
/*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
**
* This software 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 (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package java.net;
import gnu.java.net.VMAccessorGnuJavaNet;
final class VMInetAddress
{
private static volatile boolean initialized;
private static Object getHostLock;
private static volatile String localHostname;
private VMInetAddress() {}
static String getLocalHostname()
{
String hostname = localHostname;
if (hostname == null)
{
initialize();
if ((hostname = getLocalHostname0()) != null && hostname.length() > 0)
localHostname = hostname;
else hostname = "localhost";
}
return hostname;
}
static byte[] lookupInaddrAny()
throws UnknownHostException
{
int address = lookupInaddrAny0();
return new byte[] { (byte) (address >> 24), (byte) (address >> 16),
(byte) (address >> 8), (byte) address };
}
static String getHostByAddr(byte[] ip)
throws UnknownHostException
{
if (ip == null)
throw new NullPointerException();
initialize();
String hostname;
if (getHostLock != null)
{
synchronized (getHostLock)
{
hostname = getHostByAddr0(ip, ip.length);
}
}
else hostname = getHostByAddr0(ip, ip.length);
if (hostname == null || hostname.length() == 0)
throw new UnknownHostException();
return hostname;
}
static byte[][] getHostByName(String hostname)
throws UnknownHostException
{
initialize();
if (hostname.length() == 0 || hostname.charAt(0) <= ' ')
throw new UnknownHostException(hostname);
int count;
int pos;
byte[] ipAddrsBuf = new byte[40];
do
{
int res;
if (getHostLock != null)
{
synchronized (getHostLock)
{
res = getHostByName0(hostname, ipAddrsBuf, ipAddrsBuf.length);
}
}
else res = getHostByName0(hostname, ipAddrsBuf, ipAddrsBuf.length);
if (res <= 0)
throw new UnknownHostException(hostname);
pos = 0;
for (count = 0; count < res; count++)
{
if (ipAddrsBuf.length <= pos)
break;
pos = (ipAddrsBuf[pos] & 0xff) + pos + 1;
}
if (count == res && ipAddrsBuf.length >= pos)
break;
ipAddrsBuf = new byte[ipAddrsBuf.length << 1];
} while (true);
byte[][] addrs = new byte[count][];
pos = 0;
for (int i = 0; i < count; i++)
{
int iplen = ipAddrsBuf[pos++] & 0xff;
byte[] ip = new byte[iplen];
for (int j = 0; j < iplen; j++)
ip[j] = ipAddrsBuf[pos++];
addrs[i] = ip;
}
return addrs;
}
static byte[] aton(String address)
{
byte[] addr = null;
int len = address.length();
if (len > 0)
{
boolean isIPv6 = false;
if (address.charAt(0) == '[')
{
if (address.charAt(len - 1) != ']')
return null;
address = address.substring(1, len - 1);
isIPv6 = true;
}
if (isIPv6 || (addr = atonIPv4(address, 0, len)) == null)
addr = atonIPv6(address);
}
return addr;
}
private static byte[] atonIPv4(String address, int pos, int endPos)
{
int cnt = 0;
for (int i = pos - 1; (i = address.indexOf('.', i + 2)) >= 0; cnt++)
if (i >= endPos)
break;
if (cnt <= 3)
{
byte[] addr = new byte[4];
try
{
for (int i = 0; i < cnt; i++)
{
int nextPos = address.indexOf('.', pos + 1);
int value = parseUInt(address, pos, nextPos);
if ((value >>> 1) > 0x7f)
return null;
addr[i] = (byte) value;
pos = nextPos + 1;
}
if (pos < endPos)
{
int value = parseUInt(address, pos, endPos);
if ((-1 >>> ((cnt << 3) + 1)) >= (value >>> 1))
{
while (cnt < 3)
{
addr[cnt] = (byte) (value >> ((3 - cnt) << 3));
cnt++;
}
addr[3] = (byte) value;
return addr;
}
}
}
catch (NumberFormatException e) {}
}
return null;
}
private static int parseUInt(String str, int pos, int endPos)
throws NumberFormatException
{
int value = 0;
do
{
char ch = str.charAt(pos);
if (ch < '0' || ch > '9' || value > (-1 >>> 1) / 5 ||
((value = value * 10 + (ch - '0')) >= 0 && ch - '0' > value))
throw new NumberFormatException();
} while (++pos < endPos);
return value;
}
private static byte[] atonIPv6(String address)
{
int len = address.length();
if (len <= 1)
return null;
int pos = address.indexOf('%', 0);
if (pos >= 0)
{
if (len - 1 == pos)
return null;
len = pos;
}
pos = 0;
if (address.charAt(0) == ':')
{
if (address.charAt(1) != ':')
return null;
pos = 1;
}
byte[] addr = new byte[16];
int firstPos = pos;
int j = 0;
int value = 0;
int zerosIndex = -1;
boolean hasDigits = false;
while (pos < len)
{
char ch = address.charAt(pos++);
int digit =
ch >= '0' && ch <= '9' ? ch - '0' : ch >= 'A' && ch <= 'F' ?
ch - ('A' - 10) : ch >= 'a' && ch <= 'f' ? ch - ('a' - 10) : -1;
if (digit != -1)
{
if (value > 0xfff)
return null;
value = (value << 4) | digit;
hasDigits = true;
}
else
{
if (ch != ':')
{
if (ch != '.' || j > 12)
return null;
pos = address.indexOf('.', pos + 1);
if (pos < 0 || (pos = address.indexOf('.', pos + 2)) < 0 || pos >= len)
return null;
byte[] addrIPv4 = atonIPv4(address, firstPos, len);
if (addrIPv4 == null)
return null;
System.arraycopy(addrIPv4, 0, addr, j, 4);
hasDigits = false;
j += 4;
break;
}
firstPos = pos;
if (hasDigits)
{
if (pos == len || j > 14)
return null;
addr[j] = (byte) (value >> 8);
addr[j + 1] = (byte) value;
hasDigits = false;
j += 2;
value = 0;
}
else
{
if (zerosIndex >= 0)
return null;
zerosIndex = j;
}
}
}
if (hasDigits)
{
if (j > 14)
return null;
addr[j] = (byte) (value >> 8);
addr[j + 1] = (byte) value;
j += 2;
}
if (zerosIndex >= 0)
{
if (j == 16)
return null;
j -= zerosIndex;
if (j > 0)
{
System.arraycopy(addr, zerosIndex, addr, 16 - j, j);
if (j > 8)
j = 16 - j;
while (j-- > 0)
addr[zerosIndex++] = 0;
}
}
else if (j != 16)
return null;
return addr;
}
private static void initialize()
{
if (!initialized)
{
VMAccessorGnuJavaNet.socketsInitVMPlainSocketImpl();
if (getHostNeedsSync0() != 0)
{
Object obj = new Object();
if (getHostLock == null)
getHostLock = obj;
}
initialized = true;
}
}
private static native int lookupInaddrAny0();
private static native String getLocalHostname0();
private static native int getHostNeedsSync0();
private static native String getHostByAddr0(byte[] ip,
int iplen); /* blocking syscall */
private static native int getHostByName0(String hostname, byte[] ipAddrsBuf,
int bufSize); /* blocking syscall */
}