Пример #1
0
        internal GameClient(GameProxy proxy, Socket socket)
        {
            Proxy         = proxy;
            EndPoint      = (IPEndPoint)socket.RemoteEndPoint;
            _clientSocket = socket;
            _serverSocket = new Socket(proxy.Info.RealEndPoint.AddressFamily,
                                       SocketType.Stream, ProtocolType.Tcp);

            void SetOptions(Socket socket)
            {
                socket.NoDelay        = true;
                socket.ReceiveTimeout = socket.SendTimeout = (int)proxy.Timeout.TotalMilliseconds;
            }

            SetOptions(_clientSocket);
            SetOptions(_serverSocket);

            _clientSendWriter = new GameBinaryWriter(_clientSendBuffer.GetArray());
            _serverSendWriter = new GameBinaryWriter(_serverSendBuffer.GetArray());

            var args = proxy.ArgsPool.Get();

            args.Completed     += OnConnect;
            args.RemoteEndPoint = Proxy.Info.RealEndPoint;

            proxy.AddClient(this);

            Connect(args);
        }
Пример #2
0
        internal static void WriteHeader(PacketHeader header, byte[] buffer)
        {
            using var writer = new GameBinaryWriter(buffer);

            writer.WriteUInt16((ushort)(header.Length + PacketHeader.HeaderSize));
            writer.WriteUInt16(header.Code);
        }
Пример #3
0
        static void WriteHeader(GameBinaryWriter writer, PacketHeader header)
        {
            writer.Position = 0;

            writer.WriteUInt16((ushort)(header.Length + PacketHeader.HeaderSize));
            writer.WriteUInt16(header.Code);
        }
Пример #4
0
        public PacketLogWriter(Region region, GameMessageTable gameMessages, SystemMessageTable systemMessages,
                               ServerInfo[] servers, string directory, string fileNameFormat, bool compress)
        {
            if (servers == null)
            {
                throw new ArgumentNullException(nameof(servers));
            }

            if (servers.Any(x => x == null))
            {
                throw new ArgumentException("A null server was given.", nameof(servers));
            }

            if (fileNameFormat == null)
            {
                throw new ArgumentNullException(nameof(fileNameFormat));
            }

            IsCompressed   = compress;
            Region         = region.CheckValidity(nameof(region));
            GameMessages   = gameMessages ?? throw new ArgumentNullException(nameof(gameMessages));
            SystemMessages = systemMessages ?? throw new ArgumentNullException(nameof(systemMessages));
            Servers        = servers.ToDictionary(x => x.Id);

            Directory.CreateDirectory(directory);

            Stream stream = File.Open(
                Path.Combine(directory, DateTime.Now.ToString(fileNameFormat) + ".pkt"),
                FileMode.Create, FileAccess.Write);

            var magic = PacketLogEntry.Magic.ToArray();

            stream.Write(magic, 0, magic.Length);
            stream.WriteByte((byte)(compress ? 6 : 0));

            if (compress)
            {
                stream = new DeflateStream(stream, CompressionLevel.Optimal);
            }

            _writer = new GameBinaryWriter(stream);

            _writer.WriteUInt32(Version);
            _writer.WriteByte((byte)Region);
            _writer.WriteUInt32(GameMessages.Version);
            _writer.WriteUInt32((uint)servers.Length);

            foreach (var server in servers)
            {
                _writer.WriteInt32(server.Id);
                _writer.WriteString(server.Name);
                _writer.WriteBoolean(server.RealEndPoint.AddressFamily == AddressFamily.InterNetworkV6);
                _writer.WriteBytes(server.RealEndPoint.Address.GetAddressBytes());
                _writer.WriteUInt16((ushort)server.RealEndPoint.Port);
                _writer.WriteBytes(server.ProxyEndPoint.Address.GetAddressBytes());
                _writer.WriteUInt16((ushort)server.ProxyEndPoint.Port);
            }
        }
Пример #5
0
        bool SendPacketInternal(Direction direction, SerializablePacket packet, Memory <byte> buffer,
                                GameBinaryWriter writer, Socket socket, GameEncryptionSession encryption, bool server,
                                bool direct)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            var payload = Proxy.Serializer.Serialize(packet).AsMemory();

            if (payload.Length > PacketHeader.MaxPayloadSize)
            {
                throw new ArgumentException("Packet is too large.", nameof(packet));
            }

            var code     = Proxy.Serializer.GameMessages.NameToCode[packet.Name];
            var original = payload;
            var send     = Proxy.InvokeSent(this, direction, code, ref payload, direct);

            if (!send)
            {
                return(false);
            }

            // A handler might have created a packet that's too large.
            if (payload.Length > PacketHeader.MaxPayloadSize)
            {
                _log.Error(
                    "{0}: Forged packet {1} is too large ({2} bytes) to be sent correctly after running handlers; sending original",
                    direction.ToDirectionString(), packet.Name, payload.Length);

                payload = original;
            }

            lock (socket)
            {
                var header = new PacketHeader((ushort)payload.Length, code);

                WriteHeader(writer, header);
                payload.CopyTo(buffer.Slice(PacketHeader.HeaderSize, header.Length));

                try
                {
                    return(SendInternal(buffer.Slice(0, header.FullLength), false, socket, encryption, server));
                }
                catch (SocketDisconnectedException)
                {
                    // Normal disconnection.
                    return(false);
                }
            }
        }
Пример #6
0
        public byte[] Serialize(SerializablePacket packet)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            packet.OnSerialize(this);

            using var writer = new GameBinaryWriter();

            OnSerialize(writer, _byType[packet.GetType()], packet);

            return(writer.ToArray());
        }
Пример #7
0
        public byte[] Serialize(SerializablePacket packet)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            if (!_byType.TryGetValue(packet.GetType(), out var info))
            {
                throw new UnmappedMessageException();
            }

            packet.OnSerialize(this);

            using var writer = new GameBinaryWriter();

            OnSerialize(writer, info, packet);

            return(writer.ToArray());
        }
Пример #8
0
        void Receive(Direction direction, Memory <byte> headerBuffer, GameBinaryReader headerReader,
                     GameBinaryWriter headerWriter, Memory <byte> payloadBuffer, bool nested)
        {
            if (headerBuffer.IsEmpty)
            {
                var arr = new byte[PacketHeader.HeaderSize];

                headerBuffer = arr;
                headerReader = new GameBinaryReader(arr);
                headerWriter = new GameBinaryWriter(arr);
            }

            if (payloadBuffer.IsEmpty)
            {
                payloadBuffer = new byte[PacketHeader.MaxPayloadSize];
            }

            Socket from;
            Socket to;
            GameEncryptionSession fromEnc;
            GameEncryptionSession toEnc;

            if (direction == Direction.ClientToServer)
            {
                from    = _clientSocket;
                to      = _serverSocket;
                fromEnc = _clientEncryption;
                toEnc   = _serverEncryption;
            }
            else
            {
                from    = _serverSocket;
                to      = _clientSocket;
                fromEnc = _serverEncryption;
                toEnc   = _clientEncryption;
            }

            var toServer   = to == _serverSocket;
            var fromServer = to == _serverSocket;

            bool DoReceive()
            {
                try
                {
                    ReceiveInternal(headerBuffer, from, fromEnc, fromServer);

                    var header = ReadHeader(headerReader);

                    if (header.Length > PacketHeader.MaxPayloadSize)
                    {
                        DisconnectInternal();
                        _log.Error("Disconnected client {0} from {1} due to invalid packet length: {2}",
                                   EndPoint, Proxy.Info.Name, header.Length);
                        return(false);
                    }

                    var payload = payloadBuffer.Slice(0, header.Length);

                    ReceiveInternal(payload, from, fromEnc, fromServer);

                    var original = payload;
                    var send     = Proxy.InvokeReceived(this, direction, header.Code, ref payload);

                    if (send)
                    {
                        // A handler might have created a packet that's too large.
                        if (payload.Length > PacketHeader.MaxPayloadSize)
                        {
                            Proxy.Serializer.GameMessages.CodeToName.TryGetValue(header.Code,
                                                                                 out var name);

                            if (name == null)
                            {
                                name = header.Code.ToString();
                            }

                            _log.Error(
                                "{0}: Packet {1} is too large ({2} bytes) to be sent correctly; sending original",
                                direction.ToDirectionString(), name, payload.Length);

                            payload = original;
                        }

                        header = new PacketHeader((ushort)payload.Length, header.Code);

                        WriteHeader(headerWriter, header);

                        var headerSlice = headerBuffer.Slice(0, PacketHeader.HeaderSize);

                        SendInternal(headerSlice, true, to, toEnc, toServer);
                        SendInternal(payload, true, to, toEnc, toServer);
                    }
                }
                catch (SocketDisconnectedException)
                {
                    // Normal disconnection.
                    Disconnect();
                    return(false);
                }
                catch (Exception e) when(IsSocketException(e))
                {
                    // The client is already disconnected.
                    return(false);
                }

                return(true);
            }

            // If we don't expect a large number of clients, just use dedicated
            // tasks to receive data instead of spawning a new one per receive.
            if (!nested && Proxy.MaxClients <= Environment.ProcessorCount)
            {
                Task.Factory.StartNew(() =>
                {
                    while (DoReceive())
                    {
                    }

                    headerReader.Dispose();
                    headerWriter.Dispose();
                }, TaskCreationOptions.LongRunning);
            }
            else
            {
                Task.Run(() =>
                {
                    if (!DoReceive())
                    {
                        headerReader.Dispose();
                        headerWriter.Dispose();
                    }
                    else
                    {
                        Receive(direction, headerBuffer, headerReader, headerWriter, payloadBuffer, true);
                    }
                });
            }
        }
 protected override void OnSerialize(GameBinaryWriter writer, PacketInfo info,
                                     SerializablePacket packet)
 {
     _serializers[info](writer, packet);
 }
Пример #10
0
 protected abstract void OnSerialize(GameBinaryWriter writer, PacketInfo info,
                                     SerializablePacket packet);
Пример #11
0
        public void Start()
        {
            var dispatch = _context.Dispatch;

            dispatch.AddHandler("S_SPAWN_ME", (client, direction, packet, flags) =>
            {
                // Automatically join a chat channel when logging in.

                _log.Info("Making client {0} join chat channel {1} with password {2}",
                          client.EndPoint, ChatChannelName, ChatChannelPassword);

                using var writer = new GameBinaryWriter();

                writer.WriteOffset(sizeof(ushort) * 2);
                writer.WriteUInt16(ChatChannelPassword);
                writer.WriteString(ChatChannelName);

                client.SendToServer(new RawPacket("C_JOIN_PRIVATE_CHANNEL")
                {
                    Payload = writer.ToArray(),
                });

                // Let's request an absurdly low visibility range.

                _log.Info("Setting visibility range for client {0} to {1}", client.EndPoint,
                          VisibilityRange);

                client.SendToServer(new CSetVisibleRangePacket
                {
                    Range = VisibilityRange,
                });

                return(true);
            });

            dispatch.AddHandler("S_INVEN", (client, direction, packet, flags) =>
            {
                // Deny opening the inventory for the client.

                _log.Info("Denying inventory list for client {0}", client.EndPoint);

                return(false);
            });

            dispatch.AddHandler <CCheckVersionPacket>((client, direction, packet, flags) =>
            {
                foreach (var ver in packet.Versions)
                {
                    _log.Info("Client reported version: {0}", ver.Value);
                }

                return(true);
            });

            dispatch.AddHandler <CSocialPacket>((client, direction, packet, flags) =>
            {
                // Only allow the dance emote.

                _log.Info("Client {0} requested emote {1}; sending {2}",
                          client.EndPoint, packet.SocialId, DanceId);

                packet.SocialId = DanceId;

                return(true);
            });

            _log.Basic("Simple test plugin started");
        }
        void SerializeObject(GameBinaryWriter writer, object source)
        {
            var offsets = new List <(ReflectionPacketFieldInfo, int)>();

            foreach (var info in GetPacketInfo(source.GetType()).Fields.Cast <ReflectionPacketFieldInfo>())
            {
                if (info.IsByteArray)
                {
                    offsets.Add((info, writer.Position));
                    writer.WriteUInt16(0);
                    writer.WriteUInt16((ushort)((List <byte>)info.Property.GetValue(source)).Count);
                }
                else if (info.IsArray)
                {
                    writer.WriteUInt16((ushort)((IList)info.Property.GetValue(source)).Count);
                    offsets.Add((info, writer.Position));
                    writer.WriteUInt16(0);
                }
                else if (info.IsString)
                {
                    offsets.Add((info, writer.Position));
                    writer.WriteUInt16(0);
                }
                else
                {
                    info.PrimitiveSerializer(writer, info.Property.GetValue(source));
                }
            }

            foreach (var(info, offset) in offsets)
            {
                if (info.IsByteArray)
                {
                    var list = (List <byte>)info.Property.GetValue(source);

                    if (list.Count == 0)
                    {
                        continue;
                    }

                    writer.Seek(offset, (w, op) => w.WriteOffset(op));
                    writer.WriteBytes(list.ToArray());
                }
                else if (info.IsArray)
                {
                    var list = (IList)info.Property.GetValue(source);

                    if (list.Count == 0)
                    {
                        continue;
                    }

                    writer.Seek(offset, (w, op) => w.WriteOffset(op));

                    for (var i = 0; i < list.Count; i++)
                    {
                        var pos = writer.Position;

                        writer.WriteOffset(pos);
                        writer.WriteUInt16(0);

                        SerializeObject(writer, list[i]);

                        if (i != list.Count - 1)
                        {
                            writer.Seek(pos + sizeof(ushort), (w, op) => w.WriteOffset(op));
                        }
                    }
                }
                else
                {
                    writer.Seek(offset, (w, op) => w.WriteOffset(op));
                    writer.WriteString((string)info.Property.GetValue(source));
                }
            }
        }
 protected override void OnSerialize(GameBinaryWriter writer, PacketInfo info,
                                     SerializablePacket packet)
 {
     SerializeObject(writer, packet);
 }