/// <summary> /// Starts a thread that times out connections or sends keep alive packets /// </summary> public void StartCleanupThread() { if (isDoingCleanup) { return; } isDoingCleanup = true; Task.Run(() => { while (true) { TimeoutConnections(); KeepClientAlivePacket kcap = new KeepClientAlivePacket(); lock (connected) { for (int i = 0; i < connected.Length; i++) { if (connected[i] != null && TimeUtils.GetTimestamp() - connected[i].LastSentPacketTimestamp > 1) { listener.Send(kcap, connected[i].Client); } } } Thread.Sleep(100); } }, cts.Token); }
/// <summary> /// Initializes serverobject with IP /// </summary> /// <param name="useLocalhost">Whether the server should use 127.0.0.1 ip or use its actual outgoing one</param> public Server(bool useLocalhost = false) { WorldManager.OnServer = true; isDisposed = false; isDoingCleanup = false; IPAddress ip; if (useLocalhost) { ip = IPAddress.Parse("127.0.0.1"); } else { ip = GetIP(); } IPEndPoint iep = new IPEndPoint(ip, PORT); listener = new CustomUdpClient(PORT); listener.PacketRecieved += PacketReceived; pending = new Connection[PENDING_SLOTS]; connected = new Connection[CONNECTED_SLOTS]; games = new Game[GAME_SLOTS]; packetCallbacks = new Dictionary <Type, Action <Packet> >() { { typeof(StringPacket), (Packet p) => { StringPacket sp = (StringPacket)p; Console.WriteLine(sp.Content); } }, { typeof(ConnectPacket), (Packet p) => { int connectionIndex = GetConnectionIndexFromIEP(pending, p.Sender); ChallengePacket challenge; ConnectPacket cp = (ConnectPacket)p; if (connectionIndex == -1) { int i = GetFirstFreeIndex(pending); if (i == -1) { listener.Send(new DeclineConnectPacket(), p.Sender); return; } challenge = new ChallengePacket(cp.ClientSalt); pending[i] = new Connection(cp.Sender, cp.ClientSalt, challenge.ServerSalt); pending[i].RefreshRecievedPacketTimestamp(); } else { Connection c = pending[connectionIndex]; c.ClientSalt = cp.ClientSalt; challenge = new ChallengePacket(c.ClientSalt, c.ServerSalt); c.RefreshRecievedPacketTimestamp(); } listener.Send(challenge, p.Sender); } }, { typeof(ChallengeResponsePacket), (Packet p) => { int connectionIndex = GetConnectionIndexFromIEP(pending, p.Sender); if (connectionIndex == -1) { return; } Connection c = pending[connectionIndex]; ChallengeResponsePacket crp = (ChallengeResponsePacket)p; if (crp.Xored == c.Xored) // response packet was correct { pending[connectionIndex] = null; connectionIndex = GetFirstFreeIndex(connected); if (connectionIndex == -1) { listener.Send(new DeclineConnectPacket(), p.Sender); return; } connected[connectionIndex] = c; c.RefreshRecievedPacketTimestamp(); KeepClientAlivePacket kcap = new KeepClientAlivePacket(); listener.Send(kcap, p.Sender); return; } listener.Send(new DeclineConnectPacket(), p.Sender); } } }; connectedPacketCallbacks = new Dictionary <Type, Action <SaltedPacket, Connection> >() { { typeof(KeepAlivePacket), (SaltedPacket p, Connection c) => { c.RefreshRecievedPacketTimestamp(); } }, { typeof(QueuePacket), (SaltedPacket p, Connection c) => { int gameIndex = GetGameIndexFromIep(p.Sender); int gameId = -1; if (gameIndex != -1) { gameId = games[gameIndex].Id; } else { lock (games) { foreach (Game g in games) { if (g != null && g.AddConnection(c)) { gameId = g.Id; break; } } if (gameId == -1) { int newGameIndex = GetFirstFreeIndex(games); if (newGameIndex != -1) { Game g = new Game(); games[newGameIndex] = g; g.AddConnection(c); gameId = g.Id; g.StartHandle(SendPacket); g.GameEnded += (object sender, EventArgs e) => { lock (games) games[newGameIndex] = null; }; } } } } QueueResponsePacket qrp = new QueueResponsePacket(gameId); listener.Send(qrp, p.Sender); c.RefreshSentPacketTimestamp(); } }, { typeof(GetGameInfoPacket), (SaltedPacket p, Connection c) => { int gameIndex = GetGameIndexFromIep(c.Client); if (gameIndex == -1) { return; } Game g = games[gameIndex]; GameInfoPacket ggip = new GameInfoPacket(g); listener.Send(ggip, p.Sender); c.RefreshSentPacketTimestamp(); } }, { typeof(InputPacket), (SaltedPacket p, Connection c) => { int gameIndex = GetGameIndexFromIep(c.Client); if (gameIndex == -1) { SendPacket(new QueueResponsePacket(-1), c.Client); return; } Game g = games[gameIndex]; InputPacket inpt = (InputPacket)p; g.HandleInputPacket(inpt, c); } } }; }