/// <summary> /// Create packet from received bytes. /// Use this for buffers that contain multiple packets. /// The stxIndex and etxIndex will tell you where the extracted packet was located within the provided buffer. /// </summary> /// <param name="buffer"></param> /// <param name="stxIndex">Start of the packet within the provided byte array.</param> /// <param name="etxIndex">End of the packet within the provided byte array.</param> /// <returns></returns> public static NetworkPacket FromByteArray(byte[] buffer, out int stxIndex, out int etxIndex) { etxIndex = -1; stxIndex = -1; NetworkPacket packet = null; if (buffer == null) { return(null); } // Do a sweep and unescape the packet var rawByteList = new List <byte>(buffer.Length); for (int i = 0; i < buffer.Length; ++i) { if (stxIndex < 0) { if (buffer[i] == STX) { stxIndex = i; rawByteList.Add(buffer[i]); } continue; } if (buffer[i] == ETX) { etxIndex = i; rawByteList.Add(buffer[i]); break; } if (buffer[i] == ESC) { rawByteList.Add((byte)(buffer[++i] ^ MASK)); } else { rawByteList.Add(buffer[i]); } } var rawBytes = rawByteList.ToArray(); // Check if packet is valid: // Incomplete if (stxIndex == -1 || etxIndex == -1) { return(null); } // Too short if (rawBytes.Length < 6) { return(null); } // Length check var length = rawBytes[1] << 8 | rawBytes[2]; if (length != rawBytes.Length - 6) { return(null); } // Checksum check var chsumIndex = rawBytes.Length - 2; var sum = 0; for (int i = 2; i < chsumIndex; ++i) { sum ^= rawBytes[i]; } if (sum != rawBytes[chsumIndex]) { return(null); } var type = rawBytes[3]; var data = new byte[length]; Array.Copy(rawBytes, 4, data, 0, length); packet = new NetworkPacket(data, type); return(packet); }
/// <summary> /// Processes received packets. /// </summary> /// <param name="packet">Received packet.</param> void ProcessPacket(NetworkPacket packet) { // Decrypt data var data = packet.Data; if (data != null && data.Length > 0 && packet.PacketType != NetworkPacketType.PublicKey) { if (packet.PacketType != NetworkPacketType.ServerInfo) { data = _decrypter.Decrypt(packet.Data); } if (data == null) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Error! Could not decrypt message from server"); return; } } switch (packet.PacketType) { case NetworkPacketType.PublicKey: try { var serverPubKey = Encoding.ASCII.GetString(packet.Data); _encrypter = new CryptoHelper(serverPubKey); } catch (Exception ex) { _encrypter = null; Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received key is invalid! " + ex.Message); } #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable CC0004 // Catch block cannot be empty finally { try { _encrypterWaiter?.Cancel(); } catch { /* Ignore*/ } } #pragma warning restore CC0004 // Catch block cannot be empty #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body break; case NetworkPacketType.ListGames: try { var glistString = Encoding.ASCII.GetString(data); var glist = JsonConvert.DeserializeObject <List <GameInfo> >(glistString); Log.WriteLine(LogPriority.Verbose, "NetworkGameClient: Received list of games on server. Game count: " + glist.Count); GameListReceived?.Invoke(this, new GameListEventArgs(glist)); } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received list of games from server could not be read. " + e.Message); } break; case NetworkPacketType.ClientLogin: try { if (data.Length > 0 && data[0] == 0) { IsLoggedIn = true; Log.WriteLine(LogPriority.Information, "NetworkGameClient: Login to server successful!"); } else { IsLoggedIn = false; var error = "NetworkGameClient: Login to server failed! "; if (data[0] == 1) { error += "Invalid user name"; } else if (data[0] == 2) { error += "Invalid password"; } else if (data[0] == 3) { error += "Database error"; } else { error += "Unknown error"; } } LoggedIn?.Invoke(this, new LoggedInEventArgs(IsLoggedIn == true)); } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received login confirmation could not be read." + e.Message); } break; case NetworkPacketType.CreateGame: try { // Check if an UID was assigned var ginfo = JsonConvert.DeserializeObject <GameInfo>(Encoding.ASCII.GetString(data)); if (ginfo != null) { if (ginfo.UID != 0) { GameCreated?.Invoke(this, new GameCreatedEventArgs(ginfo)); } } else { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received CreateGame confirmation could not be read."); } } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received CreateGame confirmation could not be read." + e.Message); } break; case NetworkPacketType.JoinGame: try { var jMsg = JsonConvert.DeserializeObject <JoinMessage>(Encoding.ASCII.GetString(data)); if (jMsg != null) { GameJoinRequested?.Invoke(this, new GameJoinRequestedEventArgs(jMsg)); // If joining and other side declined then set IsJoined to false if (jMsg.Request == JoinRequestType.Decline) { IsJoined = false; } } } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received JoinGame confirmation could not be read." + e.Message); } break; case NetworkPacketType.ServerInfo: try { // Server data is always unencrypted var jMsg = JsonConvert.DeserializeObject <ServerInfo>(Encoding.ASCII.GetString(packet.Data)); if (jMsg != null) { ServerRequiresLogin = jMsg.RequiresLogin; ServerInfoReceived?.Invoke(this, new ServerInfoEventArgs(jMsg)); } } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received ServerInfo could not be read." + e.Message); } break; case NetworkPacketType.ExitGame: try { var eMsg = JsonConvert.DeserializeObject <ExitGame>(Encoding.ASCII.GetString(data)); if (eMsg != null) { if (eMsg.UID == UID) { IsJoined = false; UID = 0; GameExitReceived?.Invoke(this, EventArgs.Empty); } } } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received ExitGame message could not be read." + e.Message); } break; case NetworkPacketType.GameSync: try { var eMsg = JsonConvert.DeserializeObject <GameSync>(Encoding.ASCII.GetString(data)); if (eMsg != null && eMsg.UID == UID) { GameSyncReceived?.Invoke(this, new GameSyncEventArgs(eMsg)); } } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received GameSync message could not be read." + e.Message); } break; case NetworkPacketType.GameCommand: try { var eMsg = JsonConvert.DeserializeObject <GameCommand>(Encoding.ASCII.GetString(data)); if (eMsg != null) { GameCommandReceived?.Invoke(this, new GameCommandEventArgs(eMsg)); } } catch (Exception e) { Log.WriteLine(LogPriority.Error, "NetworkGameClient: Received GameSync message could not be read." + e.Message); } break; default: Log.WriteLine(LogPriority.Error, "NetworkGameClient: Packet type " + packet.PacketType + " not recognized!"); break; } }