public static IObservable<Socket> ToConnectObservable(this IPEndPoint endpoint, Selector selector, CancellationToken token) { return Observable.Create<Socket>(observer => { var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { Blocking = false }; Exception error = null; bool isConnected = false; try { socket.Connect(endpoint); isConnected = true; } catch (Exception exception) { if (!exception.IsWouldBlock()) error = exception; } if (!isConnected && error == null) { var waitEvent = new ManualResetEvent(false); var waitHandles = new[] {token.WaitHandle, waitEvent}; selector.AddCallback(SelectMode.SelectWrite, socket, _ => { try { if (!socket.Connected) socket.Connect(endpoint); selector.RemoveCallback(SelectMode.SelectWrite, socket); isConnected = true; waitEvent.Set(); } catch (Exception exception) { if (exception.IsWouldBlock()) return; error = exception; waitEvent.Set(); } }); if (WaitHandle.WaitAny(waitHandles) == 0) token.ThrowIfCancellationRequested(); } if (error == null) observer.OnNext(socket); else observer.OnError(error); observer.OnCompleted(); return Disposable.Empty; }); }
public static IObservable<Socket> ToListenerObservable(this Socket socket, int backlog, Selector selector) { return Observable.Create<Socket>(observer => { socket.Listen(backlog); selector.AddCallback(SelectMode.SelectRead, socket, _ => { var accepted = socket.Accept(); accepted.Blocking = false; observer.OnNext(accepted); }); return Disposable.Create(() => selector.RemoveCallback(SelectMode.SelectRead, socket)); }); }
public static IObservable<DisposableByteBuffer> ToFrameClientObservable(this Socket socket, SocketFlags socketFlags, BufferManager bufferManager, Selector selector) { return Observable.Create<DisposableByteBuffer>(observer => { var headerState = new BufferState(new byte[sizeof(int)], 0, sizeof(int)); var contentState = new BufferState(null, 0, -1); var selectMode = socketFlags.HasFlag(SocketFlags.OutOfBand) ? SelectMode.SelectError : SelectMode.SelectRead; selector.AddCallback(selectMode, socket, _ => { try { if (headerState.Length > 0) { headerState.Advance(socket.Receive(headerState.Bytes, headerState.Offset, headerState.Length, socketFlags)); if (headerState.Length == 0) { contentState.Length = BitConverter.ToInt32(headerState.Bytes, 0); contentState.Offset = 0; contentState.Bytes = bufferManager.TakeBuffer(contentState.Length); } } if (contentState.Bytes != null) { contentState.Advance(socket.Receive(contentState.Bytes, contentState.Offset, contentState.Length, socketFlags)); if (contentState.Length == 0) { var managedBuffer = contentState.Bytes; var length = contentState.Offset; observer.OnNext(new DisposableByteBuffer(managedBuffer, length, Disposable.Create(() => bufferManager.ReturnBuffer(managedBuffer)))); contentState.Bytes = null; headerState.Length = headerState.Offset; headerState.Offset = 0; } } } catch (Exception exception) { if (!exception.IsWouldBlock()) observer.OnError(exception); } }); return Disposable.Create(() => selector.RemoveCallback(SelectMode.SelectRead, socket)); }); }
public static IObserver<DisposableByteBuffer> ToFrameClientObserver(this Socket socket, SocketFlags socketFlags, Selector selector, CancellationToken token) { return Observer.Create<DisposableByteBuffer>(disposableBuffer => { var header = BitConverter.GetBytes(disposableBuffer.Length); var headerState = new BufferState(header, 0, header.Length); var contentState = new BufferState(disposableBuffer.Bytes, 0, disposableBuffer.Length); try { headerState.Advance(socket.Send(headerState.Bytes, headerState.Offset, headerState.Length, socketFlags)); if (headerState.Length == 0) contentState.Advance(socket.Send(contentState.Bytes, contentState.Offset, contentState.Length, socketFlags)); if (contentState.Length == 0) return; } catch (Exception exception) { if (!exception.IsWouldBlock()) throw; } var waitEvent = new AutoResetEvent(false); var waitHandles = new[] { token.WaitHandle, waitEvent }; Exception error = null; selector.AddCallback(SelectMode.SelectWrite, socket, _ => { try { if (headerState.Length > 0) headerState.Advance(socket.Send(headerState.Bytes, headerState.Offset, headerState.Length, socketFlags)); if (headerState.Length == 0) contentState.Advance(socket.Send(contentState.Bytes, contentState.Offset, contentState.Length, socketFlags)); if (contentState.Length == 0) { selector.RemoveCallback(SelectMode.SelectWrite, socket); waitEvent.Set(); } } catch (Exception exception) { if (exception.IsWouldBlock()) return; error = exception; selector.RemoveCallback(SelectMode.SelectWrite, socket); waitEvent.Set(); } }); while (headerState.Length > 0 && contentState.Length > 0) { if (WaitHandle.WaitAny(waitHandles) == 0) token.ThrowIfCancellationRequested(); if (error != null) throw error; } disposableBuffer.Dispose(); }); }