/// <summary> /// Start the lobby server link. /// </summary> public override void Start() { base.Start(); if (mTcp == null) { mTcp = new TcpProtocol(); mTcp.name = "Link"; } mNextConnect = 0; }
/// <summary> /// Start the lobby server link. /// </summary> public override void Start() { base.Start(); #if FORCE_EN_US Tools.SetCurrentCultureToEnUS(); #endif if (mTcp == null) { mTcp = new TcpProtocol(); mTcp.name = "Link"; } mNextConnect = 0; }
/// <summary> /// Thread that will be processing incoming data. /// </summary> void ThreadFunction() { for (; ; ) { mTime = DateTime.Now.Ticks / 10000; // Accept incoming connections while (mListener != null && mListener.Pending()) { TcpProtocol tc = new TcpProtocol(); tc.data = (long)(-1); tc.StartReceiving(mListener.AcceptSocket()); mTcp.Add(tc); } Buffer buffer = null; // Process incoming TCP packets for (int i = 0; i < mTcp.size; ++i) { TcpProtocol tc = mTcp[i]; while (tc.ReceivePacket(out buffer)) { try { if (!ProcessPacket(buffer, tc)) { RemoveServer(tc); tc.Disconnect(); } } #if STANDALONE catch (System.Exception ex) { Console.WriteLine("ERROR: " + ex.Message); RemoveServer(tc); tc.Disconnect(); } #else catch (System.Exception) { RemoveServer(tc); tc.Disconnect(); } #endif if (buffer != null) { buffer.Recycle(); buffer = null; } } } // We only want to send instant updates if the number of players is under a specific threshold if (mTcp.size > instantUpdatesClientLimit) mInstantUpdates = false; // Send the server list to all connected clients for (int i = 0; i < mTcp.size; ++i) { TcpProtocol tc = mTcp[i]; long customTimestamp = (long)tc.data; // Timestamp of -1 means we don't want updates to be sent if (tc.stage != TcpProtocol.Stage.Connected || customTimestamp == -1) continue; // If timestamp was set then the list was already sent previously if (customTimestamp != 0) { // List hasn't changed -- do nothing if (customTimestamp >= mLastChange) continue; // Too many clients: we want the updates to be infrequent if (!mInstantUpdates && customTimestamp + 4000 > mTime) continue; } // Create the server list packet if (buffer == null) { buffer = Buffer.Create(); BinaryWriter writer = buffer.BeginPacket(Packet.ResponseServerList); mList.WriteTo(writer); buffer.EndPacket(); } tc.SendTcpPacket(buffer); tc.data = mTime; } if (buffer != null) { buffer.Recycle(); buffer = null; } Thread.Sleep(1); } }
/// <summary> /// Process an incoming packet. /// </summary> bool ProcessPacket(Buffer buffer, TcpProtocol tc) { BinaryReader reader = buffer.BeginReading(); Packet request = (Packet)reader.ReadByte(); // TCP connections must be verified first to ensure that they are using the correct protocol if (tc.stage == TcpProtocol.Stage.Verifying) { if (tc.VerifyRequestID(request, reader, false)) return true; #if STANDALONE Console.WriteLine(tc.address + " has failed the verification step"); #endif return false; } switch (request) { case Packet.RequestServerList: { if (reader.ReadUInt16() != GameServer.gameID) return false; tc.data = (long)0; return true; } case Packet.RequestAddServer: { if (reader.ReadUInt16() != GameServer.gameID) return false; ServerList.Entry ent = new ServerList.Entry(); ent.ReadFrom(reader); if (ent.externalAddress.Address.Equals(IPAddress.None)) ent.externalAddress = tc.tcpEndPoint; mList.Add(ent, mTime).data = tc; mLastChange = mTime; #if STANDALONE Console.WriteLine(tc.address + " added a server (" + ent.internalAddress + ", " + ent.externalAddress + ")"); #endif return true; } case Packet.RequestRemoveServer: { if (reader.ReadUInt16() != GameServer.gameID) return false; IPEndPoint internalAddress, externalAddress; Tools.Serialize(reader, out internalAddress); Tools.Serialize(reader, out externalAddress); if (externalAddress.Address.Equals(IPAddress.None)) externalAddress = tc.tcpEndPoint; RemoveServer(internalAddress, externalAddress); #if STANDALONE Console.WriteLine(tc.address + " removed a server (" + internalAddress + ", " + externalAddress + ")"); #endif return true; } case Packet.Disconnect: { #if STANDALONE if (RemoveServer(tc)) Console.WriteLine(tc.address + " has disconnected"); #else RemoveServer(tc); #endif mTcp.Remove(tc); return true; } case Packet.RequestSaveFile: { string fileName = reader.ReadString(); byte[] data = reader.ReadBytes(reader.ReadInt32()); SaveFile(fileName, data); break; } case Packet.RequestLoadFile: { string fn = reader.ReadString(); byte[] data = LoadFile(fn); BinaryWriter writer = BeginSend(Packet.ResponseLoadFile); writer.Write(fn); if (data != null) { writer.Write(data.Length); writer.Write(data); } else writer.Write(0); EndSend(tc); break; } case Packet.RequestDeleteFile: { DeleteFile(reader.ReadString()); break; } case Packet.Error: { #if STANDALONE Console.WriteLine(tc.address + " error: " + reader.ReadString()); #endif return false; } } #if STANDALONE Console.WriteLine(tc.address + " sent a packet not handled by the lobby server: " + request); #endif return false; }
/// <summary> /// Send the outgoing buffer to the specified player. /// </summary> void EndSend(TcpProtocol tc) { mBuffer.EndPacket(); tc.SendTcpPacket(mBuffer); mBuffer.Recycle(); mBuffer = null; }