private int TryFillAndReadInternalBuffer(BytesSegment bs) { var readBufferSize = this.ReadaheadBufferSize; if (EnableReadaheadBuffer && (socketAvailable > bs.Len & bs.Len < readBufferSize)) { if (readaheadScore > 0) { readaheadScore--; } if (readaheadBuffer.Bytes == null) { if (readaheadScore > 0) { return(0); } readaheadBuffer.Bytes = new byte[readBufferSize]; } else if (readaheadBuffer.Bytes.Length < readBufferSize) { readaheadBuffer.Bytes = new byte[readBufferSize]; } Interlocked.Increment(ref ctr.Rsync); readaheadBuffer.Offset = 0; readaheadBuffer.Len = readBufferSize; var read = ReadSocketDirectSync(readaheadBuffer); readaheadBuffer.Len = read; if (read <= 0) { throw new Exception($"{this} should not happen: Socket.Receive() returns {read} when Socket.Available > 0."); } read = Math.Min(read, bs.Len); readaheadBuffer.CopyTo(bs, read); readaheadBuffer.SubSelf(read); return(read); } else { if (readaheadScore < readaheadScoreMax) { if (++readaheadScore == readaheadScoreMax) { // There are many large reading opearations, so the internal buffer can be released now. readaheadBuffer.Bytes = null; } } return(0); } }
public async Task <int> ReadAsync(BytesSegment bs) { lock (_syncRoot) { if (tcsNewBuffer?.IsCompleted == false) { throw new Exception("another recv task is running."); } if (buffer.Len == 0 & !recvEOF) { tcsNewBuffer.Reset(); } } if (tcsNewBuffer != null) { await tcsNewBuffer; } lock (_syncRoot) { if (recvEOF && buffer.Len == 0) { return(0); } int read = Math.Min(bs.Len, buffer.Len); buffer.CopyTo(bs, 0, read); buffer.SubSelf(read); if (buffer.Len == 0) { buffer = new BytesSegment(); tcsBufferEmptied.SetResult(0); } return(read); } }
private void Dequeue(BytesSegment bs, int len) { Queue.CopyTo(bs, len); Queue.SubSelf(len); if (Queue.Len == 0) { Queue.ResetSelf(); } }
public AwaitableWrapper WriteAsyncR(BytesSegment bs) { var rSync = TryWriteNonblocking(bs); if (rSync == bs.Len) { Interlocked.Increment(ref ctr.Wsync); return(AwaitableWrapper.GetCompleted()); } bs.SubSelf(Math.Max(rSync, 0)); return(WriteAsyncRImpl(bs)); }
public override Task WriteAsync(BytesSegment bs) { var rSync = TryWriteNonblocking(bs); if (rSync == bs.Len) { Interlocked.Increment(ref ctr.Wsync); return(NaiveUtils.CompletedTask); } bs.SubSelf(Math.Max(rSync, 0)); return(WriteAsyncImpl(bs)); }
public static void ParseServerHelloRecord(BytesSegment bs, ref ServerHello ch, out int size) { var payloadLen = GetRecordPayloadLength(bs, ref ch.Version); size = 5 + payloadLen; if (bs.Len < size) { return; } bs.SubSelf(5); bs.Len = Math.Min(bs.Len, payloadLen); ParseServerHello(bs, ref ch); }
private static void ParseServerHello(BytesSegment msg, ref ServerHello hello) { var cur = 0; if (msg[cur] != 2) { throw new Exception("Expected server hello (2), got " + msg[cur]); } cur++; var msgLength = msg[cur] << 16 | msg[cur + 1] << 8 | msg[cur + 2]; cur += 3; msg.SubSelf(4); cur = 0; hello.Version = (ushort)(msg[cur] << 8 | msg[cur + 1]); cur += 2; cur += 32; // skip random cur += 1 + msg[cur]; // skip session_id cur += 2; // skip cipher suite cur += 1; // compression_methods if (cur >= msgLength) { throw new Exception("extensionsBegin >= msgLength"); } var extensionsLength = msg[cur] << 8 | msg[cur + 1]; cur += 2; var extensionsEnd = cur + extensionsLength; if (extensionsEnd > msgLength) { throw new Exception("extensionsEnd > msgLength"); } while (cur < extensionsEnd) { var extType = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var extLen = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var extEnd = cur + extLen; if (extEnd > extensionsEnd) { throw new Exception("extEnd > extensionsEnd"); } if (extType == 0) // server_name { hello.SniUsed = true; } else if (extType == 16) // ALPN { var listLen = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var listEnd = cur + listLen; if (listEnd > extEnd) { throw new Exception("alpnListEnd > extEnd"); } if (cur < listEnd) // read the first item only { var strLen = msg[cur++]; if (cur + strLen > listEnd) { throw new Exception("alpnStrEnd > nameListEnd"); } hello.Alpn = Encoding.ASCII.GetString(msg.Bytes, msg.Offset + cur, strLen); } } else if (extType == 43) // supported_versions { if (extLen != 2) { throw new Exception("supported_versions extLen != 2"); } var ver = (ushort)(msg[cur] << 8 | msg[cur + 1]); cur += 2; hello.Version = ver; } cur = extEnd; } return; }
private static void ParseClientHello(BytesSegment msg, ref ClientHello ch) { var cur = 0; if (msg[cur] != 1) { throw new Exception("Expected client hello (1), got " + msg[cur]); } cur++; var msgLength = msg[cur] << 16 | msg[cur + 1] << 8 | msg[cur + 2]; cur += 3; msg.SubSelf(4); cur = 0; ch.Version = (ushort)(msg[cur] << 8 | msg[cur + 1]); cur += 2; cur += 32; // skip random cur += 1 + msg[cur]; // skip session_id cur += 2 + (msg[cur] << 8 | msg[cur + 1]); // skip cipher_suites cur += 1 + msg[cur]; // skip compression_methods if (cur >= msgLength) { throw new Exception("extensionsBegin >= msgLength"); } var extensionsLength = msg[cur] << 8 | msg[cur + 1]; cur += 2; var extensionsEnd = cur + extensionsLength; if (extensionsEnd > msgLength) { throw new Exception("extensionsEnd > msgLength"); } while (cur < extensionsEnd) { var extType = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var extLen = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var extEnd = cur + extLen; if (extEnd > extensionsEnd) { throw new Exception("extEnd > extensionsEnd"); } if (extType == 0) // server_name { var nameListLen = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var nameListEnd = cur + nameListLen; if (nameListEnd > extEnd) { throw new Exception("nameListEnd > extEnd"); } var nameList = new List <string>(); if (cur < nameListEnd) // read the first item only { if (msg[cur++] != 0) // name_type: host_name { throw new Exception("Not supported name type " + msg[cur]); } var nameLen = (msg[cur] << 8 | msg[cur + 1]); cur += 2; if (cur + nameLen > nameListEnd) { throw new Exception("nameEnd > nameListEnd"); } var str = NaiveUtils.UTF8Encoding.GetString(msg.Bytes, msg.Offset + cur, nameLen); // TODO: check encoding ch.Sni = str; } } else if (extType == 16) // ALPN { var listLen = (msg[cur] << 8 | msg[cur + 1]); cur += 2; var listEnd = cur + listLen; if (listEnd > extEnd) { throw new Exception("alpnListEnd > extEnd"); } if (cur < listEnd) // read the first item only { var strLen = msg[cur++]; if (cur + strLen > listEnd) { throw new Exception("alpnStrEnd > nameListEnd"); } ch.Alpn = Encoding.ASCII.GetString(msg.Bytes, msg.Offset + cur, strLen); } } else if (extType == 43) // supported_versions { var listLen = msg[cur++]; if (listLen < 2) { throw new Exception("listLen < 2"); } var listEnd = cur + listLen; if (listEnd > extEnd) { throw new Exception("supported_versions listEnd > extEnd"); } while (cur < listEnd) { var ver = (ushort)(msg[cur] << 8 | msg[cur + 1]); cur += 2; if (ver > ch.Version) { ch.Version = ver; } } } cur = extEnd; } return; }