From 2db09b002daa60f7fb84b2765afa0c65bc711b2d Mon Sep 17 00:00:00 2001 From: lidgren Date: Thu, 25 Oct 2012 08:12:14 +0000 Subject: [PATCH] - UPnP changes - now tries to parse any incoming message, regardless of port --- Lidgren.Network/NetPeer.Internal.cs | 4 +-- Lidgren.Network/NetUPnP.cs | 54 +++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index 56751ff..e1fc47f 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -398,9 +398,9 @@ namespace Lidgren.Network IPEndPoint ipsender = (IPEndPoint)m_senderRemote; - if (ipsender.Port == 1900) + if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline) { - // UPnP response + // is this an UPnP response? try { string resp = System.Text.Encoding.ASCII.GetString(m_receiveBuffer, 0, bytesReceived); diff --git a/Lidgren.Network/NetUPnP.cs b/Lidgren.Network/NetUPnP.cs index 021a2d7..a501a7b 100644 --- a/Lidgren.Network/NetUPnP.cs +++ b/Lidgren.Network/NetUPnP.cs @@ -7,6 +7,13 @@ using System.Threading; namespace Lidgren.Network { + public enum UPnPStatus + { + Discovering, + NotAvailable, + Available + } + /// /// UPnP support class /// @@ -18,12 +25,19 @@ namespace Lidgren.Network private NetPeer m_peer; private ManualResetEvent m_discoveryComplete = new ManualResetEvent(false); + internal float m_discoveryResponseDeadline; + + private UPnPStatus m_status; + + public UPnPStatus Status { get { return m_status; } } + /// /// NetUPnP constructor /// public NetUPnP(NetPeer peer) { m_peer = peer; + m_discoveryResponseDeadline = float.MinValue; } internal void Discover(NetPeer peer) @@ -35,21 +49,27 @@ namespace Lidgren.Network "MAN:\"ssdp:discover\"\r\n" + "MX:3\r\n\r\n"; + m_status = UPnPStatus.Discovering; + byte[] arr = System.Text.Encoding.UTF8.GetBytes(str); + m_peer.LogDebug("Attempting UPnP discovery"); peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); peer.RawSend(arr, 0, arr.Length, new IPEndPoint(IPAddress.Broadcast, 1900)); peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false); // allow some extra time for router to respond // System.Threading.Thread.Sleep(50); + + m_discoveryResponseDeadline = (float)NetTime.Now + 6.0f; // arbitrarily chosen number, router gets 6 seconds to respond + m_status = UPnPStatus.Discovering; } internal void ExtractServiceUrl(string resp) { #if !DEBUG - try - { + try + { #endif XmlDocument desc = new XmlDocument(); desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream()); @@ -63,10 +83,11 @@ namespace Lidgren.Network return; m_serviceUrl = CombineUrls(resp, node.Value); m_peer.LogDebug("UPnP service ready"); + m_status = UPnPStatus.Available; m_discoveryComplete.Set(); #if !DEBUG - } - catch { return; } + } + catch { return; } #endif } @@ -83,12 +104,30 @@ namespace Lidgren.Network return "http://" + gatewayURL + subURL; } + private bool CheckAvailability() + { + switch (m_status) + { + case UPnPStatus.NotAvailable: + return false; + case UPnPStatus.Available: + return true; + case UPnPStatus.Discovering: + if (m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis)) + return true; + if (NetTime.Now > m_discoveryResponseDeadline) + m_status = UPnPStatus.NotAvailable; + return false; + } + return false; + } + /// /// Add a forwarding rule to the router using UPnP /// public bool ForwardPort(int port, string description) { - if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis)) + if (!CheckAvailability()) return false; IPAddress mask; @@ -126,8 +165,9 @@ namespace Lidgren.Network /// public bool DeleteForwardingRule(int port) { - if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis)) + if (!CheckAvailability()) return false; + try { XmlDocument xdoc = SOAPRequest(m_serviceUrl, @@ -151,7 +191,7 @@ namespace Lidgren.Network /// public IPAddress GetExternalIP() { - if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis)) + if (!CheckAvailability()) return null; try {