示例#1
0
        /// <summary>
        /// Triggers after completion of asynchronous datastream reading has completed transmitting data
        /// </summary>
        /// <param name="Result">Represents the status of an asynchronous operation</param>
        private void ReadPacket(IAsyncResult Result)
        {
            //Read in the size of the payload data, making sure the connection is still opened
            int PacketSize = -1;

            try { PacketSize = DataStream.EndRead(Result); }
            //Print an error message, flag the client as dead and exit the function if any exception occurs
            catch (IOException Exception)
            {
                MessageLog.Error(Exception, "Error reading packet size, connection no longer open.");
                ConnectionDead = true;
                return;
            }

            //Copy the data buffer over into a new array and reset the buffer array for reading in the next packet
            byte[] PacketBuffer = new byte[PacketSize];
            Array.Copy(DataBuffer, PacketBuffer, PacketSize);
            DataBuffer = new byte[Connection.Available];
            //Immediately start reading packets again from the client back into the data buffer, making sure the connection is still open
            try { DataStream.BeginRead(DataBuffer, 0, DataBuffer.Length, ReadPacket, null); }
            //Print an error, flag the client as dead and exit the function if any exception occurs
            catch (IOException Exception)
            {
                MessageLog.Error(Exception, "Error registering packet reader function, client connection no longer open.");
                ConnectionDead = true;
                return;
            }

            //If the connection is new then complete the handshake and upgrade the connection to websockets
            if (!ConnectionUpgraded)
            {
                UpgradeConnection(PacketBuffer);
            }
            //Otherwise we need to extract the packet data from the buffer and decode it so we can read and process the messages within
            else if (PacketSize > 0)
            {
                //Visit https://tools.ietf.org/html/rfc6455#section-5.2 for more information on how this decoding works
                //Lets first extract the data from the first byte
                byte   FirstByte = PacketBuffer[0];
                bool   FIN       = DataExtractor.ReadBit(FirstByte, 0); //Value of 1 indicates if this is the final fragment of the message, this first fragment MAY also be the final fragment
                bool   RSV1      = DataExtractor.ReadBit(FirstByte, 1); //Set to 0 unless an extension is negotatied that defines meanings for non-zero values. Unexpected non-zero values means we should close down the connection.
                bool   RSV2      = DataExtractor.ReadBit(FirstByte, 2);
                bool   RSV3      = DataExtractor.ReadBit(FirstByte, 3);
                bool[] OpCode    = DataExtractor.ReadBits(FirstByte, 4, 7);

                //Extracting the second byte from the packet buffer
                byte SecondByte = PacketBuffer[1];
                bool MASK       = DataExtractor.ReadBit(SecondByte, 0);

                //Before we go any further we need to figure out the size of the payload data, as this may effect where we read the rest of the data from
                //Converting the 2nd byte to a binary string, then converting bits 1-7 to decimal gives us the first possible length value of the payload data
                string SecondByteBinary = BinaryConverter.ByteToBinaryString(PacketBuffer[1]);
                string PayloadBinary    = SecondByteBinary.Substring(1, 7);
                int    PayloadLength    = BinaryConverter.BinaryStringToDecimal(PayloadBinary);

                //Byte indices where we will begin reading in the decoding mask and payload data later on, these will be updated if we needed to read extra bytes to find out the payload length
                int DecodingMaskIndex = 2;
                int PayloadDataIndex  = 6;

                //PayloadLength between 0-125 represents the actual length value
                //With a length equal to 126, we read bytes 2-3 to find the length value
                if (PayloadLength == 126)
                {
                    //Bytes 2 and 3 interpreted as 16bit unsigned integer give the PayloadLength
                    byte[] LengthBytes = DataExtractor.ReadBytes(PacketBuffer, 2, 3);
                    PayloadBinary = BinaryConverter.ByteArrayToBinaryString(LengthBytes);
                    PayloadLength = BinaryConverter.BinaryStringToDecimal(PayloadBinary);
                    //Increment the DecodingMask and PayloadData indices by 2, as 3,4 contained the payload length
                    DecodingMaskIndex += 2;
                    PayloadDataIndex  += 2;
                }
                //Write a length equal to 127, we read bytes 2-9 to find the length value
                else if (PayloadLength == 127)
                {
                    //Bytes 2-9 interpreted as a 64bit unsigned integer give the PayloadLength
                    byte[] LengthBytes = DataExtractor.ReadBytes(PacketBuffer, 2, 9);
                    PayloadBinary      = BinaryConverter.ByteArrayToBinaryString(LengthBytes);
                    PayloadLength      = BinaryConverter.BinaryStringToDecimal(PayloadBinary);
                    DecodingMaskIndex += 8;
                    PayloadDataIndex  += 8;
                }

                //Extract the decoding mask bytes from the packet buffer
                byte[] DecodingMask = new byte[4] {
                    PacketBuffer[DecodingMaskIndex], PacketBuffer[DecodingMaskIndex + 1], PacketBuffer[DecodingMaskIndex + 2], PacketBuffer[DecodingMaskIndex + 3]
                };

                //Extract the payload data from the packet buffer, using the mask to decode each byte as we extract it from the packet buffer
                byte[] PayloadData = new byte[PayloadLength];
                for (int i = 0; i < PayloadLength; i++)
                {
                    PayloadData[i] = (byte)(PacketBuffer[PayloadDataIndex + i] ^ DecodingMask[i % 4]);
                }

                //Convert the PayloadData array into an ASCII string
                string FinalMessage = Encoding.ASCII.GetString(PayloadData);

                //If the FinalMessage value comes through as "\u0003?" then the connection has been closed from the client side, so we need to set
                //them as dead so they get cleaned up by the simulation
                if (FinalMessage == "\u0003?")
                {
                    ConnectionDead = true;
                }
                //Otherwise we just pass the message onto the packet handler as normal so it can be processed accordingly
                else
                {
                    PacketHandler.ReadClientPacket(ClientID, FinalMessage);
                }
            }
        }