unsafe void IMessageWriter.Write(ref WritableBuffer buffer) { int expected = GetTotalBytes(); if (expected == 0) { return; } var memory = buffer.Memory; byte *dest = (byte *)memory.BufferPtr; int actual; fixed(char *chars = value) { #if ENCODING_POINTER_API var enc = Interlocked.Exchange(ref sharedEncoder, null); if (enc == null) { enc = encoding.GetEncoder(); // need a new one } actual = enc.GetBytes(chars + offset, count, dest, expected, true); Interlocked.CompareExchange(ref sharedEncoder, enc, null); // make the encoder available for re-use #else actual = encoding.GetBytes(chars + offset, count, dest, expected); #endif } if (actual != expected) { throw new InvalidOperationException($"Unexpected length in {nameof(StringMessageWriter)}.{nameof(IMessageWriter.Write)}"); } buffer.CommitBytes(actual); }
public static unsafe void WriteUtf8String(ref WritableBuffer buffer, string value) { fixed(char *s = value) { var byteCount = Utf8Encoding.GetByteCount(value); buffer.Ensure(byteCount); int written = Utf8Encoding.GetBytes(s, value.Length, (byte *)buffer.Memory.BufferPtr, byteCount); buffer.CommitBytes(written); } }
public static unsafe void WriteAsciiString(ref WritableBuffer buffer, string value) { // One byte per char buffer.Ensure(value.Length); fixed(char *s = value) { int written = ASCIIEncoding.GetBytes(s, value.Length, (byte *)buffer.Memory.BufferPtr, value.Length); buffer.CommitBytes(written); } }
private void OnRead(UvStreamHandle handle, int status) { if (status == 0) { // A zero status does not indicate an error or connection end. It indicates // there is no data to be read right now. // See the note at http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb. // We need to clean up whatever was allocated by OnAlloc. _inputBuffer.FlushAsync(); return; } var normalRead = status > 0; var normalDone = status == EOF; var errorDone = !(normalDone || normalRead); var readCount = normalRead ? status : 0; if (!normalRead) { handle.ReadStop(); } _inputBuffer.CommitBytes(readCount); IOException error = null; if (errorDone) { Exception uvError; handle.Libuv.Check(status, out uvError); error = new IOException(uvError.Message, uvError); _input.CompleteWriting(error); } else if (readCount == 0 || _input.ReaderCompleted.IsCompleted) { _input.CompleteWriting(); } else { var task = _inputBuffer.FlushAsync(); if (!task.IsCompleted) { // If there's back pressure handle.ReadStop(); // Resume reading when task continues task.ContinueWith((t, state) => ((UvTcpConnection)state).StartReading(), this); } } }
private void OnRead(UvStreamHandle handle, int status) { if (status == 0) { // A zero status does not indicate an error or connection end. It indicates // there is no data to be read right now. // See the note at http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb. // We need to clean up whatever was allocated by OnAlloc. return; } var normalRead = status > 0; var normalDone = status == EOF; var errorDone = !(normalDone || normalRead); var readCount = normalRead ? status : 0; if (!normalRead) { handle.ReadStop(); } _inputBuffer.CommitBytes(readCount); IOException error = null; if (errorDone) { Exception uvError; handle.Libuv.Check(status, out uvError); error = new IOException(uvError.Message, uvError); _input.CompleteWriting(error); } else if (readCount == 0) { _input.CompleteWriting(); } else { var task = _input.WriteAsync(_inputBuffer); if (task.IsFaulted) { // TODO: Stop producing forever } else if (!task.IsCompleted) { // TODO: Pause reading until the task completes } } }
public void ReceiveBeginComplete(uint bytesTransferred) { if (bytesTransferred == 0 || _input.ReaderCompleted.IsCompleted) { _input.CompleteWriting(); } else { _buffer.CommitBytes((int)bytesTransferred); _buffer.Commit(); ProcessReceives(); } }
internal static unsafe void WriteFrameHeader(ref WritableBuffer output, WebSocketsFrame.FrameFlags flags, WebSocketsFrame.OpCodes opCode, int payloadLength, int mask) { byte *buffer = (byte *)output.Memory.BufferPtr; int bytesWritten; *buffer++ = (byte)(((int)flags & 240) | ((int)opCode & 15)); if (payloadLength > ushort.MaxValue) { // write as a 64-bit length *buffer++ = (byte)((mask != 0 ? 128 : 0) | 127); *buffer++ = 0; *buffer++ = 0; *buffer++ = 0; *buffer++ = 0; *buffer++ = (byte)(payloadLength >> 24); *buffer++ = (byte)(payloadLength >> 16); *buffer++ = (byte)(payloadLength >> 8); *buffer++ = (byte)(payloadLength); bytesWritten = 10; } else if (payloadLength > 125) { // write as a 16-bit length *buffer++ = (byte)((mask != 0 ? 128 : 0) | 126); *buffer++ = (byte)(payloadLength >> 8); *buffer++ = (byte)(payloadLength); bytesWritten = 4; } else { // write in the header *buffer++ = (byte)((mask != 0 ? 128 : 0) | payloadLength); bytesWritten = 2; } if (mask != 0) { *buffer++ = (byte)(mask >> 24); *buffer++ = (byte)(mask >> 16); *buffer++ = (byte)(mask >> 8); *buffer++ = (byte)(mask); bytesWritten += 4; } output.CommitBytes(bytesWritten); }
public void Complete(int status, long requestCorrelation, uint bytesTransferred) { // Receives if (requestCorrelation >= 0) { if (bytesTransferred == 0 || _input.ReaderCompleted.IsCompleted) { _input.CompleteWriting(); } else { _buffer.CommitBytes((int)bytesTransferred); _buffer.FlushAsync(); ProcessReceives(); } } else { SendCompleting(requestCorrelation); } }
public void Complete(int status, long requestCorrelation, uint bytesTransferred) { // Receives if (requestCorrelation >= 0) { if (bytesTransferred > 0) { _buffer.CommitBytes((int)bytesTransferred); _input.WriteAsync(_buffer); ProcessReceives(); } else { _input.CompleteWriting(); } } else { SendCompleting(requestCorrelation); } }
public void CommitBytes(int bytes) { _writableBuffer.CommitBytes(bytes); }
public static unsafe void WriteUInt64(ref WritableBuffer buffer, ulong value) { // optimized versions for 0-1000 int len; byte *addr; if (value < 10) { buffer.Ensure(len = 1); addr = (byte *)buffer.Memory.UnsafePointer; *addr = (byte)('0' + value); } else if (value < 100) { buffer.Ensure(len = 2); addr = (byte *)buffer.Memory.UnsafePointer; *addr++ = (byte)('0' + value / 10); *addr = (byte)('0' + value % 10); } else if (value < 1000) { buffer.Ensure(len = 3); addr = (byte *)buffer.Memory.UnsafePointer; addr[2] = (byte)('0' + value % 10); value /= 10; *addr++ = (byte)('0' + value / 10); *addr = (byte)('0' + value % 10); } else { // more generic version for all other numbers; first find the number of digits; // lost of ways to do this, but: http://stackoverflow.com/a/6655759/23354 ulong remaining = value; len = 1; if (remaining >= 10000000000000000) { remaining /= 10000000000000000; len += 16; } if (remaining >= 100000000) { remaining /= 100000000; len += 8; } if (remaining >= 10000) { remaining /= 10000; len += 4; } if (remaining >= 100) { remaining /= 100; len += 2; } if (remaining >= 10) { remaining /= 10; len += 1; } buffer.Ensure(len); // now we'll walk *backwards* from the last character, adding the digit each time // and dividing by 10 addr = (byte *)buffer.Memory.UnsafePointer + len; do { *--addr = (byte)('0' + value % 10); value /= 10; } while (value != 0); } buffer.CommitBytes(len); }