예제 #1
0
        public bool TryHandshake(Connection conn)
        {
            Stream stream = conn.stream;

            using (ArrayBuffer getHeader = bufferPool.Take(GetSize)) {
                if (!ReadHelper.TryRead(stream, getHeader.array, 0, GetSize))
                {
                    return(false);
                }
                getHeader.count = GetSize;


                if (!IsGet(getHeader.array))
                {
                    Log.Warn($"First bytes from client was not 'GET' for handshake, instead was {Log.BufferToString(getHeader.array, 0, GetSize)}");
                    return(false);
                }
            }


            string msg = ReadToEndForHandshake(stream);

            if (string.IsNullOrEmpty(msg))
            {
                return(false);
            }

            try {
                AcceptHandshake(stream, msg);
                return(true);
            } catch (ArgumentException e) {
                Log.InfoException(e);
                return(false);
            }
        }
예제 #2
0
        public bool TryHandshake(Connection conn, Uri uri)
        {
            try {
                Stream stream = conn.stream;

                byte[] keyBuffer = new byte[16];
                using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) {
                    rng.GetBytes(keyBuffer);
                }

                string key         = Convert.ToBase64String(keyBuffer);
                string keySum      = key + Constants.HandshakeGUID;
                byte[] keySumBytes = Encoding.ASCII.GetBytes(keySum);
                Log.Verbose($"Handshake Hashing {Encoding.ASCII.GetString(keySumBytes)}");

                byte[] keySumHash = SHA1.Create().ComputeHash(keySumBytes);

                string expectedResponse = Convert.ToBase64String(keySumHash);
                string handshake        =
                    $"GET /chat HTTP/1.1\r\n" +
                    $"Host: {uri.Host}:{uri.Port}\r\n" +
                    $"Upgrade: websocket\r\n" +
                    $"Connection: Upgrade\r\n" +
                    $"Sec-WebSocket-Key: {key}\r\n" +
                    $"Sec-WebSocket-Version: 13\r\n" +
                    "\r\n";
                byte[] encoded = Encoding.ASCII.GetBytes(handshake);
                stream.Write(encoded, 0, encoded.Length);

                byte[] responseBuffer = new byte[1000];

                int?lengthOrNull = ReadHelper.SafeReadTillMatch(stream, responseBuffer, 0, responseBuffer.Length, Constants.endOfHandshake);

                if (!lengthOrNull.HasValue)
                {
                    Log.Error("Connected closed before handshake");
                    return(false);
                }

                string responseString = Encoding.ASCII.GetString(responseBuffer, 0, lengthOrNull.Value);

                string acceptHeader = "Sec-WebSocket-Accept: ";
                int    startIndex   = responseString.IndexOf(acceptHeader) + acceptHeader.Length;
                int    endIndex     = responseString.IndexOf("\r\n", startIndex);
                string responseKey  = responseString.Substring(startIndex, endIndex - startIndex);

                if (responseKey != expectedResponse)
                {
                    Log.Error($"Response key incorrect, Response:{responseKey} Expected:{expectedResponse}");
                    return(false);
                }

                return(true);
            } catch (Exception e) {
                Log.Exception(e);
                return(false);
            }
        }
예제 #3
0
        static bool ReadOneMessage(Config config, byte[] buffer)
        {
            (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config;
            Stream stream = conn.stream;

            int offset = 0;

            // read 2
            offset = ReadHelper.Read(stream, buffer, offset, Constants.HeaderMinSize);
            // log after first blocking call
            Log.Verbose($"Message From {conn}");

            if (MessageProcessor.NeedToReadShortLength(buffer))
            {
                offset = ReadHelper.Read(stream, buffer, offset, Constants.ShortLength);
            }


            MessageProcessor.ValidateHeader(buffer, maxMessageSize, expectMask);

            if (expectMask)
            {
                offset = ReadHelper.Read(stream, buffer, offset, Constants.MaskSize);
            }

            int opcode        = MessageProcessor.GetOpcode(buffer);
            int payloadLength = MessageProcessor.GetPayloadLength(buffer);

            Log.Verbose($"Header ln:{payloadLength} op:{opcode} mask:{expectMask}");

            offset = ReadHelper.Read(stream, buffer, offset, payloadLength);

            int msgOffset = offset - payloadLength;

            Log.DumpBuffer($"Raw Header", buffer, 0, msgOffset);
            switch (opcode)
            {
            case 2:
                HandleArrayMessage(config, buffer, msgOffset, payloadLength);
                break;

            case 8:
                HandleCloseMessage(config, buffer, msgOffset, payloadLength);
                break;
            }

            return(true);
        }
예제 #4
0
        string ReadToEndForHandshake(Stream stream)
        {
            using (ArrayBuffer readBuffer = bufferPool.Take(maxHttpHeaderSize)) {
                int?readCountOrFail = ReadHelper.SafeReadTillMatch(stream, readBuffer.array, 0, maxHttpHeaderSize, Constants.endOfHandshake);
                if (!readCountOrFail.HasValue)
                {
                    return(null);
                }

                int readCount = readCountOrFail.Value;

                string msg = Encoding.ASCII.GetString(readBuffer.array, 0, readCount);
                Log.Verbose(msg);

                return(msg);
            }
        }
예제 #5
0
        static Header ReadHeader(Config config, byte[] buffer, bool opCodeContinuation = false)
        {
            (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config;
            Stream stream = conn.stream;
            Header header = new Header();

            // read 2
            header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.HeaderMinSize);
            // log after first blocking call
            Log.Verbose($"Message From {conn}");

            if (MessageProcessor.NeedToReadShortLength(buffer))
            {
                header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.ShortLength);
            }
            if (MessageProcessor.NeedToReadLongLength(buffer))
            {
                header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.LongLength);
            }

            Log.DumpBuffer($"Raw Header", buffer, 0, header.offset);

            MessageProcessor.ValidateHeader(buffer, maxMessageSize, expectMask, opCodeContinuation);

            if (expectMask)
            {
                header.offset = ReadHelper.Read(stream, buffer, header.offset, Constants.MaskSize);
            }

            header.opcode        = MessageProcessor.GetOpcode(buffer);
            header.payloadLength = MessageProcessor.GetPayloadLength(buffer);
            header.finished      = MessageProcessor.Finished(buffer);

            Log.Verbose($"Header ln:{header.payloadLength} op:{header.opcode} mask:{expectMask}");

            return(header);
        }
예제 #6
0
        static void ReadOneMessage(Config config, byte[] buffer)
        {
            (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue <Message> queue, BufferPool bufferPool) = config;
            Stream stream = conn.stream;

            Header header = ReadHeader(config, buffer);

            int msgOffset = header.offset;

            header.offset = ReadHelper.Read(stream, buffer, header.offset, header.payloadLength);

            if (header.finished)
            {
                switch (header.opcode)
                {
                case 2:
                    HandleArrayMessage(config, buffer, msgOffset, header.payloadLength);
                    break;

                case 8:
                    HandleCloseMessage(config, buffer, msgOffset, header.payloadLength);
                    break;
                }
            }
            else
            {
                // todo cache this to avoid allocations
                Queue <ArrayBuffer> fragments = new Queue <ArrayBuffer>();
                fragments.Enqueue(CopyMessageToBuffer(bufferPool, expectMask, buffer, msgOffset, header.payloadLength));
                int totalSize = header.payloadLength;

                while (!header.finished)
                {
                    header = ReadHeader(config, buffer, opCodeContinuation: true);

                    msgOffset     = header.offset;
                    header.offset = ReadHelper.Read(stream, buffer, header.offset, header.payloadLength);
                    fragments.Enqueue(CopyMessageToBuffer(bufferPool, expectMask, buffer, msgOffset, header.payloadLength));

                    totalSize += header.payloadLength;
                    MessageProcessor.ThrowIfMsgLengthTooLong(totalSize, maxMessageSize);
                }


                ArrayBuffer msg = bufferPool.Take(totalSize);
                msg.count = 0;
                while (fragments.Count > 0)
                {
                    ArrayBuffer part = fragments.Dequeue();

                    part.CopyTo(msg.array, msg.count);
                    msg.count += part.count;

                    part.Release();
                }

                // dump after mask off
                Log.DumpBuffer($"Message", msg);

                queue.Enqueue(new Message(conn.connId, msg));
            }
        }