зеркало из https://github.com/mono/ikvm-fork.git
Reduced the number of DatagramChannelImpl differences.
This commit is contained in:
Родитель
eaaccdd4e9
Коммит
88989f0239
|
@ -43,12 +43,6 @@ class DatagramChannelImpl
|
|||
extends DatagramChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
// Windows 2000 introduced a "feature" that causes it to return WSAECONNRESET from receive,
|
||||
// if a previous send resulted in an ICMP port unreachable. We disable this feature by using
|
||||
// this ioctl.
|
||||
private static final int IOC_IN = (int)0x80000000;
|
||||
private static final int IOC_VENDOR = 0x18000000;
|
||||
private static final int SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
||||
|
||||
// Used to make native read and write calls
|
||||
private static NativeDispatcher nd = new SocketDispatcher();
|
||||
|
@ -115,15 +109,6 @@ class DatagramChannelImpl
|
|||
this.fd = Net.socket(family, false);
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_UNCONNECTED;
|
||||
try
|
||||
{
|
||||
if (false) throw new cli.System.Net.Sockets.SocketException();
|
||||
fd.getSocket().IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
|
||||
}
|
||||
catch (cli.System.Net.Sockets.SocketException x)
|
||||
{
|
||||
throw SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ResourceManager.afterUdpClose();
|
||||
throw ioe;
|
||||
|
@ -151,15 +136,6 @@ class DatagramChannelImpl
|
|||
this.fd = Net.socket(family, false);
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_UNCONNECTED;
|
||||
try
|
||||
{
|
||||
if (false) throw new cli.System.Net.Sockets.SocketException();
|
||||
fd.getSocket().IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
|
||||
}
|
||||
catch (cli.System.Net.Sockets.SocketException x)
|
||||
{
|
||||
throw SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
|
||||
|
@ -337,7 +313,7 @@ class DatagramChannelImpl
|
|||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
private SocketAddress sender; // Set by receive0 (## ugh)
|
||||
SocketAddress sender; // Set by receive0 (## ugh)
|
||||
|
||||
public SocketAddress receive(ByteBuffer dst) throws IOException {
|
||||
if (dst.isReadOnly())
|
||||
|
@ -359,7 +335,7 @@ class DatagramChannelImpl
|
|||
readerThread = NativeThread.current();
|
||||
if (isConnected() || (security == null)) {
|
||||
do {
|
||||
n = receive0(dst);
|
||||
n = receive(fd, dst);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (n == IOStatus.UNAVAILABLE)
|
||||
return null;
|
||||
|
@ -367,7 +343,7 @@ class DatagramChannelImpl
|
|||
bb = ByteBuffer.allocate(dst.remaining());
|
||||
for (;;) {
|
||||
do {
|
||||
n = receive0(bb);
|
||||
n = receive(fd, bb);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (n == IOStatus.UNAVAILABLE)
|
||||
return null;
|
||||
|
@ -396,6 +372,42 @@ class DatagramChannelImpl
|
|||
}
|
||||
}
|
||||
|
||||
private int receive(FileDescriptor fd, ByteBuffer dst)
|
||||
throws IOException
|
||||
{
|
||||
int pos = dst.position();
|
||||
int lim = dst.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
if (dst.hasArray() && rem > 0)
|
||||
return receiveIntoManagedBuffer(fd, dst, rem, pos);
|
||||
|
||||
// Substitute a managed buffer. If the supplied buffer is empty
|
||||
// we must instead use a nonempty buffer, otherwise the call
|
||||
// will not block waiting for a datagram on some platforms.
|
||||
int newSize = Math.max(rem, 1);
|
||||
ByteBuffer bb = ByteBuffer.allocate(newSize);
|
||||
try {
|
||||
int n = receiveIntoManagedBuffer(fd, bb, newSize, 0);
|
||||
bb.flip();
|
||||
if (n > 0 && rem > 0)
|
||||
dst.put(bb);
|
||||
return n;
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
private int receiveIntoManagedBuffer(FileDescriptor fd, ByteBuffer bb,
|
||||
int rem, int pos)
|
||||
throws IOException
|
||||
{
|
||||
int n = receive0(fd, bb.array(), bb.arrayOffset() + pos, rem,
|
||||
isConnected());
|
||||
if (n > 0)
|
||||
bb.position(pos + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
public int send(ByteBuffer src, SocketAddress target)
|
||||
throws IOException
|
||||
{
|
||||
|
@ -437,7 +449,7 @@ class DatagramChannelImpl
|
|||
return 0;
|
||||
writerThread = NativeThread.current();
|
||||
do {
|
||||
n = sendImpl(src, isa);
|
||||
n = send(fd, src, target);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
|
||||
synchronized (stateLock) {
|
||||
|
@ -454,6 +466,52 @@ class DatagramChannelImpl
|
|||
}
|
||||
}
|
||||
|
||||
private int send(FileDescriptor fd, ByteBuffer src, SocketAddress target)
|
||||
throws IOException
|
||||
{
|
||||
if (src.hasArray())
|
||||
return sendFromManagedBuffer(fd, src, target);
|
||||
|
||||
// Substitute a managed buffer
|
||||
int pos = src.position();
|
||||
int lim = src.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(rem);
|
||||
try {
|
||||
bb.put(src);
|
||||
bb.flip();
|
||||
// Do not update src until we see how many bytes were written
|
||||
src.position(pos);
|
||||
|
||||
int n = sendFromManagedBuffer(fd, bb, target);
|
||||
if (n > 0) {
|
||||
// now update src
|
||||
src.position(pos + n);
|
||||
}
|
||||
return n;
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
private int sendFromManagedBuffer(FileDescriptor fd, ByteBuffer bb,
|
||||
SocketAddress target)
|
||||
throws IOException
|
||||
{
|
||||
int pos = bb.position();
|
||||
int lim = bb.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
boolean preferIPv6 = (family != StandardProtocolFamily.INET);
|
||||
int written = send0(preferIPv6, fd, bb.array(), bb.arrayOffset() + pos,
|
||||
rem, target);
|
||||
if (written > 0)
|
||||
bb.position(pos + written);
|
||||
return written;
|
||||
}
|
||||
|
||||
public int read(ByteBuffer buf) throws IOException {
|
||||
if (buf == null)
|
||||
throw new NullPointerException();
|
||||
|
@ -642,21 +700,12 @@ class DatagramChannelImpl
|
|||
if (sm != null)
|
||||
sm.checkConnect(isa.getAddress().getHostAddress(),
|
||||
isa.getPort());
|
||||
try
|
||||
{
|
||||
if (false) throw new cli.System.Net.Sockets.SocketException();
|
||||
if (false) throw new cli.System.ObjectDisposedException("");
|
||||
fd.getSocket().Connect(SocketUtil.getAddressFromInetAddress(isa.getAddress()), isa.getPort());
|
||||
fd.getSocket().IOControl(SIO_UDP_CONNRESET, new byte[] { 1 }, null);
|
||||
}
|
||||
catch (cli.System.Net.Sockets.SocketException x)
|
||||
{
|
||||
throw new SocketException(x.getMessage());
|
||||
}
|
||||
catch (cli.System.ObjectDisposedException x1)
|
||||
{
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
int n = Net.connect(family,
|
||||
fd,
|
||||
isa.getAddress(),
|
||||
isa.getPort());
|
||||
if (n <= 0)
|
||||
throw new Error(); // Can't happen
|
||||
|
||||
// Connection succeeded; disallow further invocation
|
||||
state = ST_CONNECTED;
|
||||
|
@ -1010,131 +1059,22 @@ class DatagramChannelImpl
|
|||
|
||||
// -- Native methods --
|
||||
|
||||
private static void disconnect0(FileDescriptor fd) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (false) throw new cli.System.Net.Sockets.SocketException();
|
||||
if (false) throw new cli.System.ObjectDisposedException("");
|
||||
fd.getSocket().Connect(new cli.System.Net.IPEndPoint(cli.System.Net.IPAddress.Any, 0));
|
||||
fd.getSocket().IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
|
||||
}
|
||||
catch (cli.System.Net.Sockets.SocketException x)
|
||||
{
|
||||
throw SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
catch (cli.System.ObjectDisposedException x1)
|
||||
{
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
private static native void initIDs();
|
||||
|
||||
private static native void disconnect0(FileDescriptor fd)
|
||||
throws IOException;
|
||||
|
||||
private native int receive0(FileDescriptor fd, byte[] buf, int pos, int len,
|
||||
boolean connected)
|
||||
throws IOException;
|
||||
|
||||
private native int send0(boolean preferIPv6, FileDescriptor fd, byte[] buf, int pos, int len,
|
||||
SocketAddress sa)
|
||||
throws IOException;
|
||||
|
||||
static {
|
||||
Util.load();
|
||||
initIDs();
|
||||
}
|
||||
|
||||
private int receive0(ByteBuffer bb) throws IOException
|
||||
{
|
||||
byte[] buf = new byte[bb.remaining()];
|
||||
cli.System.Net.EndPoint[] remoteEP = new cli.System.Net.EndPoint[]
|
||||
{
|
||||
new cli.System.Net.IPEndPoint(0, 0)
|
||||
};
|
||||
InetSocketAddress addr;
|
||||
int length;
|
||||
do
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
try
|
||||
{
|
||||
if (false) throw new cli.System.Net.Sockets.SocketException();
|
||||
if (false) throw new cli.System.ObjectDisposedException("");
|
||||
length = fd.getSocket().ReceiveFrom(buf, 0, buf.length, cli.System.Net.Sockets.SocketFlags.wrap(cli.System.Net.Sockets.SocketFlags.None), remoteEP);
|
||||
break;
|
||||
}
|
||||
catch (cli.System.Net.Sockets.SocketException x)
|
||||
{
|
||||
if (x.get_ErrorCode() == SocketUtil.WSAECONNRESET)
|
||||
{
|
||||
// A previous send failed (i.e. the remote host responded with a ICMP that the port is closed) and
|
||||
// the winsock stack helpfully lets us know this, but we only care about this when we're connected,
|
||||
// otherwise we'll simply retry the receive (note that we use SIO_UDP_CONNRESET to prevent these
|
||||
// WSAECONNRESET exceptions, but when switching from connected to disconnected, some can slip through).
|
||||
if (isConnected())
|
||||
{
|
||||
throw new PortUnreachableException();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (x.get_ErrorCode() == SocketUtil.WSAEMSGSIZE)
|
||||
{
|
||||
// The buffer size was too small for the packet, ReceiveFrom receives the part of the packet
|
||||
// that fits in the buffer and then throws an exception, so we have to ignore the exception in this case.
|
||||
length = buf.length;
|
||||
break;
|
||||
}
|
||||
if (x.get_ErrorCode() == SocketUtil.WSAEWOULDBLOCK)
|
||||
{
|
||||
return IOStatus.UNAVAILABLE;
|
||||
}
|
||||
throw SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
catch (cli.System.ObjectDisposedException x1)
|
||||
{
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
}
|
||||
cli.System.Net.IPEndPoint ep = (cli.System.Net.IPEndPoint)remoteEP[0];
|
||||
addr = new InetSocketAddress(SocketUtil.getInetAddressFromIPEndPoint(ep), ep.get_Port());
|
||||
} while (remoteAddress != null && !addr.equals(remoteAddress));
|
||||
sender = addr;
|
||||
bb.put(buf, 0, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
private int sendImpl(ByteBuffer bb, InetSocketAddress addr) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (false) throw new cli.System.Net.Sockets.SocketException();
|
||||
if (false) throw new cli.System.ObjectDisposedException("");
|
||||
int position = bb.position();
|
||||
byte[] buf;
|
||||
int offset;
|
||||
int length;
|
||||
if (bb.hasArray())
|
||||
{
|
||||
buf = bb.array();
|
||||
offset = bb.arrayOffset() + bb.position();
|
||||
length = bb.remaining();
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = new byte[bb.remaining()];
|
||||
offset = 0;
|
||||
length = buf.length;
|
||||
bb.get(buf);
|
||||
bb.position(position);
|
||||
}
|
||||
int sent = fd.getSocket().SendTo(buf, offset, length, cli.System.Net.Sockets.SocketFlags.wrap(cli.System.Net.Sockets.SocketFlags.None), new cli.System.Net.IPEndPoint(SocketUtil.getAddressFromInetAddress(addr.getAddress()), addr.getPort()));
|
||||
if (bb.hasArray())
|
||||
{
|
||||
bb.position(position + sent);
|
||||
}
|
||||
else
|
||||
{
|
||||
bb.put(buf, 0, sent);
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
catch (cli.System.Net.Sockets.SocketException x)
|
||||
{
|
||||
if (x.get_ErrorCode() == SocketUtil.WSAEWOULDBLOCK)
|
||||
{
|
||||
return IOStatus.UNAVAILABLE;
|
||||
}
|
||||
throw SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
catch (cli.System.ObjectDisposedException x1)
|
||||
{
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,116 @@ using FileDescriptor = java.io.FileDescriptor;
|
|||
using InetAddress = java.net.InetAddress;
|
||||
using ByteBuffer = java.nio.ByteBuffer;
|
||||
|
||||
static class Java_sun_nio_ch_DatagramChannelImpl
|
||||
{
|
||||
public static void initIDs()
|
||||
{
|
||||
}
|
||||
|
||||
public static void disconnect0(FileDescriptor fd)
|
||||
{
|
||||
#if !FIRST_PASS
|
||||
try
|
||||
{
|
||||
fd.getSocket().Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0));
|
||||
IKVM.NativeCode.sun.nio.ch.Net.setConnectionReset(fd.getSocket(), false);
|
||||
}
|
||||
catch (System.Net.Sockets.SocketException x)
|
||||
{
|
||||
throw java.net.SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
throw new java.net.SocketException("Socket is closed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int receive0(object obj, FileDescriptor fd, byte[] buf, int pos, int len, bool connected)
|
||||
{
|
||||
#if FIRST_PASS
|
||||
return 0;
|
||||
#else
|
||||
sun.nio.ch.DatagramChannelImpl impl = (sun.nio.ch.DatagramChannelImpl)obj;
|
||||
java.net.SocketAddress remoteAddress = impl.remoteAddress();
|
||||
System.Net.EndPoint remoteEP = new System.Net.IPEndPoint(0, 0);
|
||||
java.net.InetSocketAddress addr;
|
||||
int length;
|
||||
do
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
try
|
||||
{
|
||||
length = fd.getSocket().ReceiveFrom(buf, pos, len, System.Net.Sockets.SocketFlags.None, ref remoteEP);
|
||||
break;
|
||||
}
|
||||
catch (System.Net.Sockets.SocketException x)
|
||||
{
|
||||
if (x.ErrorCode == java.net.SocketUtil.WSAECONNRESET)
|
||||
{
|
||||
// A previous send failed (i.e. the remote host responded with a ICMP that the port is closed) and
|
||||
// the winsock stack helpfully lets us know this, but we only care about this when we're connected,
|
||||
// otherwise we'll simply retry the receive (note that we use SIO_UDP_CONNRESET to prevent these
|
||||
// WSAECONNRESET exceptions, but when switching from connected to disconnected, some can slip through).
|
||||
if (connected)
|
||||
{
|
||||
throw new java.net.PortUnreachableException();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (x.ErrorCode == java.net.SocketUtil.WSAEMSGSIZE)
|
||||
{
|
||||
// The buffer size was too small for the packet, ReceiveFrom receives the part of the packet
|
||||
// that fits in the buffer and then throws an exception, so we have to ignore the exception in this case.
|
||||
length = len;
|
||||
break;
|
||||
}
|
||||
if (x.ErrorCode == java.net.SocketUtil.WSAEWOULDBLOCK)
|
||||
{
|
||||
return sun.nio.ch.IOStatus.UNAVAILABLE;
|
||||
}
|
||||
throw java.net.SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
throw new java.net.SocketException("Socket is closed");
|
||||
}
|
||||
}
|
||||
System.Net.IPEndPoint ep = (System.Net.IPEndPoint)remoteEP;
|
||||
addr = new java.net.InetSocketAddress(java.net.SocketUtil.getInetAddressFromIPEndPoint(ep), ep.Port);
|
||||
} while (remoteAddress != null && !addr.equals(remoteAddress));
|
||||
impl.sender = addr;
|
||||
return length;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int send0(object obj, bool preferIPv6, FileDescriptor fd, byte[] buf, int pos, int len, object sa)
|
||||
{
|
||||
#if FIRST_PASS
|
||||
return 0;
|
||||
#else
|
||||
java.net.InetSocketAddress addr = (java.net.InetSocketAddress)sa;
|
||||
try
|
||||
{
|
||||
return fd.getSocket().SendTo(buf, pos, len, System.Net.Sockets.SocketFlags.None, new System.Net.IPEndPoint(java.net.SocketUtil.getAddressFromInetAddress(addr.getAddress()), addr.getPort()));
|
||||
}
|
||||
catch (System.Net.Sockets.SocketException x)
|
||||
{
|
||||
if (x.ErrorCode == java.net.SocketUtil.WSAEWOULDBLOCK)
|
||||
{
|
||||
return sun.nio.ch.IOStatus.UNAVAILABLE;
|
||||
}
|
||||
throw java.net.SocketUtil.convertSocketExceptionToIOException(x);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
throw new java.net.SocketException("Socket is closed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if !FIRST_PASS
|
||||
namespace IKVM.Internal.AsyncSocket
|
||||
{
|
||||
|
@ -620,7 +730,6 @@ namespace IKVM.NativeCode.sun.nio.ch
|
|||
#else
|
||||
try
|
||||
{
|
||||
FileDescriptor fd = new FileDescriptor();
|
||||
System.Net.Sockets.AddressFamily addressFamily = preferIPv6
|
||||
? System.Net.Sockets.AddressFamily.InterNetworkV6
|
||||
: System.Net.Sockets.AddressFamily.InterNetwork;
|
||||
|
@ -630,7 +739,19 @@ namespace IKVM.NativeCode.sun.nio.ch
|
|||
System.Net.Sockets.ProtocolType protocolType = stream
|
||||
? System.Net.Sockets.ProtocolType.Tcp
|
||||
: System.Net.Sockets.ProtocolType.Udp;
|
||||
fd.setSocket(new System.Net.Sockets.Socket(addressFamily, socketType, protocolType));
|
||||
System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
|
||||
if (preferIPv6)
|
||||
{
|
||||
// enable IPv4 over IPv6 sockets (note that we don't have to check for >= Vista here, because nio sockets only support IPv6 on >= Vista)
|
||||
const System.Net.Sockets.SocketOptionName IPV6_V6ONLY = (System.Net.Sockets.SocketOptionName)27;
|
||||
socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.IPv6, IPV6_V6ONLY, 0);
|
||||
}
|
||||
if (!stream)
|
||||
{
|
||||
setConnectionReset(socket, false);
|
||||
}
|
||||
FileDescriptor fd = new FileDescriptor();
|
||||
fd.setSocket(socket);
|
||||
return fd;
|
||||
}
|
||||
catch (System.Net.Sockets.SocketException x)
|
||||
|
@ -676,6 +797,18 @@ namespace IKVM.NativeCode.sun.nio.ch
|
|||
#endif
|
||||
}
|
||||
|
||||
internal static void setConnectionReset(System.Net.Sockets.Socket socket, bool enable)
|
||||
{
|
||||
// Windows 2000 introduced a "feature" that causes it to return WSAECONNRESET from receive,
|
||||
// if a previous send resulted in an ICMP port unreachable. For unconnected datagram sockets,
|
||||
// we disable this feature by using this ioctl.
|
||||
const int IOC_IN = unchecked((int)0x80000000);
|
||||
const int IOC_VENDOR = 0x18000000;
|
||||
const int SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
||||
|
||||
socket.IOControl(SIO_UDP_CONNRESET, new byte[] { enable ? (byte)1 : (byte)0 }, null);
|
||||
}
|
||||
|
||||
public static int connect0(bool preferIPv6, FileDescriptor fd, InetAddress remote, int remotePort)
|
||||
{
|
||||
#if FIRST_PASS
|
||||
|
@ -684,9 +817,14 @@ namespace IKVM.NativeCode.sun.nio.ch
|
|||
try
|
||||
{
|
||||
System.Net.IPEndPoint ep = new System.Net.IPEndPoint(global::java.net.SocketUtil.getAddressFromInetAddress(remote), remotePort);
|
||||
if (fd.isSocketBlocking())
|
||||
bool datagram = fd.getSocket().SocketType == System.Net.Sockets.SocketType.Dgram;
|
||||
if (datagram || fd.isSocketBlocking())
|
||||
{
|
||||
fd.getSocket().Connect(ep);
|
||||
if (datagram)
|
||||
{
|
||||
setConnectionReset(fd.getSocket(), true);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
|
Загрузка…
Ссылка в новой задаче