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); }
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); }
static void WriteHeader(GameBinaryWriter writer, PacketHeader header) { writer.Position = 0; writer.WriteUInt16((ushort)(header.Length + PacketHeader.HeaderSize)); writer.WriteUInt16(header.Code); }
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); } }
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); } } }
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()); }
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()); }
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); }
protected abstract void OnSerialize(GameBinaryWriter writer, PacketInfo info, SerializablePacket packet);
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); }