/// <summary>
        /// Create an encoder with the target initial buffer size.
        /// </summary>
        /// <param name="compress">True to compress collated data.</param>
        /// <param name="initialBufferSize">The initial buffer size (bytes).</param>
        public CollatedPacketEncoder(bool compress, int initialBufferSize = 64 * 1024)
        {
            CollatedBytes    = 0;
            _collationStream = _dataStream = new CompressionBuffer(initialBufferSize);
            _packet          = new PacketBuffer();

            // Prime the output stream, writing the initial header.
            PacketHeader header = PacketHeader.Create((ushort)RoutingID.CollatedPacket, 0);

            CollatedPacketMessage msg = new CollatedPacketMessage();

            msg.Flags             = (ushort)((compress) ? CollatedPacketFlag.GZipCompressed : 0u);
            msg.Reserved          = 0;
            msg.UncompressedBytes = 0;

            NetworkWriter writer = new NetworkWriter(_dataStream);

            header.Write(writer);
            msg.Write(writer);

            _resetPosition = (int)_dataStream.Position;

            CompressionEnabled = compress;
            if (compress)
            {
                _collationStream = new GZipStream(_dataStream, CompressionMode.Compress, CompressionLevel.BestCompression);
            }
        }
Пример #2
0
        private void OnWorldSendGameNumber(byte[] packet, Channel channel)
        {
            var game = Serialize <WorldSendGameNumber>(packet);

            _myPlayer = game.Name;
            Send(Deserialize <PacketHeader>(PacketHeader.Create(PacketCommand.C2S_QueryStatusReq, 0)));
        }
Пример #3
0
        private void OnSyncVersionAns(byte[] packet, Channel channel)
        {
            if (!_gameStarted)
            {
                var answer = Serialize <SynchVersionAns>(packet);

                //Log.Write("Setting up for game mode: {0}", answer.GameMode);

                _isOdin = answer.GameMode.Equals("ODIN");

                // yay linq!
                var player = answer.players.ToList().Find(p => p.userId == _mySummonerId);
                _isOrder = player.teamId == 0x64;

                Send(Deserialize <PacketHeader>(PacketHeader.Create(PacketCommand.C2S_ClientReady, 0)), Channel.LoadingScreen);

                var ping = PingLoadInfo.Create(100, 2, _mySummonerId);
                Send(Deserialize <PingLoadInfo>(ping));
                Send(Deserialize <PacketHeader>(PacketHeader.Create(PacketCommand.C2S_CharLoaded, 0)));
                Send(Deserialize <StartGame>(StartGame.Create()));
            }
        }
Пример #4
0
        private void FinaliseOutput(BinaryWriter writer, uint frameCount)
        {
            // Rewind the stream to the beginning and find the first RoutingID.ServerInfo message
            // and RoutingID.Control message with a ControlMessageID.FrameCount ID. These should be
            // the first and second messages in the stream.
            // We'll limit searching to the first 5 messages.
            long serverInfoMessageStart = -1;
            long frameCountMessageStart = -1;

            writer.Flush();

            // Extract the stream from the writer. The first stream may be a GZip stream, in which case we must
            // extract the stream that is writing to instead as we can't rewind compression streams
            // and we wrote the header raw.
            writer.BaseStream.Flush();

            Stream          outStream = null;
            CollationStream zipStream = writer.BaseStream as CollationStream;

            if (zipStream != null)
            {
                outStream = zipStream.BaseStream;
                zipStream.Flush();
            }
            else
            {
                outStream = writer.BaseStream;
            }

            // Check we are allowed to seek the stream.
            if (!outStream.CanSeek)
            {
                // Stream does not support seeking. The frame count will not be fixed.
                return;
            }

            // Record the initial stream position to restore later.
            long restorePos = outStream.Position;

            outStream.Seek(0, SeekOrigin.Begin);

            long streamPos = 0;

            byte[]       headerBuffer = new byte[PacketHeader.Size];
            PacketHeader header       = new PacketHeader();

            byte[] markerValidationBytes = BitConverter.GetBytes(Tes.IO.Endian.ToNetwork(PacketHeader.PacketMarker));
            byte[] markerBytes           = new byte[markerValidationBytes.Length];
            bool   markerValid           = false;

            int attemptsRemaining = 5;
            int byteReadLimit     = 0;

            markerBytes[0] = 0;
            while ((frameCountMessageStart < 0 || serverInfoMessageStart < 0) && attemptsRemaining > 0 && outStream.CanRead)
            {
                --attemptsRemaining;
                markerValid = false;

                // Limit the number of bytes we try read in each attempt.
                byteReadLimit = 1024;
                while (byteReadLimit > 0)
                {
                    --byteReadLimit;
                    outStream.Read(markerBytes, 0, 1);
                    if (markerBytes[0] == markerValidationBytes[0])
                    {
                        markerValid = true;
                        int i = 1;
                        for (i = 1; markerValid && outStream.CanRead && i < markerValidationBytes.Length; ++i)
                        {
                            outStream.Read(markerBytes, i, 1);
                            markerValid = markerValid && markerBytes[i] == markerValidationBytes[i];
                        }

                        if (markerValid)
                        {
                            break;
                        }
                        else
                        {
                            // We've failed to fully validate the maker. However, we did read and validate
                            // one byte in the marker, then continued reading until the failure. It's possible
                            // that the last byte read, the failed byte, may be the start of the actual marker.
                            // We check this below, and if so, we rewind the stream one byte in order to
                            // start validation from there on the next iteration. We can ignore the byte if
                            // it is does not match the first validation byte. We are unlikely to ever make this
                            // match though.
                            --i; // Go back to the last read byte.
                            if (markerBytes[i] == markerValidationBytes[0])
                            {
                                // Potentially the start of a new marker. Rewind the stream to attempt to validate it.
                                outStream.Seek(-1, SeekOrigin.Current);
                            }
                        }
                    }
                }

                if (markerValid && outStream.CanRead)
                {
                    // Potential packet target. Record the stream position at the start of the marker.
                    streamPos = outStream.Position - markerBytes.Length;
                    outStream.Seek(streamPos, SeekOrigin.Begin);

                    // Test the packet.
                    int bytesRead = outStream.Read(headerBuffer, 0, headerBuffer.Length);
                    if (bytesRead == headerBuffer.Length)
                    {
                        // Create a packet.
                        if (header.Read(new NetworkReader(new MemoryStream(headerBuffer, false))))
                        {
                            // Header is OK. Looking for RoutingID.Control
                            if (header.RoutingID == (ushort)RoutingID.ServerInfo)
                            {
                                serverInfoMessageStart = streamPos;
                            }
                            else if (header.RoutingID == (ushort)RoutingID.Control)
                            {
                                // It's control message. Complete and validate the packet.
                                // Read the header. Determine the expected size and read that much more data.
                                PacketBuffer packet = new PacketBuffer(header.PacketSize + Crc16.CrcSize);
                                packet.Emplace(headerBuffer, bytesRead);
                                packet.Emplace(outStream, header.PacketSize + Crc16.CrcSize - bytesRead);
                                if (packet.Status == PacketBufferStatus.Complete)
                                {
                                    // Packet complete. Extract the control message.
                                    NetworkReader  packetReader = new NetworkReader(packet.CreateReadStream(true));
                                    ControlMessage message      = new ControlMessage();
                                    if (message.Read(packetReader) && header.MessageID == (ushort)ControlMessageID.FrameCount)
                                    {
                                        // Found the message location.
                                        frameCountMessageStart = streamPos;
                                    }
                                }
                            }
                            else
                            {
                                // At this point, we've failed to find the right kind of header. We could use the payload size to
                                // skip ahead in the stream which should align exactly to the next message.
                                // Not done for initial testing.
                            }
                        }
                    }
                }
            }

            if (serverInfoMessageStart >= 0)
            {
                // Found the correct location. Seek the stream to here and write a new FrameCount control message.
                outStream.Seek(serverInfoMessageStart, SeekOrigin.Begin);
                PacketBuffer packet = new PacketBuffer();

                header = PacketHeader.Create((ushort)RoutingID.ServerInfo, 0);

                packet.WriteHeader(header);
                _serverInfo.Write(packet);
                packet.FinalisePacket();
                BinaryWriter patchWriter = new Tes.IO.NetworkWriter(outStream);
                packet.ExportTo(patchWriter);
                patchWriter.Flush();
            }

            if (frameCountMessageStart >= 0)
            {
                // Found the correct location. Seek the stream to here and write a new FrameCount control message.
                outStream.Seek(frameCountMessageStart, SeekOrigin.Begin);
                PacketBuffer   packet        = new PacketBuffer();
                ControlMessage frameCountMsg = new ControlMessage();

                header = PacketHeader.Create((ushort)RoutingID.Control, (ushort)ControlMessageID.FrameCount);

                frameCountMsg.ControlFlags = 0;
                frameCountMsg.Value32      = frameCount; // Placeholder. Frame count is currently unknown.
                frameCountMsg.Value64      = 0;
                packet.WriteHeader(header);
                frameCountMsg.Write(packet);
                packet.FinalisePacket();
                BinaryWriter patchWriter = new Tes.IO.NetworkWriter(outStream);
                packet.ExportTo(patchWriter);
                patchWriter.Flush();
            }

            if (outStream.Position != restorePos)
            {
                outStream.Seek(restorePos, SeekOrigin.Begin);
            }
        }