mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8235193: (dc) Remove JNI overhead from DatagramChannel.send implementation
Reviewed-by: chegar
This commit is contained in:
parent
386b387ef2
commit
e7d68cd13b
10 changed files with 438 additions and 159 deletions
|
@ -310,6 +310,13 @@ class Inet4Address extends InetAddress {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 32-bit IPv4 address.
|
||||||
|
*/
|
||||||
|
int addressValue() {
|
||||||
|
return holder().getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IP address string in textual presentation form.
|
* Returns the IP address string in textual presentation form.
|
||||||
*
|
*
|
||||||
|
|
|
@ -793,6 +793,7 @@ class Inet6Address extends InetAddress {
|
||||||
public boolean isMCOrgLocal() {
|
public boolean isMCOrgLocal() {
|
||||||
return holder6.isMCOrgLocal();
|
return holder6.isMCOrgLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the raw IP address of this {@code InetAddress} object. The result
|
* Returns the raw IP address of this {@code InetAddress} object. The result
|
||||||
* is in network byte order: the highest order byte of the address is in
|
* is in network byte order: the highest order byte of the address is in
|
||||||
|
@ -805,6 +806,13 @@ class Inet6Address extends InetAddress {
|
||||||
return holder6.ipaddress.clone();
|
return holder6.ipaddress.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the byte[] with the IPv6 address.
|
||||||
|
*/
|
||||||
|
byte[] addressBytes() {
|
||||||
|
return holder6.ipaddress;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the numeric scopeId, if this instance is associated with
|
* Returns the numeric scopeId, if this instance is associated with
|
||||||
* an interface. If no scoped_id is set, the returned value is zero.
|
* an interface. If no scoped_id is set, the returned value is zero.
|
||||||
|
@ -814,7 +822,7 @@ class Inet6Address extends InetAddress {
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public int getScopeId() {
|
public int getScopeId() {
|
||||||
return holder6.scope_id;
|
return holder6.scope_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -825,7 +833,7 @@ class Inet6Address extends InetAddress {
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public NetworkInterface getScopedInterface() {
|
public NetworkInterface getScopedInterface() {
|
||||||
return holder6.scope_ifname;
|
return holder6.scope_ifname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -326,10 +326,18 @@ public class InetAddress implements java.io.Serializable {
|
||||||
|
|
||||||
public InetAddress getByName(String hostName,
|
public InetAddress getByName(String hostName,
|
||||||
InetAddress hostAddress)
|
InetAddress hostAddress)
|
||||||
throws UnknownHostException
|
throws UnknownHostException
|
||||||
{
|
{
|
||||||
return InetAddress.getByName(hostName, hostAddress);
|
return InetAddress.getByName(hostName, hostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int addressValue(Inet4Address inet4Address) {
|
||||||
|
return inet4Address.addressValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] addressBytes(Inet6Address inet6Address) {
|
||||||
|
return inet6Address.addressBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
init();
|
init();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
package jdk.internal.access;
|
package jdk.internal.access;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
@ -43,4 +45,14 @@ public interface JavaNetInetAddressAccess {
|
||||||
*/
|
*/
|
||||||
InetAddress getByName(String hostName, InetAddress hostAddress)
|
InetAddress getByName(String hostName, InetAddress hostAddress)
|
||||||
throws UnknownHostException;
|
throws UnknownHostException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 32-bit IPv4 address.
|
||||||
|
*/
|
||||||
|
int addressValue(Inet4Address inet4Address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the byte[] with the IPv6 address.
|
||||||
|
*/
|
||||||
|
byte[] addressBytes(Inet6Address inet6Address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,8 +91,15 @@ class DatagramChannelImpl
|
||||||
private final FileDescriptor fd;
|
private final FileDescriptor fd;
|
||||||
private final int fdVal;
|
private final int fdVal;
|
||||||
|
|
||||||
// Native buffer for socket address used by receive0, protected by readLock
|
// Native sockaddrs and cached InetSocketAddress for receive, protected by readLock
|
||||||
private final NativeSocketAddress socketAddress;
|
private NativeSocketAddress sourceSockAddr;
|
||||||
|
private NativeSocketAddress cachedSockAddr;
|
||||||
|
private InetSocketAddress cachedInetSocketAddress;
|
||||||
|
|
||||||
|
// Native sockaddr and cached objects for send, protected by writeLock
|
||||||
|
private final NativeSocketAddress targetSockAddr;
|
||||||
|
private InetSocketAddress previousTarget;
|
||||||
|
private int previousSockAddrLength;
|
||||||
|
|
||||||
// Cleaner to close file descriptor and free native socket address
|
// Cleaner to close file descriptor and free native socket address
|
||||||
private final Cleanable cleaner;
|
private final Cleanable cleaner;
|
||||||
|
@ -150,59 +157,57 @@ class DatagramChannelImpl
|
||||||
|
|
||||||
// -- End of fields protected by stateLock
|
// -- End of fields protected by stateLock
|
||||||
|
|
||||||
public DatagramChannelImpl(SelectorProvider sp)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(sp);
|
|
||||||
|
|
||||||
this.socketAddress = new NativeSocketAddress();
|
public DatagramChannelImpl(SelectorProvider sp) throws IOException {
|
||||||
|
this(sp, (Net.isIPv6Available()
|
||||||
ResourceManager.beforeUdpCreate();
|
? StandardProtocolFamily.INET6
|
||||||
try {
|
: StandardProtocolFamily.INET));
|
||||||
this.family = Net.isIPv6Available()
|
|
||||||
? StandardProtocolFamily.INET6
|
|
||||||
: StandardProtocolFamily.INET;
|
|
||||||
this.fd = Net.socket(family, false);
|
|
||||||
this.fdVal = IOUtil.fdVal(fd);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
ResourceManager.afterUdpClose();
|
|
||||||
socketAddress.free();
|
|
||||||
throw ioe;
|
|
||||||
}
|
|
||||||
|
|
||||||
Runnable releaser = releaserFor(fd, socketAddress);
|
|
||||||
this.cleaner = CleanerFactory.cleaner().register(this, releaser);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
|
public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(sp);
|
super(sp);
|
||||||
|
|
||||||
Objects.requireNonNull(family, "'family' is null");
|
Objects.requireNonNull(family, "'family' is null");
|
||||||
if ((family != StandardProtocolFamily.INET) &&
|
if ((family != StandardProtocolFamily.INET) &&
|
||||||
(family != StandardProtocolFamily.INET6)) {
|
(family != StandardProtocolFamily.INET6)) {
|
||||||
throw new UnsupportedOperationException("Protocol family not supported");
|
throw new UnsupportedOperationException("Protocol family not supported");
|
||||||
}
|
}
|
||||||
if (family == StandardProtocolFamily.INET6) {
|
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
|
||||||
if (!Net.isIPv6Available()) {
|
throw new UnsupportedOperationException("IPv6 not available");
|
||||||
throw new UnsupportedOperationException("IPv6 not available");
|
}
|
||||||
|
|
||||||
|
FileDescriptor fd = null;
|
||||||
|
NativeSocketAddress[] sockAddrs = null;
|
||||||
|
|
||||||
|
ResourceManager.beforeUdpCreate();
|
||||||
|
boolean initialized = false;
|
||||||
|
try {
|
||||||
|
this.family = family;
|
||||||
|
this.fd = fd = Net.socket(family, false);
|
||||||
|
this.fdVal = IOUtil.fdVal(fd);
|
||||||
|
|
||||||
|
sockAddrs = NativeSocketAddress.allocate(3);
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
this.sourceSockAddr = sockAddrs[0];
|
||||||
|
this.cachedSockAddr = sockAddrs[1];
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
this.targetSockAddr = sockAddrs[2];
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
} finally {
|
||||||
|
if (!initialized) {
|
||||||
|
if (sockAddrs != null) NativeSocketAddress.freeAll(sockAddrs);
|
||||||
|
if (fd != null) nd.close(fd);
|
||||||
|
ResourceManager.afterUdpClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.socketAddress = new NativeSocketAddress();
|
Runnable releaser = releaserFor(fd, sockAddrs);
|
||||||
|
|
||||||
ResourceManager.beforeUdpCreate();
|
|
||||||
try {
|
|
||||||
this.family = family;
|
|
||||||
this.fd = Net.socket(family, false);
|
|
||||||
this.fdVal = IOUtil.fdVal(fd);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
ResourceManager.afterUdpClose();
|
|
||||||
socketAddress.free();
|
|
||||||
throw ioe;
|
|
||||||
}
|
|
||||||
|
|
||||||
Runnable releaser = releaserFor(fd, socketAddress);
|
|
||||||
this.cleaner = CleanerFactory.cleaner().register(this, releaser);
|
this.cleaner = CleanerFactory.cleaner().register(this, releaser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,23 +216,37 @@ class DatagramChannelImpl
|
||||||
{
|
{
|
||||||
super(sp);
|
super(sp);
|
||||||
|
|
||||||
|
NativeSocketAddress[] sockAddrs = null;
|
||||||
|
|
||||||
|
ResourceManager.beforeUdpCreate();
|
||||||
|
boolean initialized = false;
|
||||||
try {
|
try {
|
||||||
this.socketAddress = new NativeSocketAddress();
|
this.family = Net.isIPv6Available()
|
||||||
} catch (OutOfMemoryError e) {
|
? StandardProtocolFamily.INET6
|
||||||
nd.close(fd);
|
: StandardProtocolFamily.INET;
|
||||||
throw e;
|
this.fd = fd;
|
||||||
|
this.fdVal = IOUtil.fdVal(fd);
|
||||||
|
|
||||||
|
sockAddrs = NativeSocketAddress.allocate(3);
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
this.sourceSockAddr = sockAddrs[0];
|
||||||
|
this.cachedSockAddr = sockAddrs[1];
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
this.targetSockAddr = sockAddrs[2];
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
} finally {
|
||||||
|
if (!initialized) {
|
||||||
|
if (sockAddrs != null) NativeSocketAddress.freeAll(sockAddrs);
|
||||||
|
nd.close(fd);
|
||||||
|
ResourceManager.afterUdpClose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// increment UDP count to match decrement when closing
|
Runnable releaser = releaserFor(fd, sockAddrs);
|
||||||
ResourceManager.beforeUdpCreate();
|
|
||||||
|
|
||||||
this.family = Net.isIPv6Available()
|
|
||||||
? StandardProtocolFamily.INET6
|
|
||||||
: StandardProtocolFamily.INET;
|
|
||||||
this.fd = fd;
|
|
||||||
this.fdVal = IOUtil.fdVal(fd);
|
|
||||||
|
|
||||||
Runnable releaser = releaserFor(fd, socketAddress);
|
|
||||||
this.cleaner = CleanerFactory.cleaner().register(this, releaser);
|
this.cleaner = CleanerFactory.cleaner().register(this, releaser);
|
||||||
|
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
|
@ -494,7 +513,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
// sender address is in socket address buffer
|
// sender address is in socket address buffer
|
||||||
sender = socketAddress.toInetSocketAddress();
|
sender = sourceSocketAddress();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// security manager and unconnected
|
// security manager and unconnected
|
||||||
|
@ -534,7 +553,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
// sender address is in socket address buffer
|
// sender address is in socket address buffer
|
||||||
InetSocketAddress isa = socketAddress.toInetSocketAddress();
|
InetSocketAddress isa = sourceSocketAddress();
|
||||||
try {
|
try {
|
||||||
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
||||||
bb.flip();
|
bb.flip();
|
||||||
|
@ -613,7 +632,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
// sender address is in socket address buffer
|
// sender address is in socket address buffer
|
||||||
sender = socketAddress.toInetSocketAddress();
|
sender = sourceSocketAddress();
|
||||||
}
|
}
|
||||||
return sender;
|
return sender;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -650,7 +669,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
// sender address is in socket address buffer
|
// sender address is in socket address buffer
|
||||||
sender = socketAddress.toInetSocketAddress();
|
sender = sourceSocketAddress();
|
||||||
}
|
}
|
||||||
return sender;
|
return sender;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -692,13 +711,32 @@ class DatagramChannelImpl
|
||||||
{
|
{
|
||||||
int n = receive0(fd,
|
int n = receive0(fd,
|
||||||
((DirectBuffer)bb).address() + pos, rem,
|
((DirectBuffer)bb).address() + pos, rem,
|
||||||
socketAddress.address(),
|
sourceSockAddr.address(),
|
||||||
connected);
|
connected);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
bb.position(pos + n);
|
bb.position(pos + n);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an InetSocketAddress to represent the source/sender socket address
|
||||||
|
* in sourceSockAddr. Returns the cached InetSocketAddress if the source
|
||||||
|
* address is the same as the cached address.
|
||||||
|
*/
|
||||||
|
private InetSocketAddress sourceSocketAddress() throws IOException {
|
||||||
|
assert readLock.isHeldByCurrentThread();
|
||||||
|
if (cachedInetSocketAddress != null && sourceSockAddr.equals(cachedSockAddr)) {
|
||||||
|
return cachedInetSocketAddress;
|
||||||
|
}
|
||||||
|
InetSocketAddress isa = sourceSockAddr.decode();
|
||||||
|
// swap sourceSockAddr and cachedSockAddr
|
||||||
|
NativeSocketAddress tmp = cachedSockAddr;
|
||||||
|
cachedSockAddr = sourceSockAddr;
|
||||||
|
sourceSockAddr = tmp;
|
||||||
|
cachedInetSocketAddress = isa;
|
||||||
|
return isa;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int send(ByteBuffer src, SocketAddress target)
|
public int send(ByteBuffer src, SocketAddress target)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
@ -709,7 +747,8 @@ class DatagramChannelImpl
|
||||||
writeLock.lock();
|
writeLock.lock();
|
||||||
try {
|
try {
|
||||||
boolean blocking = isBlocking();
|
boolean blocking = isBlocking();
|
||||||
int n = 0;
|
int n;
|
||||||
|
boolean completed = false;
|
||||||
try {
|
try {
|
||||||
SocketAddress remote = beginWrite(blocking, false);
|
SocketAddress remote = beginWrite(blocking, false);
|
||||||
if (remote != null) {
|
if (remote != null) {
|
||||||
|
@ -724,6 +763,7 @@ class DatagramChannelImpl
|
||||||
n = IOUtil.write(fd, src, -1, nd);
|
n = IOUtil.write(fd, src, -1, nd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
completed = (n > 0);
|
||||||
} else {
|
} else {
|
||||||
// not connected
|
// not connected
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
@ -744,11 +784,12 @@ class DatagramChannelImpl
|
||||||
n = send(fd, src, isa);
|
n = send(fd, src, isa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
completed = (n >= 0);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
endWrite(blocking, n > 0);
|
endWrite(blocking, completed);
|
||||||
assert IOStatus.check(n);
|
|
||||||
}
|
}
|
||||||
|
assert n >= 0 || n == IOStatus.UNAVAILABLE;
|
||||||
return IOStatus.normalize(n);
|
return IOStatus.normalize(n);
|
||||||
} finally {
|
} finally {
|
||||||
writeLock.unlock();
|
writeLock.unlock();
|
||||||
|
@ -813,11 +854,11 @@ class DatagramChannelImpl
|
||||||
assert (pos <= lim);
|
assert (pos <= lim);
|
||||||
int rem = (pos <= lim ? lim - pos : 0);
|
int rem = (pos <= lim ? lim - pos : 0);
|
||||||
|
|
||||||
boolean preferIPv6 = (family != StandardProtocolFamily.INET);
|
|
||||||
int written;
|
int written;
|
||||||
try {
|
try {
|
||||||
written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
|
int addressLen = targetSocketAddress(target);
|
||||||
rem, target.getAddress(), target.getPort());
|
written = send0(fd, ((DirectBuffer)bb).address() + pos, rem,
|
||||||
|
targetSockAddr.address(), addressLen);
|
||||||
} catch (PortUnreachableException pue) {
|
} catch (PortUnreachableException pue) {
|
||||||
if (isConnected())
|
if (isConnected())
|
||||||
throw pue;
|
throw pue;
|
||||||
|
@ -828,6 +869,23 @@ class DatagramChannelImpl
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the given InetSocketAddress into targetSockAddr, returning the
|
||||||
|
* length of the sockaddr structure (sizeof struct sockaddr or sockaddr6).
|
||||||
|
*/
|
||||||
|
private int targetSocketAddress(InetSocketAddress isa) {
|
||||||
|
assert writeLock.isHeldByCurrentThread();
|
||||||
|
// Nothing to do if target address is already in the buffer. Use
|
||||||
|
// identity rather than equals as Inet6Address.equals ignores scope_id.
|
||||||
|
if (isa == previousTarget)
|
||||||
|
return previousSockAddrLength;
|
||||||
|
previousTarget = null;
|
||||||
|
int len = targetSockAddr.encode(family, isa);
|
||||||
|
previousTarget = isa;
|
||||||
|
previousSockAddrLength = len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(ByteBuffer buf) throws IOException {
|
public int read(ByteBuffer buf) throws IOException {
|
||||||
Objects.requireNonNull(buf);
|
Objects.requireNonNull(buf);
|
||||||
|
@ -1488,8 +1546,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block datagrams from given source if a memory to receive all
|
* Block datagrams from the given source.
|
||||||
* datagrams.
|
|
||||||
*/
|
*/
|
||||||
void block(MembershipKeyImpl key, InetAddress source)
|
void block(MembershipKeyImpl key, InetAddress source)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
@ -1527,7 +1584,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unblock given source.
|
* Unblock the given source.
|
||||||
*/
|
*/
|
||||||
void unblock(MembershipKeyImpl key, InetAddress source) {
|
void unblock(MembershipKeyImpl key, InetAddress source) {
|
||||||
assert key.channel() == this;
|
assert key.channel() == this;
|
||||||
|
@ -1731,10 +1788,9 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an action to release a the given file descriptor and free the
|
* Returns an action to release the given file descriptor and socket addresses.
|
||||||
* given native socket address.
|
|
||||||
*/
|
*/
|
||||||
private static Runnable releaserFor(FileDescriptor fd, NativeSocketAddress sa) {
|
private static Runnable releaserFor(FileDescriptor fd, NativeSocketAddress... sockAddrs) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
nd.close(fd);
|
nd.close(fd);
|
||||||
|
@ -1743,7 +1799,7 @@ class DatagramChannelImpl
|
||||||
} finally {
|
} finally {
|
||||||
// decrement socket count and release memory
|
// decrement socket count and release memory
|
||||||
ResourceManager.afterUdpClose();
|
ResourceManager.afterUdpClose();
|
||||||
sa.free();
|
NativeSocketAddress.freeAll(sockAddrs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1757,8 +1813,8 @@ class DatagramChannelImpl
|
||||||
long senderAddress, boolean connected)
|
long senderAddress, boolean connected)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
private static native int send0(boolean preferIPv6, FileDescriptor fd,
|
private static native int send0(FileDescriptor fd, long address, int len,
|
||||||
long address, int len, InetAddress addr, int port)
|
long targetAddress, int targetAddressLen)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -25,12 +25,18 @@
|
||||||
|
|
||||||
package sun.nio.ch;
|
package sun.nio.ch;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ProtocolFamily;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.channels.UnsupportedAddressTypeException;
|
||||||
|
|
||||||
|
import jdk.internal.access.JavaNetInetAddressAccess;
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
import jdk.internal.misc.Unsafe;
|
import jdk.internal.misc.Unsafe;
|
||||||
import jdk.internal.util.ArraysSupport;
|
import jdk.internal.util.ArraysSupport;
|
||||||
|
|
||||||
|
@ -41,13 +47,16 @@ import jdk.internal.util.ArraysSupport;
|
||||||
* This class is not thread safe.
|
* This class is not thread safe.
|
||||||
*/
|
*/
|
||||||
class NativeSocketAddress {
|
class NativeSocketAddress {
|
||||||
|
private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess();
|
||||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||||
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
|
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
|
||||||
|
|
||||||
private static final int AF_INET = AFINET();
|
private static final int AF_INET = AFINET();
|
||||||
private static final int AF_INET6 = AFINET6();
|
private static final int AF_INET6 = AFINET6();
|
||||||
|
|
||||||
private static final int SIZEOF_SOCKETADDRESS = sizeofSOCKETADDRESS();
|
private static final int SIZEOF_SOCKADDR4 = sizeofSockAddr4();
|
||||||
|
private static final int SIZEOF_SOCKADDR6 = sizeofSockAddr6();
|
||||||
|
private static final int SIZEOF_SOCKETADDRESS = Math.max(SIZEOF_SOCKADDR4, SIZEOF_SOCKADDR6);
|
||||||
private static final int SIZEOF_FAMILY = sizeofFamily();
|
private static final int SIZEOF_FAMILY = sizeofFamily();
|
||||||
private static final int OFFSET_FAMILY = offsetFamily();
|
private static final int OFFSET_FAMILY = offsetFamily();
|
||||||
private static final int OFFSET_SIN4_PORT = offsetSin4Port();
|
private static final int OFFSET_SIN4_PORT = offsetSin4Port();
|
||||||
|
@ -55,77 +64,127 @@ class NativeSocketAddress {
|
||||||
private static final int OFFSET_SIN6_PORT = offsetSin6Port();
|
private static final int OFFSET_SIN6_PORT = offsetSin6Port();
|
||||||
private static final int OFFSET_SIN6_ADDR = offsetSin6Addr();
|
private static final int OFFSET_SIN6_ADDR = offsetSin6Addr();
|
||||||
private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId();
|
private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId();
|
||||||
|
private static final int OFFSET_SIN6_FLOWINFO = offsetSin6FlowInfo();
|
||||||
|
|
||||||
// SOCKETADDRESS
|
// SOCKETADDRESS
|
||||||
private final long address;
|
private final long address;
|
||||||
|
|
||||||
// cached copy of SOCKETADDRESS and the corresponding InetSocketAddress
|
|
||||||
private final long cachedSocketAddress;
|
|
||||||
private InetSocketAddress cachedInetSocketAddress;
|
|
||||||
|
|
||||||
NativeSocketAddress() {
|
|
||||||
// allocate 2 * SOCKETADDRESS
|
|
||||||
int size = SIZEOF_SOCKETADDRESS << 1;
|
|
||||||
long base = UNSAFE.allocateMemory(size);
|
|
||||||
UNSAFE.setMemory(base, size, (byte) 0);
|
|
||||||
|
|
||||||
this.address = base;
|
|
||||||
this.cachedSocketAddress = base + SIZEOF_SOCKETADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
long address() {
|
long address() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free() {
|
NativeSocketAddress() {
|
||||||
UNSAFE.freeMemory(address);
|
long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS);
|
||||||
|
UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0);
|
||||||
|
this.address = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate an array of native socket addresses.
|
||||||
|
*/
|
||||||
|
static NativeSocketAddress[] allocate(int count) {
|
||||||
|
NativeSocketAddress[] array = new NativeSocketAddress[count];
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
try {
|
||||||
|
array[i] = new NativeSocketAddress();
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
freeAll(array);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free all non-null native socket addresses in the given array.
|
||||||
|
*/
|
||||||
|
static void freeAll(NativeSocketAddress[] array) {
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
NativeSocketAddress sa = array[i];
|
||||||
|
if (sa != null) {
|
||||||
|
UNSAFE.freeMemory(sa.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the given InetSocketAddress into this socket address.
|
||||||
|
* @param protocolFamily protocol family
|
||||||
|
* @param isa the InetSocketAddress to encode
|
||||||
|
* @return the size of the socket address (sizeof sockaddr or sockaddr6)
|
||||||
|
* @throws UnsupportedAddressTypeException if the address type is not supported
|
||||||
|
*/
|
||||||
|
int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) {
|
||||||
|
if (protocolFamily == StandardProtocolFamily.INET) {
|
||||||
|
// struct sockaddr
|
||||||
|
InetAddress ia = isa.getAddress();
|
||||||
|
if (!(ia instanceof Inet4Address))
|
||||||
|
throw new UnsupportedAddressTypeException();
|
||||||
|
putFamily(AF_INET);
|
||||||
|
putAddress(AF_INET, ia);
|
||||||
|
putPort(AF_INET, isa.getPort());
|
||||||
|
return SIZEOF_SOCKADDR4;
|
||||||
|
} else {
|
||||||
|
// struct sockaddr6
|
||||||
|
putFamily(AF_INET6);
|
||||||
|
putAddress(AF_INET6, isa.getAddress());
|
||||||
|
putPort(AF_INET6, isa.getPort());
|
||||||
|
UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0);
|
||||||
|
return SIZEOF_SOCKADDR6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an InetSocketAddress to represent the socket address in this buffer.
|
* Return an InetSocketAddress to represent the socket address in this buffer.
|
||||||
* @throws SocketException if the socket address is not AF_INET or AF_INET6
|
* @throws SocketException if the socket address is not AF_INET or AF_INET6
|
||||||
*/
|
*/
|
||||||
InetSocketAddress toInetSocketAddress() throws SocketException {
|
InetSocketAddress decode() throws SocketException {
|
||||||
// return cached InetSocketAddress if the SOCKETADDRESS bytes match
|
|
||||||
if (cachedInetSocketAddress != null && mismatch() < 0) {
|
|
||||||
return cachedInetSocketAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode SOCKETADDRESS to InetSocketAddress
|
|
||||||
int family = family();
|
int family = family();
|
||||||
if (family != AF_INET && family != AF_INET6)
|
if (family != AF_INET && family != AF_INET6)
|
||||||
throw new SocketException("Socket family not recognized");
|
throw new SocketException("Socket family not recognized");
|
||||||
var isa = new InetSocketAddress(address(family), port(family));
|
return new InetSocketAddress(address(family), port(family));
|
||||||
|
|
||||||
// copy SOCKETADDRESS and InetSocketAddress
|
|
||||||
UNSAFE.copyMemory(null, address, null, cachedSocketAddress, SIZEOF_SOCKETADDRESS);
|
|
||||||
this.cachedInetSocketAddress = isa;
|
|
||||||
return isa;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a mismatch between the SOCKETADDRESS structures stored at address
|
* Find a mismatch between this and another socket address
|
||||||
* and cachedSocketAddress.
|
|
||||||
* @return the byte offset of the first mismatch or -1 if no mismatch
|
* @return the byte offset of the first mismatch or -1 if no mismatch
|
||||||
*/
|
*/
|
||||||
private int mismatch() {
|
private int mismatch(NativeSocketAddress other) {
|
||||||
int i = ArraysSupport.vectorizedMismatch(null,
|
int i = ArraysSupport.vectorizedMismatch(null,
|
||||||
address,
|
this.address,
|
||||||
null,
|
null,
|
||||||
cachedSocketAddress,
|
other.address,
|
||||||
SIZEOF_SOCKETADDRESS,
|
SIZEOF_SOCKETADDRESS,
|
||||||
ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
|
ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
return i;
|
return i;
|
||||||
i = SIZEOF_SOCKETADDRESS - ~i;
|
i = SIZEOF_SOCKETADDRESS - ~i;
|
||||||
for (; i < SIZEOF_SOCKETADDRESS; i++) {
|
for (; i < SIZEOF_SOCKETADDRESS; i++) {
|
||||||
if (UNSAFE.getByte(address + i) != UNSAFE.getByte(cachedSocketAddress + i)) {
|
if (UNSAFE.getByte(this.address + i) != UNSAFE.getByte(other.address + i)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other instanceof NativeSocketAddress) {
|
||||||
|
return mismatch((NativeSocketAddress) other) < 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int h = 0;
|
||||||
|
for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) {
|
||||||
|
h = 31 * h + UNSAFE.getByte(address + offset);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
int family = family();
|
int family = family();
|
||||||
|
@ -151,7 +210,20 @@ class NativeSocketAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the value of the sin4_port or sin6_port field. These fields are
|
* Stores the given family in the sa_family field.
|
||||||
|
*/
|
||||||
|
private void putFamily(int family) {
|
||||||
|
if (SIZEOF_FAMILY == 1) {
|
||||||
|
UNSAFE.putByte(address + OFFSET_FAMILY, (byte) family);
|
||||||
|
} else if (SIZEOF_FAMILY == 2) {
|
||||||
|
UNSAFE.putShort(address + OFFSET_FAMILY, (short) family);
|
||||||
|
} else {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the value of the sin_port or sin6_port field. These fields are
|
||||||
* stored in network order.
|
* stored in network order.
|
||||||
*/
|
*/
|
||||||
private int port(int family) {
|
private int port(int family) {
|
||||||
|
@ -166,9 +238,26 @@ class NativeSocketAddress {
|
||||||
return (Byte.toUnsignedInt(b1) << 8) + Byte.toUnsignedInt(b2);
|
return (Byte.toUnsignedInt(b1) << 8) + Byte.toUnsignedInt(b2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given port number in the sin_port or sin6_port field. The
|
||||||
|
* port is stored in network order.
|
||||||
|
*/
|
||||||
|
private void putPort(int family, int port) {
|
||||||
|
byte b1 = (byte) ((port >> 8) & 0xff);
|
||||||
|
byte b2 = (byte) ((port >> 0) & 0xff);
|
||||||
|
if (family == AF_INET) {
|
||||||
|
UNSAFE.putByte(address + OFFSET_SIN4_PORT, b1);
|
||||||
|
UNSAFE.putByte(address + OFFSET_SIN4_PORT + 1, b2);
|
||||||
|
} else {
|
||||||
|
UNSAFE.putByte(address + OFFSET_SIN6_PORT, b1);
|
||||||
|
UNSAFE.putByte(address + OFFSET_SIN6_PORT + 1, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an InetAddress to represent the value of the address in the
|
* Return an InetAddress to represent the value of the address in the
|
||||||
* sin4_addr or sin6_addr fields.
|
* sin4_addr or sin6_addr fields. For IPv6 addresses, the Inet6Address is
|
||||||
|
* created with the sin6_scope_id in the sockaddr_in6 structure.
|
||||||
*/
|
*/
|
||||||
private InetAddress address(int family) {
|
private InetAddress address(int family) {
|
||||||
int len;
|
int len;
|
||||||
|
@ -196,9 +285,52 @@ class NativeSocketAddress {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given InetAddress in the sin_addr or sin6_addr/sin6_scope_id
|
||||||
|
* fields. For IPv6 addresses, the sin6_addr will be popluated with an
|
||||||
|
* IPv4-mapped IPv6 address when the given InetAddress is an IPv4 address.
|
||||||
|
*/
|
||||||
|
private void putAddress(int family, InetAddress ia) {
|
||||||
|
if (family == AF_INET) {
|
||||||
|
// IPv4 address
|
||||||
|
putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia);
|
||||||
|
} else {
|
||||||
|
int scope_id;
|
||||||
|
if (ia instanceof Inet4Address) {
|
||||||
|
// IPv4-mapped IPv6 address
|
||||||
|
UNSAFE.setMemory(address + OFFSET_SIN6_ADDR, 10, (byte) 0);
|
||||||
|
UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 10, (byte) 0xff);
|
||||||
|
UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 11, (byte) 0xff);
|
||||||
|
putAddress(address + OFFSET_SIN6_ADDR + 12, (Inet4Address) ia);
|
||||||
|
scope_id = 0;
|
||||||
|
} else {
|
||||||
|
// IPv6 address
|
||||||
|
var inet6Address = (Inet6Address) ia;
|
||||||
|
putAddress(address + OFFSET_SIN6_ADDR, inet6Address);
|
||||||
|
scope_id = inet6Address.getScopeId();
|
||||||
|
}
|
||||||
|
UNSAFE.putInt(address + OFFSET_SIN6_SCOPE_ID, scope_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void putAddress(long address, Inet4Address ia) {
|
||||||
|
int ipAddress = JNINA.addressValue(ia);
|
||||||
|
// network order
|
||||||
|
UNSAFE.putByte(address + 0, (byte) ((ipAddress >>> 24) & 0xFF));
|
||||||
|
UNSAFE.putByte(address + 1, (byte) ((ipAddress >>> 16) & 0xFF));
|
||||||
|
UNSAFE.putByte(address + 2, (byte) ((ipAddress >>> 8) & 0xFF));
|
||||||
|
UNSAFE.putByte(address + 3, (byte) (ipAddress & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void putAddress(long address, Inet6Address ia) {
|
||||||
|
byte[] bytes = JNINA.addressBytes(ia);
|
||||||
|
UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16);
|
||||||
|
}
|
||||||
|
|
||||||
private static native int AFINET();
|
private static native int AFINET();
|
||||||
private static native int AFINET6();
|
private static native int AFINET6();
|
||||||
private static native int sizeofSOCKETADDRESS();
|
private static native int sizeofSockAddr4();
|
||||||
|
private static native int sizeofSockAddr6();
|
||||||
private static native int sizeofFamily();
|
private static native int sizeofFamily();
|
||||||
private static native int offsetFamily();
|
private static native int offsetFamily();
|
||||||
private static native int offsetSin4Port();
|
private static native int offsetSin4Port();
|
||||||
|
@ -206,6 +338,7 @@ class NativeSocketAddress {
|
||||||
private static native int offsetSin6Port();
|
private static native int offsetSin6Port();
|
||||||
private static native int offsetSin6Addr();
|
private static native int offsetSin6Addr();
|
||||||
private static native int offsetSin6ScopeId();
|
private static native int offsetSin6ScopeId();
|
||||||
|
private static native int offsetSin6FlowInfo();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
IOUtil.load();
|
IOUtil.load();
|
||||||
|
|
|
@ -40,11 +40,17 @@
|
||||||
return AF_INET6;
|
return AF_INET6;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_ch_NativeSocketAddress_sizeofSOCKETADDRESS(JNIEnv* env, jclass clazz)
|
Java_sun_nio_ch_NativeSocketAddress_sizeofSockAddr4(JNIEnv* env, jclass clazz)
|
||||||
{
|
{
|
||||||
return sizeof(SOCKETADDRESS);
|
return sizeof(struct sockaddr_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_NativeSocketAddress_sizeofSockAddr6(JNIEnv* env, jclass clazz)
|
||||||
|
{
|
||||||
|
return sizeof(struct sockaddr_in6);
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_ch_NativeSocketAddress_sizeofFamily(JNIEnv* env, jclass clazz)
|
Java_sun_nio_ch_NativeSocketAddress_sizeofFamily(JNIEnv* env, jclass clazz)
|
||||||
|
@ -88,3 +94,9 @@ Java_sun_nio_ch_NativeSocketAddress_sizeofFamily(JNIEnv* env, jclass clazz)
|
||||||
{
|
{
|
||||||
return offsetof(struct sockaddr_in6, sin6_scope_id);
|
return offsetof(struct sockaddr_in6, sin6_scope_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_NativeSocketAddress_offsetSin6FlowInfo(JNIEnv* env, jclass clazz)
|
||||||
|
{
|
||||||
|
return offsetof(struct sockaddr_in6, sin6_flowinfo);
|
||||||
|
}
|
||||||
|
|
|
@ -129,25 +129,20 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jclass clazz,
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz,
|
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz,
|
||||||
jboolean preferIPv6, jobject fdo, jlong address,
|
jobject fdo, jlong bufAddress, jint len,
|
||||||
jint len, jobject destAddress, jint destPort)
|
jlong targetAddress, jint targetAddressLen)
|
||||||
{
|
{
|
||||||
jint fd = fdval(env, fdo);
|
jint fd = fdval(env, fdo);
|
||||||
void *buf = (void *)jlong_to_ptr(address);
|
void *buf = (void *)jlong_to_ptr(bufAddress);
|
||||||
SOCKETADDRESS sa;
|
SOCKETADDRESS *sa = (SOCKETADDRESS *)jlong_to_ptr(targetAddress);
|
||||||
int sa_len = 0;
|
socklen_t sa_len = (socklen_t) targetAddressLen;
|
||||||
jint n = 0;
|
jint n;
|
||||||
|
|
||||||
if (len > MAX_PACKET_LEN) {
|
if (len > MAX_PACKET_LEN) {
|
||||||
len = MAX_PACKET_LEN;
|
len = MAX_PACKET_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa,
|
n = sendto(fd, buf, len, 0, (struct sockaddr *)sa, sa_len);
|
||||||
&sa_len, preferIPv6) != 0) {
|
|
||||||
return IOS_THROWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = sendto(fd, buf, len, 0, &sa.sa, sa_len);
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
return IOS_UNAVAILABLE;
|
return IOS_UNAVAILABLE;
|
||||||
|
|
|
@ -145,22 +145,16 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jclass clazz,
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz,
|
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jclass clazz,
|
||||||
jboolean preferIPv6, jobject fdo,
|
jobject fdo, jlong bufAddress, jint len,
|
||||||
jlong address, jint len,
|
jlong targetAddress, jint targetAddressLen)
|
||||||
jobject destAddress, jint destPort)
|
|
||||||
{
|
{
|
||||||
jint fd = fdval(env, fdo);
|
jint fd = fdval(env, fdo);
|
||||||
void *buf = (void *)jlong_to_ptr(address);
|
void *buf = (void *)jlong_to_ptr(bufAddress);
|
||||||
SOCKETADDRESS sa;
|
SOCKETADDRESS *sa = (SOCKETADDRESS *)jlong_to_ptr(targetAddress);
|
||||||
int sa_len = 0;
|
int sa_len = targetAddressLen;
|
||||||
jint rv = 0;
|
jint rv;
|
||||||
|
|
||||||
if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa,
|
rv = sendto((SOCKET)fd, buf, len, 0,(struct sockaddr *)sa, sa_len);
|
||||||
&sa_len, preferIPv6) != 0) {
|
|
||||||
return IOS_THROWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = sendto((SOCKET)fd, buf, len, 0, &sa.sa, sa_len);
|
|
||||||
if (rv == SOCKET_ERROR) {
|
if (rv == SOCKET_ERROR) {
|
||||||
int theErr = (jint)WSAGetLastError();
|
int theErr = (jint)WSAGetLastError();
|
||||||
if (theErr == WSAEWOULDBLOCK) {
|
if (theErr == WSAEWOULDBLOCK) {
|
||||||
|
|
|
@ -22,10 +22,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @bug 8234805
|
* @bug 8234805 8235193
|
||||||
* @summary Test that DatagramChannel.receive returns the expected sender address
|
* @summary Test DatagramChannel send/receive and that receive returns the expected
|
||||||
* @run main ManySenders
|
* sender address
|
||||||
* @run main/othervm -Djava.net.preferIPv4Stack=true ManySenders
|
* @run main ManySourcesAndTargets
|
||||||
|
* @run main/othervm -Djava.net.preferIPv4Stack=true ManySourcesAndTargets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -36,38 +37,59 @@ import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ManySenders {
|
public class ManySourcesAndTargets {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
// use addresses on interfaces that have the loopback and local host
|
// use addresses on interfaces that have the loopback and local host
|
||||||
InetAddress lh = InetAddress.getLocalHost();
|
InetAddress lh = InetAddress.getLocalHost();
|
||||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||||
List<InetAddress> addresses = Stream.concat(
|
List<InetAddress> addresses = Stream.of(lh, lb)
|
||||||
NetworkInterface.getByInetAddress(lh).inetAddresses(),
|
.map(ManySourcesAndTargets::networkInterface)
|
||||||
NetworkInterface.getByInetAddress(lb).inetAddresses())
|
.flatMap(Optional::stream)
|
||||||
|
.flatMap(NetworkInterface::inetAddresses)
|
||||||
.filter(ia -> !ia.isAnyLocalAddress())
|
.filter(ia -> !ia.isAnyLocalAddress())
|
||||||
.distinct()
|
.distinct()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// bind DatagramChannel to wildcard address so it can receive from any address
|
// Test DatagramChannel.send
|
||||||
try (DatagramChannel reader = DatagramChannel.open()) {
|
try (DatagramChannel reader = DatagramChannel.open()) {
|
||||||
|
// bind reader to wildcard address so it can receive from any address
|
||||||
reader.bind(new InetSocketAddress(0));
|
reader.bind(new InetSocketAddress(0));
|
||||||
for (InetAddress address : addresses) {
|
for (InetAddress address : addresses) {
|
||||||
System.out.format("%n-- %s --%n", address.getHostAddress());
|
System.out.format("%n-- %s --%n", address.getHostAddress());
|
||||||
|
|
||||||
// send 3 datagrams from the given address to the reader
|
// send 3 datagrams from the given address to the reader
|
||||||
test(3, address, reader);
|
testSend(3, address, reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test DatagramChannel.receive
|
||||||
|
try (DatagramChannel sender = DatagramChannel.open()) {
|
||||||
|
// bind sender to wildcard address so it can send to any address
|
||||||
|
sender.bind(new InetSocketAddress(0));
|
||||||
|
for (InetAddress address : addresses) {
|
||||||
|
System.out.format("%n-- %s --%n", address.getHostAddress());
|
||||||
|
|
||||||
|
// send 3 datagrams to a datagram bound to the given address
|
||||||
|
testReceive(3, sender, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test(int count, InetAddress address, DatagramChannel reader) throws Exception {
|
/**
|
||||||
|
* Creates a sender DatagramChannel bound to the given address and uses it to
|
||||||
|
* sends datagrams to the given reader. The reader receives the datagrams and
|
||||||
|
* checks the source/sender address.
|
||||||
|
*/
|
||||||
|
static void testSend(int count, InetAddress address, DatagramChannel reader) throws Exception {
|
||||||
int remotePort = reader.socket().getLocalPort();
|
int remotePort = reader.socket().getLocalPort();
|
||||||
InetSocketAddress remote = new InetSocketAddress(address, remotePort);
|
InetSocketAddress remote = new InetSocketAddress(address, remotePort);
|
||||||
|
|
||||||
|
@ -103,6 +125,30 @@ public class ManySenders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reader DatagramChannel bound to the given address uses the given
|
||||||
|
* sender to send datagrams to that reader. The reader receives the datagrams.
|
||||||
|
*/
|
||||||
|
static void testReceive(int count, DatagramChannel sender, InetAddress address) throws Exception {
|
||||||
|
SocketAddress local = sender.getLocalAddress();
|
||||||
|
|
||||||
|
try (DatagramChannel reader = DatagramChannel.open()) {
|
||||||
|
// bind to the given address
|
||||||
|
reader.bind(new InetSocketAddress(address, 0));
|
||||||
|
|
||||||
|
SocketAddress remote = reader.getLocalAddress();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
System.out.format("send %s -> %s%n", local, remote);
|
||||||
|
reader.send(ByteBuffer.allocate(32), remote);
|
||||||
|
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(1000);
|
||||||
|
SocketAddress source = reader.receive(bb);
|
||||||
|
System.out.format("received datagram from %s%n", source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] serialize(SocketAddress address) throws Exception {
|
private static byte[] serialize(SocketAddress address) throws Exception {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
@ -116,4 +162,12 @@ public class ManySenders {
|
||||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||||
return (SocketAddress) ois.readObject();
|
return (SocketAddress) ois.readObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Optional<NetworkInterface> networkInterface(InetAddress ia) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(NetworkInterface.getByInetAddress(ia));
|
||||||
|
} catch (SocketException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue