public static IObservable <ByteBuffer> ToClientObservable(this Socket socket, int size, SocketFlags socketFlags, Selector selector) { return(Observable.Create <ByteBuffer>(observer => { var buffer = new byte[size]; var selectMode = socketFlags.HasFlag(SocketFlags.OutOfBand) ? SelectMode.SelectError : SelectMode.SelectRead; selector.AddCallback(selectMode, socket, _ => { try { var bytes = socket.Receive(buffer, 0, size, socketFlags); if (bytes == 0) { observer.OnCompleted(); } else { observer.OnNext(new ByteBuffer(buffer, bytes)); } } catch (Exception error) { if (error.IsWouldBlock()) { return; } observer.OnError(error); } }); return Disposable.Create(() => selector.RemoveCallback(SelectMode.SelectRead, socket)); })); }
public static IObservable <DisposableValue <ArraySegment <byte> > > ToFrameClientObservable(this Socket socket, SocketFlags socketFlags, BufferManager bufferManager, Selector selector) { return(Observable.Create <DisposableValue <ArraySegment <byte> > >(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(DisposableValue.Create(new ArraySegment <byte>(managedBuffer, 0, 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 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 IObserver <DisposableValue <ArraySegment <byte> > > ToFrameClientObserver(this Socket socket, SocketFlags socketFlags, Selector selector, CancellationToken token) { return(Observer.Create <DisposableValue <ArraySegment <byte> > >(disposableBuffer => { var header = BitConverter.GetBytes(disposableBuffer.Value.Count); var headerState = new BufferState(header, 0, header.Length); var contentState = new BufferState(disposableBuffer.Value.Array, 0, disposableBuffer.Value.Count); 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(); })); }
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 IObserver <ByteBuffer> ToClientObserver(this Socket socket, SocketFlags socketFlags, Selector selector, CancellationToken token) { return(Observer.Create <ByteBuffer>( buffer => { var state = new BufferState(buffer.Bytes, 0, buffer.Length); // Try to write as much as possible without registering a callback. try { state.Advance(socket.Send(state.Bytes, state.Offset, state.Length, socketFlags)); if (state.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 { state.Advance(socket.Send(state.Bytes, state.Offset, state.Length, socketFlags)); if (state.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 (state.Length > 0) { if (WaitHandle.WaitAny(waitHandles) == 0) { token.ThrowIfCancellationRequested(); } if (error != null) { throw error; } } })); }