NPServer now in 2 flavours, mono-compatible (2 sockets for IPv4 and IPv6) and mono-incompatible (Win32-proprietary fallback socket)

feature-npv2
Icedream 2014-05-22 17:26:58 +02:00
parent 3c2ed60f5e
commit cce59f8124
1 changed files with 82 additions and 12 deletions

View File

@ -21,7 +21,12 @@ namespace NPSharp.NP
private readonly List<NPServerClient> _clients; private readonly List<NPServerClient> _clients;
private readonly ILog _log; private readonly ILog _log;
private readonly ushort _port; private readonly ushort _port;
#if MONO_INCOMPATIBLE
private readonly Socket _socket; private readonly Socket _socket;
#else
private readonly Socket _socket4;
private readonly Socket _socket6;
#endif
/// <summary> /// <summary>
/// Constructs a new NP server. /// Constructs a new NP server.
@ -31,13 +36,19 @@ namespace NPSharp.NP
_log = LogManager.GetLogger("NPServer"); _log = LogManager.GetLogger("NPServer");
_clients = new List<NPServerClient>(); _clients = new List<NPServerClient>();
#if MONO_INCOMPATIBLE
// Mono can't compile this since the constructor is proprietary to Windows' .NET library // Mono can't compile this since the constructor is proprietary to Windows' .NET library
//_socket = new Socket(SocketType.Stream, ProtocolType.IP); _socket = new Socket(SocketType.Stream, ProtocolType.IP);
// Instead we will specifically disable the socket's property to ignore IPv4
_socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
_socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
// Mono can't compile this either since the IPv6Only socket option is completely missing.
//_socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
//_socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
#else
// So as much as this hurts me, I have to go with TWO sockets.
// Guys, this is why I hate network programming sometimes. SOMETIMES.
_socket4 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
#endif
_port = port; _port = port;
} }
@ -74,7 +85,13 @@ namespace NPSharp.NP
/// </summary> /// </summary>
public void Start() public void Start()
{ {
if (_socket.IsBound) if (
#if MONO_INCOMPATIBLE
_socket.IsBound
#else
_socket4.IsBound || _socket6.IsBound
#endif
)
throw new InvalidOperationException("This server is already running"); throw new InvalidOperationException("This server is already running");
try try
@ -89,17 +106,36 @@ namespace NPSharp.NP
throw new SocketException(10013 /* Permission denied */); throw new SocketException(10013 /* Permission denied */);
} }
#if MONO_INCOMPATIBLE
_socket.Bind(new IPEndPoint(IPAddress.IPv6Any, _port)); _socket.Bind(new IPEndPoint(IPAddress.IPv6Any, _port));
_socket.Listen(4); _socket.Listen(100);
#else
_socket4.Bind(new IPEndPoint(IPAddress.Any, _port));
_socket4.Listen(100);
_socket6.Bind(new IPEndPoint(IPAddress.IPv6Any, _port));
_socket6.Listen(100);
#endif
Task.Factory.StartNew(() => Task.Factory.StartNew(() =>
{ {
_log.Debug("Listener loop started"); _log.Debug("Listener loop started");
#if MONO_INCOMPATIBLE
var socket = _socket;
#else
var socket = _socket4;
#endif
var allDone = new ManualResetEvent(false); var allDone = new ManualResetEvent(false);
while (_socket != null && _socket.IsBound) while (
#if MONO_INCOMPATIBLE
_socket != null && _socket.IsBound
#else
_socket4 != null && _socket4.IsBound
#endif
)
{ {
allDone.Reset(); allDone.Reset();
_socket.BeginAccept(ar => socket.BeginAccept(ar =>
{ {
_log.Debug("Async accept client start"); _log.Debug("Async accept client start");
allDone.Set(); allDone.Set();
@ -112,12 +148,41 @@ namespace NPSharp.NP
_log.Debug("Async accept client end"); _log.Debug("Async accept client end");
_handleClient(npsc); _handleClient(npsc);
}, _socket); }, socket);
allDone.WaitOne(); allDone.WaitOne();
} }
_log.Debug("Listener loop shut down"); _log.Debug("Listener loop shut down");
}); });
#if !MONO_INCOMPATIBLE
Task.Factory.StartNew(() =>
{
_log.Debug("Listener loop (IPv6) started");
var allDone = new ManualResetEvent(false);
while (_socket6 != null && _socket6.IsBound)
{
allDone.Reset();
_socket6.BeginAccept(ar =>
{
_log.Debug("Async accept (IPv6) client start");
allDone.Set();
var serverSocket = (Socket)ar.AsyncState;
var clientSocket = serverSocket.EndAccept(ar);
var npsc = new NPServerClient(this, new RPCServerStream(clientSocket));
_log.Debug("Async accept (IPv6) client end");
_handleClient(npsc);
}, _socket6);
allDone.WaitOne();
}
_log.Debug("Listener loop (IPv6) shut down");
});
} }
#endif
/// <summary> /// <summary>
/// Shuts down all connections and stops the NP server. /// Shuts down all connections and stops the NP server.
@ -125,7 +190,12 @@ namespace NPSharp.NP
public void Stop() public void Stop()
{ {
// TODO: Wait for sockets to COMPLETELY shut down // TODO: Wait for sockets to COMPLETELY shut down
#if MONO_INCOMPATIBLE
_socket.Shutdown(SocketShutdown.Both); _socket.Shutdown(SocketShutdown.Both);
#else
_socket4.Shutdown(SocketShutdown.Both);
_socket6.Shutdown(SocketShutdown.Both);
#endif
} }
internal void _handleClient(NPServerClient client) internal void _handleClient(NPServerClient client)