/// <summary> /// Process all incoming packets. /// </summary> public void ProcessPackets() { mMyTime = DateTime.UtcNow.Ticks / 10000; // Request pings every so often, letting the server know we're still here. if (mTcp.isConnected && mCanPing && mPingTime + 4000 < mMyTime) { mCanPing = false; mPingTime = mMyTime; BeginSend(Packet.RequestPing); EndSend(); } Buffer buffer = null; bool keepGoing = true; #if !UNITY_WEBPLAYER IPEndPoint ip = null; while (keepGoing && isActive && mUdp.ReceivePacket(out buffer, out ip)) { mUdpIsUsable = true; keepGoing = ProcessPacket(buffer, ip); buffer.Recycle(); } #endif while (keepGoing && isActive && mTcp.ReceivePacket(out buffer)) { keepGoing = ProcessPacket(buffer, null); buffer.Recycle(); } }
/// <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> /// Keep receiving incoming packets. /// </summary> void Update() { Buffer buffer; bool changed = false; long time = System.DateTime.UtcNow.Ticks / 10000; // Automatically try to connect and reconnect if not connected if (mRemoteAddress != null && mTcp.stage == TcpProtocol.Stage.NotConnected && mNextConnect < time) { mNextConnect = time + 5000; mTcp.Connect(mRemoteAddress); } // TCP-based lobby while (mTcp.ReceivePacket(out buffer)) { if (buffer.size > 0) { try { BinaryReader reader = buffer.BeginReading(); Packet response = (Packet)reader.ReadByte(); if (response == Packet.ResponseID) { if (mTcp.VerifyResponseID(response, reader)) { isActive = true; // Request the server list -- with TCP this only needs to be done once mTcp.BeginSend(Packet.RequestServerList).Write(GameServer.gameID); mTcp.EndSend(); } } else if (response == Packet.Disconnect) { knownServers.Clear(); isActive = false; changed = true; errorString = ""; } else if (response == Packet.ResponseServerList) { lock (knownServers.list) knownServers.list.Clear(); knownServers.ReadFrom(reader, time); changed = true; errorString = ""; } else if (response == Packet.Error) { errorString = reader.ReadString(); Debug.LogWarning(errorString); changed = true; } } catch (System.Exception ex) { errorString = ex.Message; Debug.LogWarning(ex.Message); mTcp.Close(false); } } buffer.Recycle(); } // Trigger the listener callback if (changed && onChange != null) { onChange(); } }
/// <summary> /// Send periodic updates. /// </summary> void ThreadFunction() { mInternal = new IPEndPoint(Tools.localAddress, mGameServer.tcpPort); mExternal = new IPEndPoint(Tools.externalAddress, mGameServer.tcpPort); for (; ;) { long time = DateTime.UtcNow.Ticks / 10000; if (mShutdown) { mTcp.Disconnect(); mThread = null; #if STANDALONE Tools.Print("TcpLobbyLink shut down"); #endif break; } #if !STANDALONE if (TNManager.isPaused) { Thread.Sleep(500); continue; } #endif Buffer buffer; // Try to establish a connection if (mGameServer != null && !mTcp.isConnected && !mTcp.isTryingToConnect && mNextConnect < time) { #if STANDALONE Tools.Print("TcpLobbyLink is connecting to " + mRemoteAddress + "..."); #endif mUpdateNeeded = true; mNextConnect = time + 15000; mTcp.Connect(mRemoteAddress); } while (mTcp.ReceivePacket(out buffer)) { BinaryReader reader = buffer.BeginReading(); Packet response = (Packet)reader.ReadByte(); if (mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); mWasConnected = true; #if STANDALONE Tools.Print("TcpLobbyLink connection established"); #endif } else { #if STANDALONE Tools.Print("TcpLobbyLink Error: Protocol version mismatch"); #endif mThread = null; return; } } else if (response == Packet.RequestPing) { } #if STANDALONE else if (response == Packet.Error) { Tools.Print("TcpLobbyLink Error: " + reader.ReadString()); } else if (response == Packet.Disconnect) { Tools.Print("TcpLobbyLink disconnected"); } else { Tools.Print("TcpLobbyLink can't handle this packet: " + response); } #endif buffer.Recycle(); } // Automatically try to re-establish a connection on disconnect if (mWasConnected && !mTcp.isConnected && !mTcp.isTryingToConnect) { mNextConnect = time + 5000; mWasConnected = false; } else if (mGameServer != null && mTcp.isConnected && (mUpdateNeeded || mNextSend < time)) { mUpdateNeeded = false; mNextSend = time + 5000; Buffer buff = Buffer.Create(); BinaryWriter writer = buff.BeginPacket(Packet.RequestAddServer); writer.Write(GameServer.gameID); writer.Write(mGameServer.name); writer.Write((short)mGameServer.playerCount); Tools.Serialize(writer, mInternal); Tools.Serialize(writer, mExternal); buff.EndPacket(); mTcp.SendTcpPacket(buff); buff.Recycle(); } try { Thread.Sleep(10); } catch (System.Threading.ThreadInterruptedException) { return; } } }
/// <summary> /// Send periodic updates. /// </summary> void ThreadFunction() { mInternal = new IPEndPoint(Tools.localAddress, mGameServer.tcpPort); mExternal = new IPEndPoint(Tools.externalAddress, mGameServer.tcpPort); for (; ;) { long time = DateTime.UtcNow.Ticks / 10000; if (mShutdown) { mTcp.Disconnect(); mThread = null; break; } Buffer buffer; // Try to establish a connection if (mGameServer != null && !mTcp.isConnected && mNextConnect < time) { mNextConnect = time + 15000; mTcp.Connect(mRemoteAddress); } while (mTcp.ReceivePacket(out buffer)) { BinaryReader reader = buffer.BeginReading(); Packet response = (Packet)reader.ReadByte(); if (mTcp.stage == TcpProtocol.Stage.Verifying) { if (mTcp.VerifyResponseID(response, reader)) { mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000); mWasConnected = true; } else { #if STANDALONE Console.WriteLine("TcpLobbyLink: Protocol version mismatch"); #endif mThread = null; return; } } else if (response == Packet.Error) { // Automatically try to re-establish a connection on disconnect mNextConnect = mWasConnected ? 0 : time + 30000; #if STANDALONE Console.WriteLine("TcpLobbyLink: " + reader.ReadString()); #endif } #if STANDALONE else { Console.WriteLine("TcpLobbyLink can't handle this packet: " + response); } #endif buffer.Recycle(); } if (mGameServer != null && mTcp.isConnected) { BinaryWriter writer = mTcp.BeginSend(Packet.RequestAddServer); writer.Write(GameServer.gameID); writer.Write(mGameServer.name); writer.Write((short)mGameServer.playerCount); Tools.Serialize(writer, mInternal); Tools.Serialize(writer, mExternal); mTcp.EndSend(); mGameServer = null; } Thread.Sleep(10); } }