context: /*
    Copyright (C) 2011 Jeroen Frijters
  
    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
    arising from the use of this software.
  
    Permission is granted to anyone to use this software for any purpose,
    including commercial applications, and to alter it and redistribute it
    freely, subject to the following restrictions:
  
    1. The origin of this software must not be misrepresented; you must not
       claim that you wrote the original software. If you use this software
       in a product, an acknowledgment in the product documentation would be
       appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
       misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution.
  
    Jeroen Frijters
    jeroen@frijters.net
    
  */
  
  using System;
  using System.Collections.Generic;
  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, bool isIPv6)
  	{
  #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;
  		if (fd.getSocket().AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
  		{
  			remoteEP = new System.Net.IPEndPoint(System.Net.IPAddress.IPv6Any, 0);
  		}
  		else
  		{
  			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, InetAddress addr, int port)
  	{
  #if FIRST_PASS
  		return 0;
  #else
  		try
  		{
  			return fd.getSocket().SendTo(buf, pos, len, System.Net.Sockets.SocketFlags.None, new System.Net.IPEndPoint(java.net.SocketUtil.getAddressFromInetAddress(addr, preferIPv6), port));
  		}
  		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
  {
  	using System.Net;
  	using System.Net.Sockets;
  
  	abstract class OperationBase<TInput>
  	{
  		private static readonly AsyncCallback callback = CallbackProc;
  		private Socket socket;
  		private sun.nio.ch.Iocp.ResultHandler handler;
  		private int result;
  		private Exception exception;
  
  		internal int Do(Socket socket, TInput input, object handler)
  		{
  			try
  			{
  				this.socket = socket;
  				this.handler = (sun.nio.ch.Iocp.ResultHandler)handler;
  				IAsyncResult ar = Begin(socket, input, callback, this);
  				if (ar.CompletedSynchronously)
  				{
  					if (exception != null)
  					{
  						throw exception;
  					}
  					return result;
  				}
  				else
  				{
  					return sun.nio.ch.IOStatus.UNAVAILABLE;
  				}
  			}
  			catch (SocketException x)
  			{
  				throw java.net.SocketUtil.convertSocketExceptionToIOException(x);
  			}
  			catch (ObjectDisposedException)
  			{
  				throw new java.nio.channels.ClosedChannelException();
  			}
  		}
  
  		private static void CallbackProc(IAsyncResult ar)
  		{
  			OperationBase<TInput> obj = (OperationBase<TInput>)ar.AsyncState;
  			try
  			{
  				int result = obj.End(obj.socket, ar);
  				if (ar.CompletedSynchronously)
  				{
  					obj.result = result;
  				}
  				else
  				{
  					obj.handler.completed(result, false);
  				}
  			}
  			catch (SocketException x)
  			{
  				if (ar.CompletedSynchronously)
  				{
  					obj.exception = x;
  				}
  				else
  				{
  					obj.handler.failed(x.ErrorCode, java.net.SocketUtil.convertSocketExceptionToIOException(x));
  				}
  			}
  			catch (ObjectDisposedException x)
  			{
  				if (ar.CompletedSynchronously)
  				{
  					obj.exception = x;
  				}
  				else
  				{
  					obj.handler.failed(0, new java.nio.channels.ClosedChannelException());
  				}
  			}
  		}
  
  		protected abstract IAsyncResult Begin(Socket socket, TInput input, AsyncCallback callback, object state);
  		protected abstract int End(Socket socket, IAsyncResult ar);
  	}
  }
  #endif
  
  static class Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl
  {
  #if !FIRST_PASS
  	sealed class Accept : IKVM.Internal.AsyncSocket.OperationBase<System.Net.Sockets.Socket>
  	{
  		protected override IAsyncResult Begin(System.Net.Sockets.Socket listenSocket, System.Net.Sockets.Socket acceptSocket, AsyncCallback callback, object state)
  		{
  			return listenSocket.BeginAccept(acceptSocket, 0, callback, state);
  		}
  
  		protected override int End(System.Net.Sockets.Socket socket, IAsyncResult ar)
  		{
  			socket.EndAccept(ar);
  			return 0;
  		}
  	}
  #endif
  
  	public static void initIDs()
  	{
  	}
  
  	public static int accept0(FileDescriptor listenSocket, FileDescriptor acceptSocket, object handler)
  	{
  #if FIRST_PASS
  		return 0;
  #else
  		return new Accept().Do(listenSocket.getSocket(), acceptSocket.getSocket(), handler);
  #endif
  	}
  
  	public static void updateAcceptContext(FileDescriptor listenSocket, FileDescriptor acceptSocket)
  	{
  		// already handled by .NET Framework
  	}
  
  	public static void closesocket0(long socket)
  	{
  		// unused
  	}
  }
  
  static class Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl
  {
  #if !FIRST_PASS
  	sealed class Connect : IKVM.Internal.AsyncSocket.OperationBase<System.Net.IPEndPoint>
  	{
  		protected override IAsyncResult Begin(System.Net.Sockets.Socket socket, System.Net.IPEndPoint remoteEP, AsyncCallback callback, object state)
  		{
  			return socket.BeginConnect(remoteEP, callback, state);
  		}
  
  		protected override int End(System.Net.Sockets.Socket socket, IAsyncResult ar)
  		{
  			socket.EndConnect(ar);
  			return 0;
  		}
  	}
  
  	private static List<ArraySegment<byte>> ByteBuffersToList(ByteBuffer[] bufs)
  	{
  		List<ArraySegment<byte>> list = new List<ArraySegment<byte>>(bufs.Length);
  		foreach (ByteBuffer bb in bufs)
  		{
  			list.Add(new ArraySegment<byte>(bb.array(), bb.arrayOffset() + bb.position(), bb.remaining()));
  		}
  		return list;
  	}
  
  	sealed class Receive : IKVM.Internal.AsyncSocket.OperationBase<ByteBuffer[]>
  	{
  		protected override IAsyncResult Begin(System.Net.Sockets.Socket socket, ByteBuffer[] bufs, AsyncCallback callback, object state)
  		{
  			return socket.BeginReceive(ByteBuffersToList(bufs), System.Net.Sockets.SocketFlags.None, callback, state);
  		}
  
  		protected override int End(System.Net.Sockets.Socket socket, IAsyncResult ar)
  		{
  			return socket.EndReceive(ar);
  		}
  	}
  
  	sealed class Send : IKVM.Internal.AsyncSocket.OperationBase<ByteBuffer[]>
  	{
  		protected override IAsyncResult Begin(System.Net.Sockets.Socket socket, ByteBuffer[] bufs, AsyncCallback callback, object state)
  		{
  			return socket.BeginSend(ByteBuffersToList(bufs), System.Net.Sockets.SocketFlags.None, callback, state);
  		}
  
  		protected override int End(System.Net.Sockets.Socket socket, IAsyncResult ar)
  		{
  			return socket.EndSend(ar);
  		}
  	}
  #endif
  
  	public static void initIDs()
  	{
  	}
  
  	public static int connect0(FileDescriptor fd, bool preferIPv6, InetAddress remote, int remotePort, object handler)
  	{
  #if FIRST_PASS
  		return 0;
  #else
  		return new Connect().Do(fd.getSocket(), new System.Net.IPEndPoint(java.net.SocketUtil.getAddressFromInetAddress(remote, preferIPv6), remotePort), handler);
  #endif
  	}
  
  	public static void updateConnectContext(FileDescriptor fd)
  	{
  		// already handled by .NET Framework
  	}
  
  	public static int read0(FileDescriptor fd, ByteBuffer[] bufs, object handler)
  	{
  #if FIRST_PASS
  		return 0;
  #else
  		return new Receive().Do(fd.getSocket(), bufs, handler);
  #endif
  	}
  
  	public static int write0(FileDescriptor fd, ByteBuffer[] bufs, object handler)
  	{
  #if FIRST_PASS
  		return 0;
  #else
  		return new Send().Do(fd.getSocket(), bufs, handler);
  #endif
  	}
  
  	public static void shutdown0(long socket, int how)
  	{
  		// unused
  	}
  
  	public static void closesocket0(long socket)
  	{
  		// unused
  	}
  }
  
  namespace IKVM.NativeCode.sun.nio.ch
  {
  	static class SocketDispatcher
  	{
  		public static long read(object nd, FileDescriptor fd, ByteBuffer[] bufs, int offset, int length)
  		{
  #if FIRST_PASS
  			return 0;
  #else
  			ByteBuffer[] altBufs = null;
  			List<ArraySegment<byte>> list = new List<ArraySegment<byte>>(length);
  			for (int i = 0; i < length; i++)
  			{
  				ByteBuffer bb = bufs[i + offset];
  				if (!bb.hasArray())
  				{
  
gt: 					if (altBufs == null)