Beispiel #1
0
 protected override void PreProcessRaw(ArraySegment <byte> data)
 {
     if (mode == Modes.WebSocket)
     {
         if (wsWaitHeader == false)
         {
             if (wsHeader.Mask)
             {
                 wsHeader.UnmaskData(data.Array, data.Offset,
                                     Math.Min(data.Count, wsHeader.PayloadLength - wsMaskIndex), ref wsMaskIndex);
             }
         }
     }
 }
        // Receive frames, unmask them.
        // Should handle pings/pongs internally.
        // Should parse out Close frames.
        public async Task <WebSocketReceiveTuple> ReceiveAsync(ArraySegment <byte> buffer, CancellationToken cancel)
        {
            if (currentHeader == null)
            {
                var  header          = new WebSocketHeader();
                byte headerReadState = 1;                // skip initialization

                byte[] headerBuffer    = new byte[14];
                int    headerBytesRead = 0;
                int    headerLength    = 2;

                while (true)
                {
                    if (headerReadState == 0)                     // re-initialize
                    {
                        // create buffer big enough to hold the complete header
                        headerBuffer    = new byte[14];
                        headerBytesRead = 0;
                        headerLength    = 2;
                        headerReadState = 1;
                    }

                    var count = await stream.ReadAsync(headerBuffer, headerBytesRead, headerLength - headerBytesRead, cancel);

                    headerBytesRead += count;
                    if (headerBytesRead < headerLength)
                    {
                        continue;
                    }

                    if (headerReadState == 1)                     // read first 2 bytes
                    {
                        header.Fin      = ((headerBuffer[0] >> 7) & 0x01) == 1;
                        header.OpCode   = (MessageType)((headerBuffer[0] >> 0) & 0x0f);
                        header.Mask     = ((headerBuffer[1] >> 7) & 0x01) == 1;
                        headerReadState = 2;
                    }

                    if (headerReadState == 2)                     // read length
                    {
                        ulong len = (ulong)(headerBuffer[1] >> 0) & 0x7f;

                        if (header.PayloadLength == 126)
                        {
                            headerLength = 4;
                            if (headerBytesRead < headerLength)
                            {
                                continue;
                            }
                            len = (ulong)(headerBuffer[2] * 0x100) + headerBuffer[3];
                        }
                        else if (len == 127)
                        {
                            headerLength = 10;
                            if (headerBytesRead < headerLength)
                            {
                                continue;
                            }
                            len = (ulong)(headerBuffer[6] * 0x1000000) +
                                  (ulong)(headerBuffer[7] * 0x10000) +
                                  (ulong)(headerBuffer[8] * 0x100) + (ulong)headerBuffer[9];
                        }

                        header.PayloadLength = len;
                        headerReadState      = 3;                    // length received
                    }

                    if (header.Mask && headerReadState >= 3)                     // read masking-key
                    {
                        if (headerReadState == 3)
                        {
                            headerLength   += 4;
                            headerReadState = 4;
                        }

                        if (headerBytesRead < headerLength)
                        {
                            continue;
                        }
                        header.MaskingKey[0] = headerBuffer[headerLength - 4];
                        header.MaskingKey[1] = headerBuffer[headerLength - 3];
                        header.MaskingKey[2] = headerBuffer[headerLength - 2];
                        header.MaskingKey[3] = headerBuffer[headerLength - 1];
                    }

                    // received header
                    Console.WriteLine("fin:{0} opcode:{1} mask:{2} len:{3} controlframe:{4}", header.Fin, header.OpCode, header.Mask, header.PayloadLength, header.IsControlFrame);

                    if (header.IsControlFrame)
                    {
                        // See RFC 6455 section 5.5
                        // can safely cast to int because control frames have max payload length of 125
                        int controlFrameLength    = (int)header.PayloadLength;
                        var controlFrameBuffer    = new byte[controlFrameLength];
                        var controlFrameBytesRead = 0;

                        while (controlFrameBytesRead < controlFrameLength)
                        {
                            controlFrameBytesRead += await stream.ReadAsync(controlFrameBuffer, controlFrameBytesRead, controlFrameLength - controlFrameBytesRead, cancel);
                        }

                        header.UnmaskData(new ArraySegment <byte>(controlFrameBuffer, 0, controlFrameLength));

                        // TODO: read data (ping/pong-content)

                        switch (header.OpCode)
                        {
                        case MessageType.Close:
                            if (controlFrameLength >= 2)
                            {
                                this.Environment[OwinConstants.WebSocket.ClientCloseStatus] = (controlFrameBuffer[0] * 0x100) + controlFrameBuffer[1];
                                if (controlFrameLength > 2)
                                {
                                    this.Environment[OwinConstants.WebSocket.ClientCloseDescription] = Encoding.UTF8.GetString(controlFrameBuffer, 2, controlFrameLength - 2);
                                }
                            }
                            return(new WebSocketReceiveTuple((int)MessageType.Close, true, 0));

                        case MessageType.Ping:
                        case MessageType.Pong:
                            throw new NotImplementedException();                                     // TODO
                        }

                        headerReadState = 0;                         // receive next header
                    }
                    else
                    {
                        currentHeader = header;
                        break;
                    }
                }
            }

            // now receive payload
            int maxBytes;

            if (currentHeader.PayloadLength > int.MaxValue)
            {
                maxBytes = int.MaxValue;
            }
            else
            {
                maxBytes = (int)currentHeader.PayloadLength;
            }

            if (buffer.Count < maxBytes)
            {
                maxBytes = buffer.Count;
            }

            int bytes = await stream.ReadAsync(buffer.Array, buffer.Offset, maxBytes, cancel);

            // unmask it
            if (currentHeader.Mask)
            {
                // TODO: handle unaligned offset?
                currentHeader.UnmaskData(buffer);
            }

            currentHeader.PayloadReceived += (ulong)bytes;

            bool endOfFrame   = currentHeader.PayloadReceived >= currentHeader.PayloadLength;
            bool endOfMessage = endOfFrame && currentHeader.Fin;

            int messageType = (int)currentHeader.OpCode;

            if (endOfFrame)
            {
                currentHeader = null;                 // forget last header
            }
            return(new WebSocketReceiveTuple(messageType, endOfMessage, bytes));
        }
Beispiel #3
0
		// Receive frames, unmask them.
		// Should handle pings/pongs internally.
		// Should parse out Close frames.
		public async Task<WebSocketReceiveTuple> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancel)
		{
			if (currentHeader == null)
			{
				var header = new WebSocketHeader();
				byte headerReadState = 1;// skip initialization

				byte[] headerBuffer = new byte[14];
				int headerBytesRead = 0; 
				int headerLength = 2;

				while (true)
				{
					if (headerReadState == 0) // re-initialize
					{
						// create buffer big enough to hold the complete header
						headerBuffer = new byte[14];
						headerBytesRead = 0;
						headerLength = 2;
						headerReadState = 1;
					}

					var count = await stream.ReadAsync(headerBuffer, headerBytesRead, headerLength - headerBytesRead, cancel);
					headerBytesRead += count;
					if (headerBytesRead < headerLength)
					{
						continue;
					}

					if (headerReadState == 1) // read first 2 bytes
					{
						header.Fin = ((headerBuffer[0] >> 7) & 0x01) == 1;
						header.OpCode = (MessageType)((headerBuffer[0] >> 0) & 0x0f);
						header.Mask = ((headerBuffer[1] >> 7) & 0x01) == 1;
						headerReadState = 2;
					}

					if (headerReadState == 2) // read length
					{
						ulong len = (ulong)(headerBuffer[1] >> 0) & 0x7f;

						if (header.PayloadLength == 126)
						{
							headerLength = 4;
							if (headerBytesRead < headerLength)
							{
								continue;
							}
							len = (ulong)(headerBuffer[2] * 0x100) + headerBuffer[3];
						}
						else if (len == 127)
						{
							headerLength = 10;
							if (headerBytesRead < headerLength)
							{
								continue;
							}
							len = (ulong)(headerBuffer[6] * 0x1000000) +
									(ulong)(headerBuffer[7] * 0x10000) +
										(ulong)(headerBuffer[8] * 0x100) + (ulong)headerBuffer[9];
						}

						header.PayloadLength = len;
						headerReadState = 3; // length received
					}

					if (header.Mask && headerReadState >= 3) // read masking-key
					{
						if (headerReadState == 3)
						{
							headerLength += 4;
							headerReadState = 4;
						}
					
						if (headerBytesRead < headerLength)
						{
							continue;
						}
						header.MaskingKey[0] = headerBuffer[headerLength - 4];
						header.MaskingKey[1] = headerBuffer[headerLength - 3];
						header.MaskingKey[2] = headerBuffer[headerLength - 2];
						header.MaskingKey[3] = headerBuffer[headerLength - 1];
					}

					// received header
					Console.WriteLine("fin:{0} opcode:{1} mask:{2} len:{3} controlframe:{4}", header.Fin, header.OpCode, header.Mask, header.PayloadLength, header.IsControlFrame);

					if (header.IsControlFrame)
					{
						// See RFC 6455 section 5.5
						// can safely cast to int because control frames have max payload length of 125
						int controlFrameLength = (int)header.PayloadLength;
						var controlFrameBuffer = new byte[controlFrameLength];
						var controlFrameBytesRead = 0;

						while (controlFrameBytesRead < controlFrameLength)
						{
							controlFrameBytesRead += await stream.ReadAsync(controlFrameBuffer, controlFrameBytesRead, controlFrameLength - controlFrameBytesRead, cancel);
						}

						header.UnmaskData(new ArraySegment<byte>(controlFrameBuffer, 0, controlFrameLength));

						// TODO: read data (ping/pong-content)

						switch (header.OpCode)
						{
							case MessageType.Close:
								if (controlFrameLength >= 2)
								{
									this.Environment[OwinConstants.WebSocket.ClientCloseStatus] = (controlFrameBuffer[0] * 0x100) + controlFrameBuffer[1];
									if (controlFrameLength > 2)
									{
										this.Environment[OwinConstants.WebSocket.ClientCloseDescription] = Encoding.UTF8.GetString(controlFrameBuffer, 2, controlFrameLength - 2);
									}
								}
								return new WebSocketReceiveTuple((int)MessageType.Close, true, 0);
							case MessageType.Ping:
							case MessageType.Pong:
								throw new NotImplementedException(); // TODO
						}

						headerReadState = 0; // receive next header
					}
					else
					{
						currentHeader = header;
						break;
					}
				}
			}

			// now receive payload
			int maxBytes;
			if (currentHeader.PayloadLength > int.MaxValue)
				maxBytes = int.MaxValue;
			else
				maxBytes = (int)currentHeader.PayloadLength;

			if (buffer.Count < maxBytes)
				maxBytes = buffer.Count;

			int bytes = await stream.ReadAsync(buffer.Array, buffer.Offset, maxBytes, cancel);

			// unmask it
			if (currentHeader.Mask)
			{
				// TODO: handle unaligned offset?
				currentHeader.UnmaskData(buffer);
			}

			currentHeader.PayloadReceived += (ulong)bytes;

			bool endOfFrame = currentHeader.PayloadReceived >= currentHeader.PayloadLength;
			bool endOfMessage = endOfFrame && currentHeader.Fin;

			int messageType = (int)currentHeader.OpCode;

			if (endOfFrame)
				currentHeader = null; // forget last header

			return new WebSocketReceiveTuple(messageType, endOfMessage, bytes);
		}