Inheritance: ISocketOutput
Beispiel #1
0
        public void ProduceStart()
        {
            if (_resultStarted)
            {
                return;
            }
            _resultStarted = true;

            FireOnSendingHeaders();

            _headersSent = true;

            var status = ReasonPhrases.ToStatus(StatusCode, ReasonPhrase);

            var responseHeader = CreateResponseHeader(status, ResponseHeaders);

            SocketOutput.Write(
                responseHeader.Item1,
                (error, x) =>
            {
                if (error != null)
                {
                    Trace.WriteLine("ProduceStart " + error.ToString());
                }
                ((IDisposable)x).Dispose();
            },
                responseHeader.Item2);
        }
Beispiel #2
0
        private async Task WriteChunkedAsync(ArraySegment <byte> data, CancellationToken cancellationToken)
        {
            await SocketOutput.WriteAsync(BeginChunkBytes(data.Count), immediate : false, cancellationToken : cancellationToken);

            await SocketOutput.WriteAsync(data, immediate : false, cancellationToken : cancellationToken);

            await SocketOutput.WriteAsync(_endChunkBytes, immediate : true, cancellationToken : cancellationToken);
        }
        public void Start()
        {
            KestrelTrace.Log.ConnectionStart(_connectionId);

            SocketInput  = new SocketInput(Memory);
            SocketOutput = new SocketOutput(Thread, _socket);
            _frame       = new Frame(this);
            _socket.ReadStart(_allocCallback, _readCallback, this);
        }
        public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
        {
            _socket = socket;
            ConnectionControl = this;

            _connectionId = Interlocked.Increment(ref _lastConnectionId);

            _rawSocketInput = new SocketInput(Memory2, ThreadPool);
            _rawSocketOutput = new SocketOutput(Thread, _socket, Memory2, this, _connectionId, Log, ThreadPool, WriteReqPool);
        }
Beispiel #5
0
        public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
        {
            _socket           = socket;
            ConnectionControl = this;

            _connectionId = Interlocked.Increment(ref _lastConnectionId);

            _rawSocketInput  = new SocketInput(Memory2);
            _rawSocketOutput = new SocketOutput(Thread, _socket, _connectionId, Log);
        }
        public Connection(ListenerContext context, UvStreamHandle socket)
            : base(context)
        {
            _socket = socket;
            ConnectionControl = this;

            _connectionId = Interlocked.Increment(ref _lastConnectionId);

            SocketInput = new SocketInput(Memory2);
            SocketOutput = new SocketOutput(Thread, _socket, _connectionId, Log);
            _frame = new Frame(this);
        }
Beispiel #7
0
 internal void Contextualize(
     SocketOutput socketOutput,
     UvStreamHandle socket,
     ArraySegment <byte> buffer,
     Action <Exception, object> callback,
     object state)
 {
     _self     = socketOutput;
     _socket   = socket;
     _buffer   = buffer;
     _callback = callback;
     _state    = state;
 }
Beispiel #8
0
        public void ProduceContinue()
        {
            if (_responseStarted)
            {
                return;
            }

            StringValues expect;

            if (_httpVersion == HttpVersionType.Http1_1 &&
                RequestHeaders.TryGetValue("Expect", out expect) &&
                (expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
            {
                SocketOutput.Write(_continueBytes);
            }
        }
Beispiel #9
0
        private async Task ProduceStart(bool immediate, bool appCompleted)
        {
            if (_responseStarted)
            {
                return;
            }
            _responseStarted = true;

            var status = ReasonPhrases.ToStatus(StatusCode, ReasonPhrase);

            var responseHeader = CreateResponseHeader(status, appCompleted);

            using (responseHeader.Item2)
            {
                await SocketOutput.WriteAsync(responseHeader.Item1, immediate : immediate);
            }
        }
Beispiel #10
0
        public void Write(ArraySegment <byte> data)
        {
            ProduceStart(immediate: false);

            if (_autoChunk)
            {
                if (data.Count == 0)
                {
                    return;
                }
                WriteChunked(data);
            }
            else
            {
                SocketOutput.Write(data, immediate: true);
            }
        }
Beispiel #11
0
        public void Write(ArraySegment <byte> data)
        {
            ProduceStartAndFireOnStarting(immediate: false).GetAwaiter().GetResult();

            if (_autoChunk)
            {
                if (data.Count == 0)
                {
                    return;
                }
                WriteChunked(data);
            }
            else
            {
                SocketOutput.Write(data, immediate: true);
            }
        }
Beispiel #12
0
        public async Task WriteAsyncAwaited(ArraySegment <byte> data, CancellationToken cancellationToken)
        {
            await ProduceStartAndFireOnStarting(immediate : false);

            if (_autoChunk)
            {
                if (data.Count == 0)
                {
                    return;
                }
                await WriteChunkedAsync(data, cancellationToken);
            }
            else
            {
                await SocketOutput.WriteAsync(data, immediate : true, cancellationToken : cancellationToken);
            }
        }
Beispiel #13
0
        public void ProduceStart(bool immediate = true, bool appCompleted = false)
        {
            // ProduceStart shouldn't no-op in the future just b/c FireOnStarting throws.
            if (_responseStarted)
            {
                return;
            }
            FireOnStarting();
            _responseStarted = true;

            var status = ReasonPhrases.ToStatus(StatusCode, ReasonPhrase);

            var responseHeader = CreateResponseHeader(status, appCompleted);

            SocketOutput.Write(responseHeader.Item1, immediate: immediate);
            responseHeader.Item2.Dispose();
        }
Beispiel #14
0
        public Task WriteAsync(ArraySegment <byte> data, CancellationToken cancellationToken)
        {
            ProduceStart(immediate: false);

            if (_autoChunk)
            {
                if (data.Count == 0)
                {
                    return(TaskUtilities.CompletedTask);
                }
                return(WriteChunkedAsync(data, cancellationToken));
            }
            else
            {
                return(SocketOutput.WriteAsync(data, immediate: true, cancellationToken: cancellationToken));
            }
        }
        public void CanWrite1MB()
        {
            // This test was added because when initially implementing write-behind buffering in
            // SocketOutput, the write callback would never be invoked for writes larger than
            // _maxBytesPreCompleted even after the write actually completed.

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    triggerCompleted(0);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
                var bufferSize = 1048576;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
                var completedWh = new ManualResetEventSlim();

                // Act
                socketOutput.WriteAsync(buffer).ContinueWith(
                    (t) =>
                    {
                        Assert.Null(t.Exception);
                        completedWh.Set();
                    }
                );

                // Assert
                Assert.True(completedWh.Wait(1000));
            }
        }
        public void CanWrite1MB()
        {
            // This test was added because when initially implementing write-behind buffering in
            // SocketOutput, the write callback would never be invoked for writes larger than
            // _maxBytesPreCompleted even after the write actually completed.

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    triggerCompleted(0);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new KestrelTrace(new TestKestrelTrace()));
                var trace = new KestrelTrace(new TestKestrelTrace());
                var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace);

                // I doubt _maxBytesPreCompleted will ever be over a MB. If it is, we should change this test.
                var bufferSize = 1048576;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
                var completedWh = new ManualResetEventSlim();
                Action<Exception, object, bool> onCompleted = (ex, state, calledInline) =>
                {
                    Assert.Null(ex);
                    Assert.Null(state);
                    completedWh.Set();
                };

                // Act
                socketOutput.Write(buffer, onCompleted, null);

                // Assert
                Assert.True(completedWh.Wait(1000));
            }
        }
Beispiel #17
0
        void IConnectionControl.End(ProduceEndType endType)
        {
            lock (_stateLock)
            {
                switch (endType)
                {
                case ProduceEndType.SocketShutdownSend:
                    if (_connectionState != ConnectionState.Open)
                    {
                        return;
                    }
                    _connectionState = ConnectionState.Shutdown;

                    Log.ConnectionWriteFin(_connectionId);
                    SocketOutput.End(endType);
                    break;

                case ProduceEndType.ConnectionKeepAlive:
                    if (_connectionState != ConnectionState.Open)
                    {
                        return;
                    }

                    Log.ConnectionKeepAlive(_connectionId);
                    break;

                case ProduceEndType.SocketDisconnect:
                    if (_connectionState == ConnectionState.Disconnected)
                    {
                        return;
                    }
                    _connectionState = ConnectionState.Disconnected;

                    Log.ConnectionDisconnect(_connectionId);
                    SocketOutput.End(endType);
                    break;
                }
            }
        }
Beispiel #18
0
        public void ProduceContinue()
        {
            if (_resultStarted)
            {
                return;
            }

            string[] expect;
            if (HttpVersion.Equals("HTTP/1.1") &&
                RequestHeaders.TryGetValue("Expect", out expect) &&
                (expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
            {
                SocketOutput.Write(
                    new ArraySegment <byte>(_continueBytes, 0, _continueBytes.Length),
                    (error, _) =>
                {
                    if (error != null)
                    {
                        Trace.WriteLine("ProduceContinue " + error.ToString());
                    }
                },
                    null);
            }
        }
        public void Start()
        {
            KestrelTrace.Log.ConnectionStart(_connectionId);

            SocketInput = new SocketInput(Memory);
            SocketOutput = new SocketOutput(Thread, _socket);
            _frame = new Frame(this);
            _socket.ReadStart(_allocCallback, _readCallback, this);
        }
        public void WritesDontCompleteImmediatelyWhenTooManyBytesIncludingNonImmediateAreAlreadyPreCompleted()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue = new Queue<Action<int>>();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                var bufferSize = maxBytesPreCompleted;

                var data = new byte[bufferSize];
                var fullBuffer = new ArraySegment<byte>(data, 0, bufferSize);
                var halfBuffer = new ArraySegment<byte>(data, 0, bufferSize / 2);

                var completedWh = new ManualResetEventSlim();
                Action<Task> onCompleted = (Task t) =>
                {
                    Assert.Null(t.Exception);
                    completedWh.Set();
                };

                // Act 
                socketOutput.WriteAsync(halfBuffer, false).ContinueWith(onCompleted);
                // Assert
                // The first write should pre-complete since it is not immediate.
                Assert.True(completedWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                // Act 
                socketOutput.WriteAsync(halfBuffer).ContinueWith(onCompleted);
                // Assert
                // The second write should pre-complete since it is <= _maxBytesPreCompleted.
                Assert.True(completedWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                // Act 
                socketOutput.WriteAsync(halfBuffer, false).ContinueWith(onCompleted);
                // Assert
                // The third write should pre-complete since it is not immediate, even though too many.
                Assert.True(completedWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                // Act
                socketOutput.WriteAsync(halfBuffer).ContinueWith(onCompleted);
                // Assert 
                // Too many bytes are already pre-completed for the fourth write to pre-complete.
                Assert.False(completedWh.Wait(1000));
                // Act
                while (completeQueue.Count > 0)
                {
                    completeQueue.Dequeue()(0);
                }
                // Assert
                // Finishing the first write should allow the second write to pre-complete.
                Assert.True(completedWh.Wait(1000));
            }
        }
Beispiel #21
0
        public async Task FlushAsync(CancellationToken cancellationToken)
        {
            await ProduceStartAndFireOnStarting(immediate : false);

            await SocketOutput.WriteAsync(_emptyData, immediate : true, cancellationToken : cancellationToken);
        }
Beispiel #22
0
 public void Flush()
 {
     ProduceStartAndFireOnStarting(immediate: false).GetAwaiter().GetResult();
     SocketOutput.Write(_emptyData, immediate: true);
 }
Beispiel #23
0
 public WriteContext(SocketOutput self)
 {
     Self    = self;
     Buffers = new Queue <ArraySegment <byte> >();
 }
Beispiel #24
0
        private Task CreateResponseHeader(
            byte[] statusBytes,
            bool appCompleted,
            bool immediate)
        {
            var begin = SocketOutput.ProducingStart();
            var end   = begin;

            if (_keepAlive)
            {
                foreach (var connectionValue in _responseHeaders.HeaderConnection)
                {
                    if (connectionValue.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1)
                    {
                        _keepAlive = false;
                    }
                }
            }

            if (_keepAlive && !_responseHeaders.HasTransferEncoding && !_responseHeaders.HasContentLength)
            {
                if (appCompleted)
                {
                    // Don't set the Content-Length or Transfer-Encoding headers
                    // automatically for HEAD requests or 101, 204, 205, 304 responses.
                    if (Method != "HEAD" && StatusCanHaveBody(StatusCode))
                    {
                        // Since the app has completed and we are only now generating
                        // the headers we can safely set the Content-Length to 0.
                        _responseHeaders.SetRawContentLength("0", _bytesContentLengthZero);
                    }
                }
                else
                {
                    if (_httpVersion == HttpVersionType.Http1_1)
                    {
                        _autoChunk = true;
                        _responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked);
                    }
                    else
                    {
                        _keepAlive = false;
                    }
                }
            }

            if (_keepAlive == false && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_1)
            {
                _responseHeaders.SetRawConnection("close", _bytesConnectionClose);
            }
            else if (_keepAlive && _responseHeaders.HasConnection == false && _httpVersion == HttpVersionType.Http1_0)
            {
                _responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
            }

            end.CopyFrom(_httpVersion == HttpVersionType.Http1_1 ? _bytesHttpVersion1_1 : _bytesHttpVersion1_0);
            end.CopyFrom(statusBytes);
            _responseHeaders.CopyTo(ref end);
            end.CopyFrom(_bytesEndHeaders, 0, _bytesEndHeaders.Length);

            SocketOutput.ProducingComplete(end);

            if (immediate)
            {
                return(SocketOutput.WriteAsync(default(ArraySegment <byte>), immediate: true));
            }
            else
            {
                return(TaskUtilities.CompletedTask);
            }
        }
Beispiel #25
0
 private void WriteChunkedResponseSuffix()
 {
     SocketOutput.Write(_endChunkedResponseBytes, immediate: true);
 }
        public void WritesDontCompleteImmediatelyWhenTooManyBytesAreAlreadyPreCompleted()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue = new Queue<Action<int>>();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new KestrelTrace(new TestKestrelTrace()));
                var trace = new KestrelTrace(new TestKestrelTrace());
                var socketOutput = new SocketOutput(kestrelThread, socket, 0, trace);

                var bufferSize = maxBytesPreCompleted;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
                var completedWh = new ManualResetEventSlim();
                Action<Exception, object, bool> onCompleted = (ex, state, calledInline) =>
                {
                    Assert.Null(ex);
                    Assert.Null(state);
                    completedWh.Set();
                };

                // Act
                socketOutput.Write(buffer, onCompleted, null);
                // Assert
                // The first write should pre-complete since it is <= _maxBytesPreCompleted.
                Assert.True(completedWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                // Act
                socketOutput.Write(buffer, onCompleted, null);
                // Assert
                // Too many bytes are already pre-completed for the second write to pre-complete.
                Assert.False(completedWh.Wait(1000));
                // Act
                completeQueue.Dequeue()(0);
                // Assert
                // Finishing the first write should allow the second write to pre-complete.
                Assert.True(completedWh.Wait(1000));
            }
        }
        public void ProducingStartAndProducingCompleteCanBeUsedDirectly()
        {
            int nBuffers = 0;
            var nBufferWh = new ManualResetEventSlim();

            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    nBuffers = buffers;
                    nBufferWh.Set();
                    triggerCompleted(0);
                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                // block 1
                var start = socketOutput.ProducingStart();
                start.Block.End = start.Block.Data.Offset + start.Block.Data.Count;

                // block 2
                var block2 = memory.Lease();
                block2.End = block2.Data.Offset + block2.Data.Count;
                start.Block.Next = block2;

                var end = new MemoryPoolIterator2(block2, block2.End);

                socketOutput.ProducingComplete(end);

                // A call to Write is required to ensure a write is scheduled
                socketOutput.WriteAsync(default(ArraySegment<byte>));

                Assert.True(nBufferWh.Wait(1000));
                Assert.Equal(2, nBuffers);
            }
        }
 public WriteContext(SocketOutput self)
 {
     Self = self;
     Buffers = new Queue<ArraySegment<byte>>();
 }
 public void Post(Action<SocketOutput> callback, SocketOutput state)
 {
     lock (_workSync)
     {
         _workAdding.Enqueue(new Work
         {
             CallbackAdapter = _socketCallbackAdapter,
             Callback = callback,
             State = state
         });
     }
     _post.Send();
 }
Beispiel #30
0
 public void Flush()
 {
     ProduceStart(immediate: false);
     SocketOutput.Write(_emptyData, immediate: true);
 }
Beispiel #31
0
 private void WriteChunked(ArraySegment <byte> data)
 {
     SocketOutput.Write(BeginChunkBytes(data.Count), immediate: false);
     SocketOutput.Write(data, immediate: false);
     SocketOutput.Write(_endChunkBytes, immediate: true);
 }
Beispiel #32
0
 public void Write(ArraySegment <byte> data, Action <Exception, object> callback, object state)
 {
     ProduceStart();
     SocketOutput.Write(data, callback, state);
 }
Beispiel #33
0
 public WriteContext(SocketOutput self)
 {
     Self = self;
 }
        public void WritesDontGetCompletedTooQuickly()
        {
            // This should match _maxBytesPreCompleted in SocketOutput
            var maxBytesPreCompleted = 65536;
            var completeQueue = new Queue<Action<int>>();
            var onWriteWh = new ManualResetEventSlim();

            // Arrange
            var mockLibuv = new MockLibuv
            {
                OnWrite = (socket, buffers, triggerCompleted) =>
                {
                    completeQueue.Enqueue(triggerCompleted);
                    onWriteWh.Set();

                    return 0;
                }
            };

            using (var kestrelEngine = new KestrelEngine(mockLibuv, new TestServiceContext()))
            using (var memory = new MemoryPool2())
            {
                kestrelEngine.Start(count: 1);

                var kestrelThread = kestrelEngine.Threads[0];
                var socket = new MockSocket(kestrelThread.Loop.ThreadId, new TestKestrelTrace());
                var trace = new KestrelTrace(new TestKestrelTrace());
                var ltp = new LoggingThreadPool(trace);
                var socketOutput = new SocketOutput(kestrelThread, socket, memory, null, 0, trace, ltp, new Queue<UvWriteReq>());

                var bufferSize = maxBytesPreCompleted;
                var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);

                var completedWh = new ManualResetEventSlim();
                Action<Task> onCompleted = (Task t) =>
                {
                    Assert.Null(t.Exception);
                    completedWh.Set();
                };

                var completedWh2 = new ManualResetEventSlim();
                Action<Task> onCompleted2 = (Task t) =>
                {
                    Assert.Null(t.Exception);
                    completedWh2.Set();
                };

                // Act (Pre-complete the maximum number of bytes in preparation for the rest of the test)
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                // Assert
                // The first write should pre-complete since it is <= _maxBytesPreCompleted.
                Assert.True(completedWh.Wait(1000));
                Assert.True(onWriteWh.Wait(1000));
                // Arrange
                completedWh.Reset();
                onWriteWh.Reset();

                // Act
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted);
                socketOutput.WriteAsync(buffer).ContinueWith(onCompleted2);

                Assert.True(onWriteWh.Wait(1000));
                completeQueue.Dequeue()(0);

                // Assert 
                // Too many bytes are already pre-completed for the third but not the second write to pre-complete.
                // https://github.com/aspnet/KestrelHttpServer/issues/356
                Assert.True(completedWh.Wait(1000));
                Assert.False(completedWh2.Wait(1000));

                // Act
                completeQueue.Dequeue()(0);

                // Assert
                // Finishing the first write should allow the second write to pre-complete.
                Assert.True(completedWh2.Wait(1000));
            }
        }
Beispiel #35
0
 public Task FlushAsync(CancellationToken cancellationToken)
 {
     ProduceStart(immediate: false);
     return(SocketOutput.WriteAsync(_emptyData, immediate: true));
 }
 internal void Contextualize(
     SocketOutput socketOutput,
     UvStreamHandle socket,
     ArraySegment<byte> buffer,
     Action<Exception, object> callback,
     object state)
 {
     _self = socketOutput;
     _socket = socket;
     _buffer = buffer;
     _callback = callback;
     _state = state;
 }
 public WriteContext(SocketOutput self)
 {
     Self = self;
 }