Adding libuv p/invokes
This commit is contained in:
parent
3404100f08
commit
1b412bc99f
|
|
@ -0,0 +1,196 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public class Libuv
|
||||||
|
{
|
||||||
|
private IntPtr _module = IntPtr.Zero;
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern IntPtr LoadLibrary(string dllToLoad);
|
||||||
|
|
||||||
|
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern bool FreeLibrary(IntPtr hModule);
|
||||||
|
|
||||||
|
|
||||||
|
public void Load(string dllToLoad)
|
||||||
|
{
|
||||||
|
var module = LoadLibrary(dllToLoad);
|
||||||
|
foreach (var field in GetType().GetTypeInfo().DeclaredFields)
|
||||||
|
{
|
||||||
|
var procAddress = GetProcAddress(module, field.Name.TrimStart('_'));
|
||||||
|
if (procAddress == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var value = Marshal.GetDelegateForFunctionPointer(procAddress, field.FieldType);
|
||||||
|
field.SetValue(this, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Check(int statusCode)
|
||||||
|
{
|
||||||
|
if (statusCode < 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Status code " + statusCode);
|
||||||
|
}
|
||||||
|
return statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_loop_init(UvLoopHandle a0);
|
||||||
|
uv_loop_init _uv_loop_init;
|
||||||
|
public void loop_init(UvLoopHandle handle)
|
||||||
|
{
|
||||||
|
Check(_uv_loop_init(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_loop_close(IntPtr a0);
|
||||||
|
uv_loop_close _uv_loop_close;
|
||||||
|
public void loop_close(UvLoopHandle handle)
|
||||||
|
{
|
||||||
|
Check(_uv_loop_close(handle.DangerousGetHandle()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_run(UvLoopHandle handle, int mode);
|
||||||
|
uv_run _uv_run;
|
||||||
|
public int run(UvLoopHandle handle, int mode)
|
||||||
|
{
|
||||||
|
return Check(_uv_run(handle, mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void uv_stop(UvLoopHandle handle);
|
||||||
|
uv_stop _uv_stop;
|
||||||
|
public void stop(UvLoopHandle handle)
|
||||||
|
{
|
||||||
|
_uv_stop(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void uv_close_cb(IntPtr handle);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void uv_close(IntPtr handle, uv_close_cb close_cb);
|
||||||
|
uv_close _uv_close;
|
||||||
|
public void close(UvHandle handle, uv_close_cb close_cb)
|
||||||
|
{
|
||||||
|
_uv_close(handle.DangerousGetHandle(), close_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void uv_async_cb(IntPtr handle);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb);
|
||||||
|
uv_async_init _uv_async_init;
|
||||||
|
public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb)
|
||||||
|
{
|
||||||
|
Check(_uv_async_init(loop, handle, cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_async_send(UvAsyncHandle handle);
|
||||||
|
uv_async_send _uv_async_send;
|
||||||
|
public void async_send(UvAsyncHandle handle)
|
||||||
|
{
|
||||||
|
Check(_uv_async_send(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
|
||||||
|
uv_tcp_init _uv_tcp_init;
|
||||||
|
public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
|
||||||
|
{
|
||||||
|
Check(_uv_tcp_init(loop, handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
|
||||||
|
uv_tcp_bind _uv_tcp_bind;
|
||||||
|
public void tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags)
|
||||||
|
{
|
||||||
|
Check(_uv_tcp_bind(handle, ref addr, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void uv_connection_cb(IntPtr server, int status);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_listen(UvStreamHandle handle, int backlog, uv_connection_cb cb);
|
||||||
|
uv_listen _uv_listen;
|
||||||
|
public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb)
|
||||||
|
{
|
||||||
|
Check(_uv_listen(handle, backlog, cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_accept(UvStreamHandle server, UvStreamHandle client);
|
||||||
|
uv_accept _uv_accept;
|
||||||
|
public void accept(UvStreamHandle server, UvStreamHandle client)
|
||||||
|
{
|
||||||
|
Check(_uv_accept(server, client));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void uv_alloc_cb(IntPtr server, int suggested_size, out uv_buf_t buf);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void uv_read_cb(IntPtr server, int nread, ref uv_buf_t buf);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
|
||||||
|
uv_read_start _uv_read_start;
|
||||||
|
public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
|
||||||
|
{
|
||||||
|
Check(_uv_read_start(handle, alloc_cb, read_cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_read_stop(UvStreamHandle handle);
|
||||||
|
uv_read_stop _uv_read_stop;
|
||||||
|
public void read_stop(UvStreamHandle handle)
|
||||||
|
{
|
||||||
|
Check(_uv_read_stop(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_ip4_addr(string ip, int port, out sockaddr addr);
|
||||||
|
|
||||||
|
uv_ip4_addr _uv_ip4_addr;
|
||||||
|
public void ip4_addr(string ip, int port, out sockaddr addr)
|
||||||
|
{
|
||||||
|
Check(_uv_ip4_addr(ip, port, out addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate int uv_ip6_addr(string ip, int port, out sockaddr addr);
|
||||||
|
|
||||||
|
uv_ip6_addr _uv_ip6_addr;
|
||||||
|
public void ip6_addr(string ip, int port, out sockaddr addr)
|
||||||
|
{
|
||||||
|
Check(_uv_ip6_addr(ip, port, out addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct sockaddr
|
||||||
|
{
|
||||||
|
long w;
|
||||||
|
long x;
|
||||||
|
long y;
|
||||||
|
long z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct uv_buf_t
|
||||||
|
{
|
||||||
|
public uint len;
|
||||||
|
public IntPtr memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public class UvAsyncHandle : UvHandle
|
||||||
|
{
|
||||||
|
private static Libuv.uv_async_cb _uv_async_cb = AsyncCb;
|
||||||
|
|
||||||
|
unsafe static void AsyncCb(IntPtr handle)
|
||||||
|
{
|
||||||
|
GCHandle gcHandle = GCHandle.FromIntPtr(*(IntPtr*)handle);
|
||||||
|
var self = (UvAsyncHandle)gcHandle.Target;
|
||||||
|
self._callback.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Action _callback;
|
||||||
|
|
||||||
|
public void Init(UvLoopHandle loop, Action callback)
|
||||||
|
{
|
||||||
|
CreateHandle(loop, 256);
|
||||||
|
_callback = callback;
|
||||||
|
_uv.async_init(loop, this, _uv_async_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UvAsyncCb(IntPtr handle)
|
||||||
|
{
|
||||||
|
_callback.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send()
|
||||||
|
{
|
||||||
|
_uv.async_send(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public abstract class UvHandle : SafeHandle
|
||||||
|
{
|
||||||
|
protected Libuv _uv;
|
||||||
|
static Libuv.uv_close_cb _close_cb = DestroyHandle;
|
||||||
|
|
||||||
|
public UvHandle() : base(IntPtr.Zero, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsInvalid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return handle == IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe protected void CreateHandle(Libuv uv, int size)
|
||||||
|
{
|
||||||
|
_uv = uv;
|
||||||
|
handle = Marshal.AllocCoTaskMem(size);
|
||||||
|
*(IntPtr*)handle = GCHandle.ToIntPtr(GCHandle.Alloc(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CreateHandle(UvLoopHandle loop, int size)
|
||||||
|
{
|
||||||
|
CreateHandle(loop._uv, size);
|
||||||
|
}
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
var memory = handle;
|
||||||
|
if (memory != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
_uv.close(this, _close_cb);
|
||||||
|
handle = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe protected static void DestroyHandle(IntPtr memory)
|
||||||
|
{
|
||||||
|
var gcHandlePtr = *(IntPtr*)memory;
|
||||||
|
if (gcHandlePtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
GCHandle.FromIntPtr(gcHandlePtr).Free();
|
||||||
|
}
|
||||||
|
Marshal.FreeCoTaskMem(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public class UvLoopHandle : UvHandle
|
||||||
|
{
|
||||||
|
public void Init(Libuv uv)
|
||||||
|
{
|
||||||
|
CreateHandle(uv, 256);
|
||||||
|
_uv.loop_init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int Run(int mode = 0)
|
||||||
|
{
|
||||||
|
return _uv.run(this, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_uv.stop(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
var memory = this.handle;
|
||||||
|
if (memory != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
_uv.loop_close(this);
|
||||||
|
handle = IntPtr.Zero;
|
||||||
|
DestroyHandle(memory);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public abstract class UvStreamHandle : UvHandle
|
||||||
|
{
|
||||||
|
private Libuv.uv_connection_cb _connection_cb;
|
||||||
|
private Libuv.uv_alloc_cb _alloc_cb;
|
||||||
|
private Libuv.uv_read_cb _read_cb;
|
||||||
|
|
||||||
|
private Action<int, UvStreamHandle> _connection;
|
||||||
|
private Action<int, UvStreamHandle> _alloc;
|
||||||
|
private Action<int, byte[], UvStreamHandle> _read;
|
||||||
|
|
||||||
|
public void Listen(int backlog, Action<int, UvStreamHandle> connection)
|
||||||
|
{
|
||||||
|
_connection_cb = OnConnection;
|
||||||
|
_connection = connection;
|
||||||
|
_uv.listen(this, 10, _connection_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnConnection(IntPtr server, int status)
|
||||||
|
{
|
||||||
|
_connection(status, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Accept(UvStreamHandle handle)
|
||||||
|
{
|
||||||
|
_uv.accept(this, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadStart(Action<int, byte[], UvStreamHandle> read)
|
||||||
|
{
|
||||||
|
_alloc_cb = OnAlloc;
|
||||||
|
_read_cb = OnRead;
|
||||||
|
_read = read;
|
||||||
|
_uv.read_start(this, _alloc_cb, _read_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAlloc(IntPtr server, int suggested_size, out Libuv.uv_buf_t buf)
|
||||||
|
{
|
||||||
|
buf = new Libuv.uv_buf_t
|
||||||
|
{
|
||||||
|
memory = Marshal.AllocCoTaskMem(suggested_size),
|
||||||
|
len = (uint)suggested_size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRead(IntPtr server, int nread, ref Libuv.uv_buf_t buf)
|
||||||
|
{
|
||||||
|
if (nread == -4095)
|
||||||
|
{
|
||||||
|
_read(0, null, this);
|
||||||
|
Marshal.FreeCoTaskMem(buf.memory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var length = _uv.Check(nread);
|
||||||
|
var data = new byte[length];
|
||||||
|
Marshal.Copy(buf.memory, data, 0, length);
|
||||||
|
Marshal.FreeCoTaskMem(buf.memory);
|
||||||
|
|
||||||
|
_read(length, data, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadStop()
|
||||||
|
{
|
||||||
|
_uv.read_stop(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
|
{
|
||||||
|
public class UvTcpHandle : UvStreamHandle
|
||||||
|
{
|
||||||
|
public void Init(UvLoopHandle loop)
|
||||||
|
{
|
||||||
|
CreateHandle(loop, 256);
|
||||||
|
_uv.tcp_init(loop, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(IPEndPoint endpoint)
|
||||||
|
{
|
||||||
|
Libuv.sockaddr addr;
|
||||||
|
_uv.ip4_addr(endpoint.Address.ToString(), endpoint.Port, out addr);
|
||||||
|
_uv.tcp_bind(this, ref addr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Server.Kestrel.Networking;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.KestralTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for NetworkingTests
|
||||||
|
/// </summary>
|
||||||
|
public class NetworkingTests
|
||||||
|
{
|
||||||
|
Libuv _uv;
|
||||||
|
public NetworkingTests()
|
||||||
|
{
|
||||||
|
_uv = new Libuv();
|
||||||
|
_uv.Load("libuv.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task LoopCanBeInitAndClose()
|
||||||
|
{
|
||||||
|
var loop = new UvLoopHandle();
|
||||||
|
loop.Init(_uv);
|
||||||
|
loop.Run();
|
||||||
|
loop.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AsyncCanBeSent()
|
||||||
|
{
|
||||||
|
var loop = new UvLoopHandle();
|
||||||
|
loop.Init(_uv);
|
||||||
|
var trigger = new UvAsyncHandle();
|
||||||
|
var called = false;
|
||||||
|
trigger.Init(loop, () =>
|
||||||
|
{
|
||||||
|
called = true;
|
||||||
|
trigger.Close();
|
||||||
|
});
|
||||||
|
trigger.Send();
|
||||||
|
loop.Run();
|
||||||
|
loop.Close();
|
||||||
|
Assert.True(called);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SocketCanBeInitAndClose()
|
||||||
|
{
|
||||||
|
var loop = new UvLoopHandle();
|
||||||
|
loop.Init(_uv);
|
||||||
|
var tcp = new UvTcpHandle();
|
||||||
|
tcp.Init(loop);
|
||||||
|
tcp.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||||
|
tcp.Close();
|
||||||
|
loop.Run();
|
||||||
|
loop.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SocketCanListenAndAccept()
|
||||||
|
{
|
||||||
|
var loop = new UvLoopHandle();
|
||||||
|
loop.Init(_uv);
|
||||||
|
var tcp = new UvTcpHandle();
|
||||||
|
tcp.Init(loop);
|
||||||
|
tcp.Bind(new IPEndPoint(IPAddress.Loopback, 54321));
|
||||||
|
tcp.Listen(10, (status, handle) =>
|
||||||
|
{
|
||||||
|
var tcp2 = new UvTcpHandle();
|
||||||
|
tcp2.Init(loop);
|
||||||
|
tcp.Accept(tcp2);
|
||||||
|
tcp2.Close();
|
||||||
|
tcp.Close();
|
||||||
|
});
|
||||||
|
var t = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var socket = new Socket(
|
||||||
|
AddressFamily.InterNetwork,
|
||||||
|
SocketType.Stream,
|
||||||
|
ProtocolType.Tcp);
|
||||||
|
await Task.Factory.FromAsync(
|
||||||
|
socket.BeginConnect,
|
||||||
|
socket.EndConnect,
|
||||||
|
new IPEndPoint(IPAddress.Loopback, 54321),
|
||||||
|
null,
|
||||||
|
TaskCreationOptions.None);
|
||||||
|
socket.Close();
|
||||||
|
});
|
||||||
|
loop.Run();
|
||||||
|
loop.Close();
|
||||||
|
await t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SocketCanRead()
|
||||||
|
{
|
||||||
|
int bytesRead = 0;
|
||||||
|
var loop = new UvLoopHandle();
|
||||||
|
loop.Init(_uv);
|
||||||
|
var tcp = new UvTcpHandle();
|
||||||
|
tcp.Init(loop);
|
||||||
|
tcp.Bind(new IPEndPoint(IPAddress.Loopback, 54321));
|
||||||
|
tcp.Listen(10, (status, handle) =>
|
||||||
|
{
|
||||||
|
var tcp2 = new UvTcpHandle();
|
||||||
|
tcp2.Init(loop);
|
||||||
|
tcp.Accept(tcp2);
|
||||||
|
tcp2.ReadStart((nread, data, handle2) =>
|
||||||
|
{
|
||||||
|
bytesRead += nread;
|
||||||
|
if (nread == 0)
|
||||||
|
{
|
||||||
|
tcp2.Close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tcp.Close();
|
||||||
|
});
|
||||||
|
var t = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var socket = new Socket(
|
||||||
|
AddressFamily.InterNetwork,
|
||||||
|
SocketType.Stream,
|
||||||
|
ProtocolType.Tcp);
|
||||||
|
await Task.Factory.FromAsync(
|
||||||
|
socket.BeginConnect,
|
||||||
|
socket.EndConnect,
|
||||||
|
new IPEndPoint(IPAddress.Loopback, 54321),
|
||||||
|
null,
|
||||||
|
TaskCreationOptions.None);
|
||||||
|
await Task.Factory.FromAsync(
|
||||||
|
socket.BeginSend,
|
||||||
|
socket.EndSend,
|
||||||
|
new[] { new ArraySegment<byte>(new byte[] { 1, 2, 3, 4, 5 }) },
|
||||||
|
SocketFlags.None,
|
||||||
|
null,
|
||||||
|
TaskCreationOptions.None);
|
||||||
|
socket.Close();
|
||||||
|
});
|
||||||
|
loop.Run();
|
||||||
|
loop.Close();
|
||||||
|
await t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Loading…
Reference in New Issue