private void EnsureBuffer() { if (_needAlloc) { _writableBuffer = _writer.Alloc(); _needAlloc = false; } }
private void ProcessReceives() { _buffer = _input.Alloc(2048); var receiveBufferSeg = GetSegmentFromMemory(_buffer.Memory); if (!_rio.RioReceive(_requestQueue, ref receiveBufferSeg, 1, RioReceiveFlags.None, 0)) { ThrowError(ErrorType.Receive); } }
private static unsafe Exception Receive(int fd, int availableBytes, ref WritableBuffer wb) { int ioVectorLength = availableBytes <= wb.Buffer.Length ? 1 : Math.Min(1 + (availableBytes - wb.Buffer.Length + MaxPooledBlockLength - 1) / MaxPooledBlockLength, MaxIOVectorReceiveLength); var ioVectors = stackalloc IOVector[ioVectorLength]; var allocated = 0; var advanced = 0; int ioVectorsUsed = 0; for (; ioVectorsUsed < ioVectorLength; ioVectorsUsed++) { wb.Ensure(1); var memory = wb.Buffer; var length = memory.Length; void *pointer; wb.Buffer.TryGetPointer(out pointer); ioVectors[ioVectorsUsed].Base = pointer; ioVectors[ioVectorsUsed].Count = (void *)length; allocated += length; if (allocated >= availableBytes) { // Every Memory (except the last one) must be filled completely. ioVectorsUsed++; break; } wb.Advance(length); advanced += length; } var expectedMin = Math.Min(availableBytes, allocated); // Ideally we get availableBytes in a single receive // but we are happy if we get at least a part of it // and we are willing to take {MaxEAgainCount} EAGAINs. // Less data could be returned due to these reasons: // * TCP URG // * packet was not placed in receive queue (race with FIONREAD) // * ? const int MaxEAgainCount = 10; var eAgainCount = 0; var received = 0; do { var result = SocketInterop.Receive(fd, ioVectors, ioVectorsUsed); if (result.IsSuccess) { received += result.Value; if (received >= expectedMin) { // We made it! wb.Advance(received - advanced); return(null); } eAgainCount = 0; // Update ioVectors to match bytes read var skip = result.Value; for (int i = 0; (i < ioVectorsUsed) && (skip > 0); i++) { var length = (int)ioVectors[i].Count; var skipped = Math.Min(skip, length); ioVectors[i].Count = (void *)(length - skipped); ioVectors[i].Base = (byte *)ioVectors[i].Base + skipped; skip -= skipped; } } else if (result == PosixResult.EAGAIN || result == PosixResult.EWOULDBLOCK) { eAgainCount++; if (eAgainCount == MaxEAgainCount) { return(new NotSupportedException("Too many EAGAIN, unable to receive available bytes.")); } } else if (result == PosixResult.ECONNRESET) { return(new ConnectionResetException(result.ErrorDescription(), result.AsException())); } else { return(result.AsException()); } } while (true); }
void IMessageWriter.WritePayload(WritableBuffer buffer) => buffer.WriteUtf8String(value);
public unsafe int SignHash(IHashProvider provider, SignatureScheme scheme, ref WritableBuffer writer, byte *message, int messageLength) { var keySize = SignatureSize(scheme); IntPtr hashType; switch (scheme) { case SignatureScheme.rsa_pkcs1_sha256: case SignatureScheme.rsa_pss_sha256: hashType = EVP_sha256; break; case SignatureScheme.rsa_pkcs1_sha512: case SignatureScheme.rsa_pss_sha512: hashType = EVP_sha512; break; case SignatureScheme.rsa_pkcs1_sha384: case SignatureScheme.rsa_pss_sha384: hashType = EVP_sha384; break; default: ExceptionHelper.ThrowException(new ArgumentOutOfRangeException(nameof(scheme))); hashType = IntPtr.Zero; break; } EVP_MD_CTX ctx = EVP_MD_CTX_new(); EVP_PKEY_CTX pctx; GCHandle handle; try { ThrowOnError(EVP_DigestSignInit(ctx, &pctx, hashType, IntPtr.Zero, _key)); ThrowIfNegative(EVP_PKEY_CTX_ctrl(pctx, EVP_PKEY_type.EVP_PKEY_RSA, EVP_PKEY_Ctrl_OP.EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_Ctrl_Command.EVP_PKEY_CTRL_MD, 0, (void *)hashType)); if ((((ushort)scheme) & 0x00FF) == 1) { ThrowIfNegative(EVP_PKEY_CTX_ctrl(pctx, EVP_PKEY_type.EVP_PKEY_RSA, EVP_PKEY_Ctrl_OP.EVP_PKEY_OP_NONE , EVP_PKEY_Ctrl_Command.EVP_PKEY_CTRL_RSA_PADDING, (int)RSA_PADDING.RSA_PKCS1_PADDING, null)); } else { //PSS Padding ThrowIfNegative(EVP_PKEY_CTX_ctrl(pctx, EVP_PKEY_type.EVP_PKEY_RSA, EVP_PKEY_Ctrl_OP.EVP_PKEY_OP_SIGN , EVP_PKEY_Ctrl_Command.EVP_PKEY_CTRL_RSA_PADDING, (int)RSA_PADDING.RSA_PKCS1_PSS_PADDING, null)); ThrowIfNegative(EVP_PKEY_CTX_ctrl(pctx, EVP_PKEY_type.EVP_PKEY_RSA, EVP_PKEY_Ctrl_OP.EVP_PKEY_OP_SIGN , EVP_PKEY_Ctrl_Command.EVP_PKEY_CTRL_RSA_PSS_SALTLEN, 32, null)); } ThrowOnError(EVP_DigestUpdate(ctx, message, messageLength)); var size = UIntPtr.Zero; ThrowOnError(EVP_DigestSignFinal(ctx, null, ref size)); writer.Ensure((int)size); var output = writer.Memory.GetPointer(out handle); ThrowOnError(EVP_DigestSignFinal(ctx, output, ref size)); writer.Advance((int)size); return((int)size); } finally { ctx.Free(); if (handle.IsAllocated) { handle.Free(); } } }
protected void WriteTag(ref WritableBuffer writer) { writer.Ensure(_key.TagSize); _key.GetTag(writer.Buffer.Span.Slice(0, _key.TagSize)); writer.Advance(_key.TagSize); }
public static void WriteEndChunkBytes(ref WritableBuffer start) { start.Write(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count); }
private void WriteEndResponse(ref WritableBuffer buffer) { buffer.Write(_chunkedEndBytes, 0, _chunkedEndBytes.Length); }
public static void WriteUInt64(this WritableBuffer buffer, ulong value) { // optimized versions for 0-1000 int len; if (value < 10) { buffer.Ensure(len = 1); var span = buffer.Memory.Span; span[0] = (byte)('0' + value); } else if (value < 100) { buffer.Ensure(len = 2); var span = buffer.Memory.Span; span[0] = (byte)('0' + value / 10); span[1] = (byte)('0' + value % 10); } else if (value < 1000) { buffer.Ensure(len = 3); var span = buffer.Memory.Span; span[2] = (byte)('0' + value % 10); value /= 10; span[0] = (byte)('0' + value / 10); span[1] = (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 int index = len - 1; var span = buffer.Memory.Span; do { span[index--] = (byte)('0' + value % 10); value /= 10; } while (value != 0); } buffer.Advance(len); }
internal virtual void Visit(WritableBuffer key, WritableBuffer value) { key.PutInt(0, this.Key); value.PutInt(0, this.Value); }
public override void HandleHandshakeMessage(HandshakeType handshakeMessageType, ReadableBuffer buffer, ref WritableBuffer outBuffer) { switch (State) { case StateType.None: if (handshakeMessageType != HandshakeType.client_hello) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, "Tls 12 didnt get a client hello"); } Hello.ReadClientHelloTls12(buffer, this); if (CipherSuite == null) { //Couldn't agree a set of ciphers Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.handshake_failure, "Could not agree on a cipher suite during reading client hello"); } this.StartHandshakeHash(buffer); //Write server hello ChangeState(StateType.SendServerHello); _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.server_hello, Hello.SendServerHello12); _frameWriter.FinishFrame(ref outBuffer); _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.certificate, ServerHandshakeTls12.SendCertificates); _frameWriter.FinishFrame(ref outBuffer); if (CipherSuite.ExchangeType == KeyExchangeType.Ecdhe || CipherSuite.ExchangeType == KeyExchangeType.Dhe) { if (KeyShare == null) { KeyShare = CryptoProvider.GetDefaultKeyShare(CipherSuite.ExchangeType); } _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.server_key_exchange, ServerHandshakeTls12.SendKeyExchange); _frameWriter.FinishFrame(ref outBuffer); } _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.server_hello_done, (w, state) => w); _frameWriter.FinishFrame(ref outBuffer); ChangeState(StateType.WaitClientKeyExchange); break; case StateType.WaitClientKeyExchange: if (handshakeMessageType != HandshakeType.client_key_exchange) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"Received a {handshakeMessageType} when we expected a {HandshakeType.client_key_exchange}"); } HandshakeHash.HashData(buffer); KeyShare.SetPeerKey(buffer.Slice(5)); _schedule.GenerateMasterSecret(); _schedule.CalculateClientFinished(); //We can send the server finished because we have the expected client finished _schedule.GenerateKeyMaterial(); ChangeState(StateType.ChangeCipherSpec); break; case StateType.WaitClientFinished: if (handshakeMessageType != HandshakeType.finished) { Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"unexpected message"); } _schedule.CompareClientFinishedGenerateServerFinished(buffer); _frameWriter.StartFrame(RecordType.ChangeCipherSpec, ref outBuffer); outBuffer.WriteBigEndian <byte>(1); _frameWriter.FinishFrame(ref outBuffer); _writeKey = _schedule.GetServerKey(); _frameWriter.StartFrame(RecordType.Handshake, ref outBuffer); this.WriteHandshake(ref outBuffer, HandshakeType.finished, _schedule.WriteServerFinished); _frameWriter.FinishFrame(ref outBuffer); KeyShare?.Dispose(); KeyShare = null; ChangeState(StateType.HandshakeComplete); break; default: Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.unexpected_message, $"Not in any known state {State} that we expected a handshake messge from {handshakeMessageType}"); break; } }
private unsafe Uv.uv_buf_t OnAlloc(UvStreamHandle handle, int status) { _inputBuffer = _input.Alloc(2048); return(handle.Libuv.buf_init((IntPtr)_inputBuffer.Memory.UnsafePointer, _inputBuffer.Memory.Length)); }
public async Task FlushAsync(WritableBuffer buffer) { await buffer.FlushAsync(); }
public static WritableBuffer SendKeyExchange(WritableBuffer buffer, IConnectionState connectionState) { connectionState.KeyShare.WritePublicKey(ref buffer); return(buffer); }
public void write(string s, WritableBuffer header) { }
protected virtual bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { throw new NotImplementedException(); }
public Benchmarks() { _buffer = new byte[1024]; _stream = new MemoryStream(_buffer); _writer = new WritableBuffer(_buffer, () => new byte[1024], buf => { }); }
public abstract void HandleHandshakeMessage(HandshakeType handshakeMessageType, ReadableBuffer buffer, ref WritableBuffer outBuffer);
public TcpWriteBatch() { byte[] bytes = Encoding.UTF8.GetBytes(Content); this.dataBuffer = WritableBuffer.From(bytes); this.writeCount = 0; }
public void StartHandshake(ref WritableBuffer writer) { this.WriteHandshake(ref writer, HandshakeType.client_hello, Hello.WriteClientHello); _helloBuffer = writer.AsReadableBuffer().ToArray(); State = StateType.WaitServerHello; }
private Uv.uv_buf_t OnAlloc(UvStreamHandle handle, int status) { _inputBuffer = _input.Alloc(2048); return(handle.Libuv.buf_init(_inputBuffer.Memory.BufferPtr, _inputBuffer.Memory.Length)); }
private void WriteEndResponse(WritableBuffer buffer) { buffer.Write(_chunkedEndBytes); }
public abstract void Encrypt(ref WritableBuffer writer, Span <byte> plainText, RecordType recordType, TlsVersion tlsVersion);
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: public boolean visit(WritableBuffer key, WritableBuffer value) throws java.io.IOException public bool visit(WritableBuffer key, WritableBuffer value) { throw new IOException("boom!"); }
private static void WriteHeaders(HttpHeaders headers, ref WritableBuffer buffer) { foreach (var header in headers) { buffer.Append($"{header.Key}:{string.Join(",", header.Value)}\r\n", TextEncoding.Utf8); } }
protected virtual bool Read(ReadableBuffer readableBuffer, WritableBuffer writableBuffer, out ReadCursor consumed, out ReadCursor examined) { throw new NotImplementedException(); }
private async void ReceiveFromSocketAndPushToWriterAsync() { SocketAsyncEventArgs args = null; try { // if the consumer says they don't want the data, we need to shut down the receive GC.KeepAlive(_input.Writing.ContinueWith(delegate {// GC.KeepAlive here just to shut the compiler up try { Socket.Shutdown(SocketShutdown.Receive); } catch { } })); // wait for someone to be interested in data before we // start allocating buffers and probing the socket await _input.ReadingStarted; args = GetOrCreateSocketAsyncEventArgs(); while (!_input.Writing.IsCompleted) { bool haveWriteBuffer = false; WritableBuffer buffer = default(WritableBuffer); var initialSegment = default(ArraySegment <byte>); try { int bytesFromInitialDataBuffer = 0; if (Socket.Available == 0) { // now, this gets a bit messy unfortunately, because support for the ideal option // (zero-length reads) is platform dependent switch (_bufferStyle) { case BufferStyle.Unknown: try { initialSegment = await ReceiveInitialDataUnknownStrategyAsync(args); } catch { initialSegment = default(ArraySegment <byte>); } if (initialSegment.Array == null) { continue; // redo from start } break; case BufferStyle.UseZeroLengthBuffer: // if we already have a buffer, use that (but: zero count); otherwise use a shared // zero-length; this avoids constantly changing the buffer that the args use, which // avoids some overheads args.SetBuffer(args.Buffer ?? _zeroLengthBuffer, 0, 0); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); break; case BufferStyle.UseSmallBuffer: // We need to do a speculative receive with a *cheap* buffer while we wait for input; it would be *nice* if // we could do a zero-length receive, but this is not supported equally on all platforms (fine on Windows, but // linux hates it). The key aim here is to make sure that we don't tie up an entire block from the memory pool // waiting for input on a socket; fine for 1 socket, not so fine for 100,000 sockets // do a short receive while we wait (async) for data initialSegment = LeaseSmallBuffer(); args.SetBuffer(initialSegment.Array, initialSegment.Offset, initialSegment.Count); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); break; } if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } // note we can't check BytesTransferred <= 0, as we always // expect 0; but if we returned, we expect data to be // buffered *on the socket*, else EOF if ((bytesFromInitialDataBuffer = args.BytesTransferred) <= 0) { if (ReferenceEquals(initialSegment.Array, _zeroLengthBuffer)) { // sentinel value that means we should just // consume sync (we expect there to be data) initialSegment = default(ArraySegment <byte>); } else { // socket reported EOF RecycleSmallBuffer(ref initialSegment); } if (Socket.Available == 0) { // yup, definitely an EOF break; } } } // note that we will try to coalesce things here to reduce the number of flushes; we // certainly want to coalesce the initial buffer (from the speculative receive) with the initial // data, but we probably don't want to buffer indefinitely; for now, it will buffer up to 4 pages // before flushing (entirely arbitrarily) - might want to make this configurable later buffer = _input.Alloc(SmallBufferSize * 2); haveWriteBuffer = true; const int FlushInputEveryBytes = 4 * MemoryPool.MaxPooledBlockLength; if (initialSegment.Array != null) { // need to account for anything that we got in the speculative receive if (bytesFromInitialDataBuffer != 0) { buffer.Write(new Span <byte>(initialSegment.Array, initialSegment.Offset, bytesFromInitialDataBuffer)); } // make the small buffer available to other consumers RecycleSmallBuffer(ref initialSegment); } bool isEOF = false; while (Socket.Available != 0 && buffer.BytesWritten < FlushInputEveryBytes) { buffer.Ensure(); // ask for *something*, then use whatever is available (usually much much more) SetBuffer(buffer.Memory, args); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); // either way, need to validate if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } int len = args.BytesTransferred; if (len <= 0) { // socket reported EOF isEOF = true; break; } // record what data we filled into the buffer buffer.Advance(len); } if (isEOF) { break; } } finally { RecycleSmallBuffer(ref initialSegment); if (haveWriteBuffer) { await buffer.FlushAsync(); } } } _input.CompleteWriter(); } catch (Exception ex) { // don't trust signal after an error; someone else could // still have it and invoke Set if (args != null) { args.UserToken = null; } _input?.CompleteWriter(ex); } finally { RecycleSocketAsyncEventArgs(args); } }
public void WriteMessage(ref WritableBuffer buffer) { buffer.WriteBigEndian(MessageId); }
private unsafe Uv.uv_buf_t OnAlloc(UvStreamHandle handle, int status) { _inputBuffer = _input.Alloc(2048); void* pointer; if (!_inputBuffer.Memory.TryGetPointer(out pointer)) { throw new InvalidOperationException("Pointer must be pinned"); } return handle.Libuv.buf_init((IntPtr)pointer, _inputBuffer.Memory.Length); }
public static void WriteAsciiString(this WritableBuffer buffer, string value) => WriteString(buffer, value, ASCIIEncoding);
public WriteableBufferFormatter(ref WritableBuffer writableBuffer, FormattingData formattingData) { _writableBuffer = writableBuffer; FormattingData = formattingData; }
public static void WriteUtf8String(this WritableBuffer buffer, string value) => WriteString(buffer, value, Utf8Encoding);
protected override bool Read(ReadOnlyBuffer readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position examined) { consumed = default(Position); examined = default(Position); while (_mode < Mode.Trailer) { if (_mode == Mode.Prefix) { ParseChunkedPrefix(readableBuffer, out consumed, out examined); if (_mode == Mode.Prefix) { return(false); } readableBuffer = readableBuffer.Slice(consumed); } if (_mode == Mode.Extension) { ParseExtension(readableBuffer, out consumed, out examined); if (_mode == Mode.Extension) { return(false); } readableBuffer = readableBuffer.Slice(consumed); } if (_mode == Mode.Data) { ReadChunkedData(readableBuffer, writableBuffer, out consumed, out examined); if (_mode == Mode.Data) { return(false); } readableBuffer = readableBuffer.Slice(consumed); } if (_mode == Mode.Suffix) { ParseChunkedSuffix(readableBuffer, out consumed, out examined); if (_mode == Mode.Suffix) { return(false); } readableBuffer = readableBuffer.Slice(consumed); } } // Chunks finished, parse trailers if (_mode == Mode.Trailer) { ParseChunkedTrailer(readableBuffer, out consumed, out examined); if (_mode == Mode.Trailer) { return(false); } readableBuffer = readableBuffer.Slice(consumed); } // _consumedBytes aren't tracked for trailer headers, since headers have seperate limits. if (_mode == Mode.TrailerHeaders) { if (_context.TakeMessageHeaders(readableBuffer, out consumed, out examined)) { _mode = Mode.Complete; } } return(_mode == Mode.Complete); }
// REVIEW: See if we can use IFormatter here public static void WriteUInt32(this WritableBuffer buffer, uint value) => WriteUInt64(buffer, value);