public MultipleLoopTests() { var engine = new KestrelEngine(new TestServiceContext()); _uv = engine.Libuv; _logger = engine.Log; }
internal static void _WriteCallback(IntPtr handle, int status) { var request = FromIntPtr <UvWriteRequest>(handle); foreach (var gcHandle in request._PinnedWriteHandles) { gcHandle.Free(); } request._PinnedWriteHandles.Clear(); var callback = request.Callback; request.Callback = null; var state = request.State; request.State = null; Exception error; Libuv.CheckStatusCode(status, out error); if (callback != null) { callback.Invoke(request, error, state); } request.Close(); }
/// <summary> /// Executes the request on the base handle. /// </summary> public void Connect() { var addr = SockAddr.FromIpEndPoint(this.EndPoint); Libuv.EnsureSuccess(Libuv.uv_tcp_connect(this, this.BaseHandle, ref addr, _UvConnectCallback)); this.EndPoint = null; }
/// <summary> /// Starts reading data from an incoming stream. /// The <paramref name="readCallback"/> will be executed several times until the stream closes or <see cref="ReadStop"/> method is called. /// </summary> /// <param name="allocCallback">Allocation callback.</param> /// <param name="readCallback">Read callback.</param> /// <param name="state">State to be passed to the callbacks.</param> public void ReadStart(AllocCallbackDelegate allocCallback, ReadCallbackDelegate readCallback, object state = null) { this.EnsureCallingThread(); if (this._ReadVitality.IsAllocated) { throw new InvalidOperationException("ReadStop must be called before ReadStart may be called again."); } try { this._ReadVitality = GCHandle.Alloc(this, GCHandleType.Normal); this._UserAllocCallback = allocCallback; this._UserReadCallback = readCallback; this._UserReadState = state; Libuv.EnsureSuccess(Libuv.uv_read_start(this, _UvAllocCallback, _UvReadCallback)); } catch (Exception) { this._UserAllocCallback = null; this._UserReadCallback = null; this._UserReadState = null; if (this._ReadVitality.IsAllocated) { this._ReadVitality.Free(); } throw; } }
public unsafe void Write( UvStreamHandle handle, ref ReadableBuffer buffer, Action <UvWriteReq, int, Exception, object> callback, object state) { try { int nBuffers = 0; if (buffer.IsSingleSpan) { nBuffers = 1; } else { foreach (var span in buffer) { nBuffers++; } } // add GCHandle to keeps this SafeHandle alive while request processing _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal)); var pBuffers = (Uv.uv_buf_t *)_bufs; if (nBuffers > BUFFER_COUNT) { // create and pin buffer array when it's larger than the pre-allocated one var bufArray = new Uv.uv_buf_t[nBuffers]; var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); _pins.Add(gcHandle); pBuffers = (Uv.uv_buf_t *)gcHandle.AddrOfPinnedObject(); } if (nBuffers == 1) { var span = buffer.FirstSpan; pBuffers[0] = Libuv.buf_init((IntPtr)span.UnsafePointer, span.Length); } else { int i = 0; foreach (var span in buffer) { pBuffers[i++] = Libuv.buf_init((IntPtr)span.UnsafePointer, span.Length); } } _callback = callback; _state = state; _uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb); } catch { _callback = null; _state = null; Unpin(this); throw; } }
public NetworkingTests() { var engine = new KestrelEngine(new TestServiceContext()); _uv = engine.Libuv; _logger = engine.Log; }
public void Connect( UvTcpHandle socket, IPEndPoint endpoint, Action <UvConnectRequest, int, Exception, object> callback, object state) { _callback = callback; _state = state; SockAddr addr; var addressText = endpoint.Address.ToString(); Exception error1; _uv.ip4_addr(addressText, endpoint.Port, out addr, out error1); if (error1 != null) { Exception error2; _uv.ip6_addr(addressText, endpoint.Port, out addr, out error2); if (error2 != null) { throw error1; } } Pin(); Libuv.tcp_connect(this, socket, ref addr, _uv_connect_cb); }
/// <summary> /// Start listening for incoming connections. /// </summary> /// <param name="backlog">Indicates the number of connections the kernel might queue.</param> /// <param name="callback">Callback to be called when a new incoming connection is received.</param> /// <param name="state">State to be passed to the callback.</param> public void Listen(int backlog, ListenCallbackDelegate callback, object state = null) { this.EnsureCallingThread(); if (this._ListenVitality.IsAllocated) { throw new InvalidOperationException("Listen may not be called more than once."); } try { this._UserListenCallback = callback; this._UserListenState = state; this._ListenVitality = GCHandle.Alloc(this, GCHandleType.Normal); Libuv.EnsureSuccess(Libuv.uv_listen(this, backlog, _UvListenCallback)); } catch { this._UserListenCallback = null; this._UserListenState = null; if (this._ListenVitality.IsAllocated) { this._ListenVitality.Free(); } throw; } }
/// <summary> /// Executes the write request on the base handle. /// </summary> public void Write() { this.EnsureCallingThread(); try { // Build UvBuffers to write var buffers = this.Buffers; var count = buffers.Count; var uvBuffers = new UvBuffer[count]; for (int i = 0; i < count; i++) { var buffer = buffers[i]; var pinnedBufferHandle = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); this._PinnedWriteHandles.Add(pinnedBufferHandle); uvBuffers[i] = Libuv.uv_buf_init(Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset), buffer.Count); } this.Write(uvBuffers); } catch (Exception) { foreach (var gcHandle in this._PinnedWriteHandles) { gcHandle.Free(); } this._PinnedWriteHandles.Clear(); throw; } }
/// <summary> /// Binds the handle to the specified end point. /// </summary> /// <param name="endPoint"></param> public void Bind(IPEndPoint endPoint) { this.EnsureCallingThread(); var addr = SockAddr.FromIpEndPoint(endPoint); Libuv.EnsureSuccess(Libuv.uv_tcp_bind(this, ref addr, 0)); }
private static void _ListenCallback(IntPtr serverPtr, int status) { var stream = FromIntPtr <UvNetworkStream>(serverPtr); Exception error; Libuv.CheckStatusCode(status, out error); stream._UserListenCallback.Invoke(stream, error, stream._UserListenState); }
public void Connect( UvPipeHandle pipe, string name, Action <UvConnectRequest, int, UvException, object> callback, object state) { _callback = callback; _state = state; Libuv.pipe_connect(this, pipe, name, _uv_connect_cb); }
private unsafe void WriteArraySegmentInternal( UvStreamHandle handle, ArraySegment <ArraySegment <byte> > bufs, UvStreamHandle sendHandle, Action <UvWriteReq, int, UvException, object> callback, object state) { try { var pBuffers = (Uv.uv_buf_t *)_bufs; var nBuffers = bufs.Count; if (nBuffers > BUFFER_COUNT) { // create and pin buffer array when it's larger than the pre-allocated one var bufArray = new Uv.uv_buf_t[nBuffers]; var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned); _pins.Add(gcHandle); pBuffers = (Uv.uv_buf_t *)gcHandle.AddrOfPinnedObject(); } for (var index = 0; index < nBuffers; index++) { // create and pin each segment being written var buf = bufs.Array[bufs.Offset + index]; var gcHandle = GCHandle.Alloc(buf.Array, GCHandleType.Pinned); _pins.Add(gcHandle); pBuffers[index] = Libuv.buf_init( gcHandle.AddrOfPinnedObject() + buf.Offset, buf.Count); } _callback = callback; _state = state; if (sendHandle == null) { _uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb); } else { _uv.write2(this, handle, pBuffers, nBuffers, sendHandle, _uv_write_cb); } } catch { _callback = null; _state = null; UnpinGcHandles(); throw; } }
/// <summary> /// Initializes a new instance of the <see cref="UvPrepare"/> handle. /// </summary> /// <param name="loop">Loop, on which this handle will be initialized.</param> /// <param name="callback">Callback, which will be invoked every loop iteration.</param> /// <param name="state">A state object to be stored in the handle for later use inside the callback.</param> public UvPrepare(UvLoop loop, Action <UvPrepare> callback, object state) : base(loop, UvHandleType.Prepare) { if (callback == null) { throw new ArgumentNullException(nameof(callback)); } this._Callback = callback; this._State = state; Libuv.EnsureSuccess(Libuv.uv_prepare_init(loop, this)); this.NeedsToBeClosed = true; }
/// <summary> /// Initializes a new instance of the <see cref="UvAsync"/> handle. /// </summary> /// <param name="loop">Loop, on which this handle will be initialized.</param> /// <param name="callback">A callback, which will be executed after a loop will receive an async signal from this handle.</param> /// <param name="state">A state object to be stored in the handle for later use inside the callback.</param> public UvAsync(UvLoop loop, Action <UvAsync> callback, object state = null) : base(loop, UvHandleType.Async) { if (callback == null) { throw new ArgumentNullException(nameof(callback)); } this._Callback = callback; this._State = state; Libuv.EnsureSuccess(Libuv.uv_async_init(loop, this, _UvAsyncCallback)); this.NeedsToBeClosed = true; }
/// <inheritdoc/> protected override void CloseHandle() { this.EnsureCallingThread(); // Protect the managed object from being collected by GC during closing inside the libuv logic if (!this._ClosingHandle.IsAllocated) { this._ClosingHandle = GCHandle.Alloc(this, GCHandleType.Normal); } // Object disposing will be performed inside a callback Libuv.uv_close(this, _UvCloseCallback); }
/// <summary> /// Stops data reading for the stream. The <see cref="ReadCallbackDelegate"/> callback will no longer be called. /// </summary> public void ReadStop() { this.EnsureCallingThread(); if (!this._ReadVitality.IsAllocated) { throw new InvalidOperationException("ReadStart must be called before ReadStop may be called."); } this._UserAllocCallback = null; this._UserReadCallback = null; this._UserReadState = null; this._ReadVitality.Free(); Libuv.EnsureSuccess(Libuv.uv_read_stop(this)); }
/// <summary> /// Get the address of the peer connected to the handle. /// </summary> /// <returns></returns> public IPEndPoint GetSockEndPoint() { this.EnsureCallingThread(); SockAddr socketAddress; #if DOTNET_CORE int namelen = Marshal.SizeOf <SockAddr>(); #else int namelen = Marshal.SizeOf(typeof(SockAddr)); #endif Libuv.EnsureSuccess(Libuv.uv_tcp_getsockname(this, out socketAddress, ref namelen)); return(socketAddress.ToIpEndPoint()); }
private static void _ReadCallback(IntPtr streamPtr, int nread, ref UvBuffer buf) { var stream = FromIntPtr <UvStream>(streamPtr); foreach (var gcHandle in stream._PinnedReadHandles) { gcHandle.Free(); } stream._PinnedReadHandles.Clear(); Exception error; Libuv.CheckStatusCode(nread, out error); stream._UserReadCallback.Invoke(stream, nread, error, stream._UserReadState); }
public KestrelEngine(ILibraryManager libraryManager, IApplicationShutdown appShutdownService) { AppShutdown = appShutdownService; Threads = new List <KestrelThread>(); Listeners = new List <Listener>(); Memory = new MemoryPool(); Libuv = new Libuv(); var libraryPath = default(string); if (libraryManager != null) { var library = libraryManager.GetLibraryInformation("Microsoft.AspNet.Server.Kestrel"); libraryPath = library.Path; if (library.Type == "Project") { libraryPath = Path.GetDirectoryName(libraryPath); } if (Libuv.IsWindows) { var architecture = IntPtr.Size == 4 ? "x86" : "amd64"; libraryPath = Path.Combine( libraryPath, "native", "windows", architecture, "libuv.dll"); } else if (Libuv.IsDarwin) { libraryPath = Path.Combine( libraryPath, "native", "darwin", "universal", "libuv.dylib"); } else { libraryPath = "libuv.so.1"; } } Libuv.Load(libraryPath); }
public KestrelEngine(ILibraryManager libraryManager, ServiceContext context) : this(context) { Libuv = new Libuv(); var libraryPath = default(string); if (libraryManager != null) { var library = libraryManager.GetLibrary("Microsoft.AspNet.Server.Kestrel"); libraryPath = library.Path; if (library.Type == "Project") { libraryPath = Path.GetDirectoryName(libraryPath); } if (Libuv.IsWindows) { var architecture = IntPtr.Size == 4 ? "x86" : "x64"; libraryPath = Path.Combine( libraryPath, "runtimes", "win7-" + architecture, "native", "libuv.dll"); } else if (Libuv.IsDarwin) { libraryPath = Path.Combine( libraryPath, "runtimes", "osx", "native", "libuv.dylib"); } else { libraryPath = "libuv.so.1"; } } Libuv.Load(libraryPath); }
private void RunLoop() { Uv = new Libuv(); Log = new KestrelTrace(new LoggerFactory().CreateLogger <UvTcpListener>()); Loop = new UvLoopHandle(Log); Loop.Init(Uv); _shutdownPostHandle = new UvAsyncHandle(Log); _shutdownPostHandle.Init(Loop, OnPost, _queueCloseCallback); _listenSocket = new UvTcpHandle(Log); _listenSocket.Init(Loop, _queueCloseCallback); _listenSocket.NoDelay(true); string host = null; if (_ip == IPAddress.Any) { host = "*"; } else if (_ip == IPAddress.Loopback) { host = "localhost"; } else { host = _ip.ToString(); } var url = $"http://{host}:{_port}"; var address = Microsoft.AspNetCore.Server.Kestrel.ServerAddress.FromUrl(url); _listenSocket.Bind(address); _listenSocket.Listen(10, _onConnectionCallback, this); Uv.run(Loop, 0); }
private static void _AllocCallback(IntPtr streamPtr, int suggestedSize, out UvBuffer buf) { var stream = FromIntPtr <UvStream>(streamPtr); try { var buffer = stream._UserAllocCallback.Invoke(stream, suggestedSize, stream._UserReadState); var pinnedBufferHandle = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); stream._PinnedReadHandles.Add(pinnedBufferHandle); buf = Libuv.uv_buf_init(Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset), buffer.Count); } catch (Exception) { foreach (var gcHandle in stream._PinnedReadHandles) { gcHandle.Free(); } stream._PinnedReadHandles.Clear(); buf = Libuv.uv_buf_init(IntPtr.Zero, 0); throw; } }
private static void _ConnectCallback(IntPtr handle, int status) { var request = FromIntPtr <UvTcpConnectRequest>(handle); var callback = request.Callback; request.Callback = null; var state = request.State; request.State = null; Exception error; Libuv.CheckStatusCode(status, out error); if (callback != null) { callback.Invoke(request, error, state); } request.Close(); }
private static int _CalculateSize(UvHandleType handleType) { return(Libuv.uv_handle_size(handleType).ToInt32()); }
/// <summary> /// This call is used in conjunction with <see cref="Listen"/> to accept incoming connections. /// Call this function after receiving a <see cref="ListenCallbackDelegate"/> to accept the connection. /// </summary> /// <param name="client"></param> public void Accept(UvStream client) { this.EnsureCallingThread(); Libuv.EnsureSuccess(Libuv.uv_accept(this, client)); }
/// <summary> /// Set the number of pending pipe instance handles when the pipe server is waiting for connections. /// </summary> /// <param name="count"></param> public void SetPendingInstances(int count) { this.EnsureCallingThread(); Libuv.uv_pipe_pending_instances(this, count); }
/// <summary> /// Enables / disables Nagle’s algorithm. /// </summary> /// <param name="enable"></param> public void NoDelay(bool enable) { this.EnsureCallingThread(); Libuv.EnsureSuccess(Libuv.uv_tcp_nodelay(this, enable ? 1 : 0)); }
/// <summary> /// Opens an existing file descriptor or SOCKET as a TCP handle. /// </summary> /// <param name="hSocket"></param> public void Open(IntPtr hSocket) { this.EnsureCallingThread(); Libuv.EnsureSuccess(Libuv.uv_tcp_open(this, hSocket)); }
/// <summary> /// Initializes a new instance of <see cref="UvTcp"/> handle on the given event loop. /// </summary> /// <param name="loop"></param> public UvTcp(UvLoop loop) : base(loop, UvHandleType.Tcp) { Libuv.EnsureSuccess(Libuv.uv_tcp_init(loop, this)); this.NeedsToBeClosed = true; }