/// <summary> /// Gateway lobby logic is done on a separate thread so that it's not blocking the main thread. /// </summary> void ThreadDiscover(object obj) { string request = "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "ST:upnp:rootdevice\r\n" + "MAN:\"ssdp:discover\"\r\n" + "MX:3\r\n\r\n"; byte[] requestBytes = Encoding.ASCII.GetBytes(request); List <IPAddress> ips = Tools.localAddresses; IPEndPoint searchEndpoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900); // UPnP discovery should happen on all network interfaces for (int i = 0; i < ips.size; ++i) { IPAddress ip = ips[i]; UdpClient sender = null; try { #if STANDALONE Tools.Print("Checking UPnP status on " + ip + "..."); #endif sender = new UdpClient(new IPEndPoint(ip, 0)); sender.Client.ReceiveTimeout = 3000; // Send several requests due to the unreliable nature of UDP for (int b = 0; b < 3; ++b) { sender.Send(requestBytes, requestBytes.Length, searchEndpoint); } for (; ;) { IPEndPoint sourceAddress = new IPEndPoint(IPAddress.Any, 0); byte[] data = sender.Receive(ref sourceAddress); if (ParseResponse(Encoding.ASCII.GetString(data, 0, data.Length))) { sender.Close(); sender = null; mGatewayAddress = sourceAddress.Address; #if STANDALONE Tools.Print("UPnP Gateway: " + mGatewayAddress); #endif mStatus = Status.Success; mDiscover = null; return; } } } catch (System.Exception) { if (sender != null) { sender.Close(); } } mStatus = Status.Failure; #if STANDALONE Tools.Print("UPnP Gateway: Not found"); #endif // If we found one, we're done if (mStatus == Status.Success) { break; } } mDiscover = null; }
public bool Start(int port) { Stop(); mPort = port; mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); #if !UNITY_WEBPLAYER // Web player doesn't seem to support broadcasts mSocket.MulticastLoopback = true; mMulticast = useMulticasting; try { if (useMulticasting) { List <IPAddress> ips = Tools.localAddresses; foreach (IPAddress ip in ips) { MulticastOption opt = new MulticastOption(multicastIP, ip); mSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, opt); } } else { mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); } } catch (System.Exception) { } #endif // Port zero means we will be able to send, but not receive if (mPort == 0) { return(true); } try { // Use the default network interface if one wasn't explicitly chosen #if (UNITY_IPHONE && !UNITY_EDITOR) //|| UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX IPAddress networkInterface = useMulticasting ? multicastIP : (defaultNetworkInterface ?? IPAddress.Any); #else IPAddress networkInterface = defaultNetworkInterface ?? IPAddress.Any; #endif mEndPoint = new IPEndPoint(networkInterface, 0); mDefaultEndPoint = new IPEndPoint(networkInterface, 0); // Bind the socket to the specific network interface and start listening for incoming packets mSocket.Bind(new IPEndPoint(networkInterface, mPort)); mSocket.BeginReceiveFrom(mTemp, 0, mTemp.Length, SocketFlags.None, ref mEndPoint, OnReceive, null); } #if UNITY_EDITOR catch (System.Exception ex) { UnityEngine.Debug.LogError("[TNet] Udp.Start: " + ex.Message); Stop(); return(false); } #elif DEBUG catch (System.Exception ex) { Tools.Print("Udp.Start: " + ex.Message); Stop(); return(false); } #else catch (System.Exception) { Stop(); return(false); } #endif return(true); }
/// <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> /// Process an incoming packet. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { BinaryReader reader = buffer.BeginReading(); Packet request = (Packet)reader.ReadByte(); switch (request) { case Packet.RequestPing: { BeginSend(Packet.ResponsePing); EndSend(ip); break; } 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 = ip; } mList.Add(ent, mTime); #if STANDALONE Tools.Print(ip + " 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 = ip; } RemoveServer(internalAddress, externalAddress); #if STANDALONE Tools.Print(ip + " removed a server (" + internalAddress + ", " + externalAddress + ")"); #endif return(true); } case Packet.RequestServerList: { if (reader.ReadUInt16() != GameServer.gameID) { return(false); } mList.WriteTo(BeginSend(Packet.ResponseServerList)); EndSend(ip); return(true); } } return(false); }
/// <summary> /// Load a previously saved ban list. /// </summary> public void LoadBanList() { Tools.Print("Bans: " + (Tools.LoadList(string.IsNullOrEmpty(rootDirectory) ? banFilePath : Path.Combine(rootDirectory, banFilePath), mBan) ? mBan.Count.ToString() : "file not found")); }
/// <summary> /// Process an incoming packet. /// </summary> bool ProcessPacket(Buffer buffer, IPEndPoint ip) { if (mBan.Count != 0 && mBan.Contains(ip.Address.ToString())) { return(false); } var reader = buffer.BeginReading(); var request = (Packet)reader.ReadByte(); switch (request) { case Packet.RequestPing: { var writer = BeginSend(Packet.ResponsePing); writer.Write(mTime); writer.Write((ushort)mList.list.size); EndSend(ip); break; } case Packet.RequestAddServer: { if (reader.ReadUInt16() != GameServer.gameID) { return(false); } var ent = new ServerList.Entry(); ent.ReadFrom(reader); if (mBan.Count != 0 && (mBan.Contains(ent.externalAddress.Address.ToString()) || IsBanned(ent.name))) { return(false); } if (ent.externalAddress.Address.Equals(IPAddress.None) || ent.externalAddress.Address.Equals(IPAddress.IPv6None)) { ent.externalAddress = ip; } mList.Add(ent, mTime); #if STANDALONE Tools.Print(ip + " 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.Address.Equals(IPAddress.IPv6None)) { externalAddress = ip; } RemoveServer(internalAddress, externalAddress); #if STANDALONE Tools.Print(ip + " removed a server (" + internalAddress + ", " + externalAddress + ")"); #endif return(true); } case Packet.RequestServerList: { if (reader.ReadUInt16() != GameServer.gameID) { return(false); } mList.WriteTo(BeginSend(Packet.ResponseServerList)); EndSend(ip); return(true); } } return(false); }