예제 #1
0
        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);
            }
        }
예제 #2
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);
     }
 }
예제 #3
0
 private void Dequeue(BytesSegment bs, int len)
 {
     Queue.CopyTo(bs, len);
     Queue.SubSelf(len);
     if (Queue.Len == 0)
     {
         Queue.ResetSelf();
     }
 }
예제 #4
0
        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));
        }
예제 #5
0
        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));
        }
예제 #6
0
        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);
        }
예제 #7
0
        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;
        }
예제 #8
0
        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;
        }