/// <summary> /// Open up a port on the gateway. /// </summary> private void Open(int port, bool tcp, OnPortRequest callback) { int id = (port << 8) | (tcp ? 1 : 0); if (port > 0 && !mPorts.Contains(id) && mStatus != Status.Failure) { ListLessGarb <IPAddress> debug = NetworkUtility.localAddresses; if (mDiscover == null) { mDiscover = new Thread(ThreadDiscover); mThreads.Add(mDiscover); mDiscover.Start(mDiscover); } string addr = NetworkUtility.localAddress.ToString(); if (addr == "127.0.0.1") { return; } mPorts.Add(id); ExtraParams xp = new ExtraParams(); xp.callback = callback; xp.port = port; xp.protocol = tcp ? ProtocolType.Tcp : ProtocolType.Udp; xp.action = "AddPortMapping"; xp.request = "<NewRemoteHost></NewRemoteHost>\n" + "<NewExternalPort>" + port + "</NewExternalPort>\n" + "<NewProtocol>" + (tcp ? "TCP" : "UDP") + "</NewProtocol>\n" + "<NewInternalPort>" + port + "</NewInternalPort>\n" + "<NewInternalClient>" + addr + "</NewInternalClient>\n" + "<NewEnabled>1</NewEnabled>\n" + "<NewPortMappingDescription>" + name + "</NewPortMappingDescription>\n" + "<NewLeaseDuration>0</NewLeaseDuration>\n"; xp.th = new Thread(OpenRequest); lock (mThreads) { mThreads.Add(xp.th); } xp.th.Start(xp); Debug.Log("[UPnP:Open(" + port + ", " + (tcp ? "TCP" : "UDP") + ")] -> Requested"); } else if (callback != null) { callback(this, port, tcp ? ProtocolType.Tcp : ProtocolType.Udp, false); } }
/// <summary> /// Start listening for incoming messages on the specified port. /// </summary> public bool Start(int port, bool multiThreaded = true) { this.multiThreaded = multiThreaded; Stop(); Port = port; Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Web player doesn't seem to support broadcasts Socket.MulticastLoopback = true; multicast = useMulticasting; try { if (useMulticasting) { ListLessGarb <IPAddress> ips = NetworkUtility.localAddresses; foreach (IPAddress ip in ips) { MulticastOption opt = new MulticastOption(multicastIP, ip); Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, opt); } } else { Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); } } catch (Exception e) { Debug.LogException(e); } // Port zero means we will be able to send, but not receive if (Port == 0) { #if DEBUG Debug.Log("[UdpProtocol:Start(" + port + ") - Port zero means we will be able to send, but not receive"); #endif 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 endPoint = new IPEndPoint(networkInterface, 0); defaultEndPoint = new IPEndPoint(networkInterface, 0); // Bind the socket to the specific network interface and start listening for incoming packets Socket.Bind(new IPEndPoint(networkInterface, Port)); Socket.BeginReceiveFrom(temp, 0, temp.Length, SocketFlags.None, ref endPoint, OnReceive, null); } catch (Exception ex) { Debug.LogException(ex); Stop(); return(false); } if (multiThreaded) { thread = new Thread(ThreadProcessPackets); thread.Start(); } #if DEBUG Debug.Log("[UdpProtocol:Start(" + port + ") - Success ! useMulticasting? " + useMulticasting + " EndPoint: " + endPoint); #endif return(true); }
/// <summary> /// Gateway lobby logic is done on a separate thread so that it's not blocking the main thread. /// </summary> private void ThreadDiscover(object obj) { Thread th = (Thread)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); int port = 10000 + (int)(DateTime.UtcNow.Ticks % 45000); ListLessGarb <IPAddress> ips = NetworkUtility.localAddresses; Debug.Log("[UPnP:ThreadDiscover()] -> Running. Status: " + mStatus + " | IPs count: " + ips.Count); // UPnP discovery should happen on all network interfaces for (int i = 0; i < ips.size; ++i) { IPAddress ip = ips[i]; mStatus = Status.Searching; UdpClient receiver = null; try { UdpClient sender = new UdpClient(new IPEndPoint(ip, port)); sender.Connect(IPAddress.Broadcast, 1900); sender.Send(requestBytes, requestBytes.Length); sender.Close(); receiver = new UdpClient(new IPEndPoint(ip, port)); receiver.Client.ReceiveTimeout = 3000; IPEndPoint sourceAddress = new IPEndPoint(IPAddress.Any, 0); for (;;) { byte[] data = receiver.Receive(ref sourceAddress); if (ParseResponse(Encoding.ASCII.GetString(data, 0, data.Length))) { receiver.Close(); lock (mThreads) { mGatewayAddress = sourceAddress.Address; #if UNITY_EDITOR Debug.Log("[TNet] UPnP Gateway: " + mGatewayAddress); #endif mStatus = Status.Success; mThreads.Remove(th); } mDiscover = null; return; } } } catch (Exception ex) { Debug.LogException(ex); } if (receiver != null) { receiver.Close(); } lock (mThreads) { mStatus = Status.Failure; mThreads.Remove(th); } mDiscover = null; // If we found one, we're done if (mStatus == Status.Success) { break; } } if (mStatus != Status.Success) { Debug.LogWarning( "[UPnP:ThreadDiscover()] -> UPnP discovery failed. TNet won't be able to open ports automatically."); } }