|
@@ -70,7 +70,7 @@ namespace Mono.Nat.Upnp
|
|
|
|
|
|
// FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address
|
|
// FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address
|
|
// Are we going to get addresses with the "http://" attached?
|
|
// Are we going to get addresses with the "http://" attached?
|
|
- if (locationDetails.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
+ if (locationDetails.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
NatUtility.Log("Found device at: {0}", locationDetails);
|
|
NatUtility.Log("Found device at: {0}", locationDetails);
|
|
// This bit strings out the "http://" from the string
|
|
// This bit strings out the "http://" from the string
|
|
@@ -98,7 +98,7 @@ namespace Mono.Nat.Upnp
|
|
this.localAddress = localAddress;
|
|
this.localAddress = localAddress;
|
|
|
|
|
|
// Split the string at the "location" section so i can extract the ipaddress and service description url
|
|
// Split the string at the "location" section so i can extract the ipaddress and service description url
|
|
- string locationDetails = deviceDetails.Substring(deviceDetails.IndexOf("Location", StringComparison.InvariantCultureIgnoreCase) + 9).Split('\r')[0];
|
|
|
|
|
|
+ string locationDetails = deviceDetails.Substring(deviceDetails.IndexOf("Location", StringComparison.OrdinalIgnoreCase) + 9).Split('\r')[0];
|
|
this.serviceType = serviceType;
|
|
this.serviceType = serviceType;
|
|
|
|
|
|
// Make sure we have no excess whitespace
|
|
// Make sure we have no excess whitespace
|
|
@@ -106,7 +106,7 @@ namespace Mono.Nat.Upnp
|
|
|
|
|
|
// FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address
|
|
// FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address
|
|
// Are we going to get addresses with the "http://" attached?
|
|
// Are we going to get addresses with the "http://" attached?
|
|
- if (locationDetails.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
|
+ if (locationDetails.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
NatUtility.Log("Found device at: {0}", locationDetails);
|
|
NatUtility.Log("Found device at: {0}", locationDetails);
|
|
// This bit strings out the "http://" from the string
|
|
// This bit strings out the "http://" from the string
|
|
@@ -171,189 +171,12 @@ namespace Mono.Nat.Upnp
|
|
get { return serviceType; }
|
|
get { return serviceType; }
|
|
}
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
|
- /// Begins an async call to get the external ip address of the router
|
|
|
|
- /// </summary>
|
|
|
|
- public override IAsyncResult BeginGetExternalIP(AsyncCallback callback, object asyncState)
|
|
|
|
- {
|
|
|
|
- // Create the port map message
|
|
|
|
- GetExternalIPAddressMessage message = new GetExternalIPAddressMessage(this);
|
|
|
|
- return BeginMessageInternal(message, callback, asyncState, EndGetExternalIPInternal);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Maps the specified port to this computer
|
|
|
|
- /// </summary>
|
|
|
|
- public override IAsyncResult BeginCreatePortMap(Mapping mapping, AsyncCallback callback, object asyncState)
|
|
|
|
- {
|
|
|
|
- CreatePortMappingMessage message = new CreatePortMappingMessage(mapping, localAddress, this);
|
|
|
|
- return BeginMessageInternal(message, callback, asyncState, EndCreatePortMapInternal);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public override Task CreatePortMap(Mapping mapping)
|
|
public override Task CreatePortMap(Mapping mapping)
|
|
{
|
|
{
|
|
CreatePortMappingMessage message = new CreatePortMappingMessage(mapping, localAddress, this);
|
|
CreatePortMappingMessage message = new CreatePortMappingMessage(mapping, localAddress, this);
|
|
return _httpClient.SendAsync(message.Encode(), message.Method);
|
|
return _httpClient.SendAsync(message.Encode(), message.Method);
|
|
}
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
|
- /// Removes a port mapping from this computer
|
|
|
|
- /// </summary>
|
|
|
|
- public override IAsyncResult BeginDeletePortMap(Mapping mapping, AsyncCallback callback, object asyncState)
|
|
|
|
- {
|
|
|
|
- DeletePortMappingMessage message = new DeletePortMappingMessage(mapping, this);
|
|
|
|
- return BeginMessageInternal(message, callback, asyncState, EndDeletePortMapInternal);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public override IAsyncResult BeginGetAllMappings(AsyncCallback callback, object asyncState)
|
|
|
|
- {
|
|
|
|
- GetGenericPortMappingEntry message = new GetGenericPortMappingEntry(0, this);
|
|
|
|
- return BeginMessageInternal(message, callback, asyncState, EndGetAllMappingsInternal);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public override IAsyncResult BeginGetSpecificMapping(Protocol protocol, int port, AsyncCallback callback, object asyncState)
|
|
|
|
- {
|
|
|
|
- GetSpecificPortMappingEntryMessage message = new GetSpecificPortMappingEntryMessage(protocol, port, this);
|
|
|
|
- return this.BeginMessageInternal(message, callback, asyncState, new AsyncCallback(this.EndGetSpecificMappingInternal));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- ///
|
|
|
|
- /// </summary>
|
|
|
|
- /// <param name="result"></param>
|
|
|
|
- public override void EndCreatePortMap(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- if (result == null) throw new ArgumentNullException("result");
|
|
|
|
-
|
|
|
|
- PortMapAsyncResult mappingResult = result as PortMapAsyncResult;
|
|
|
|
- if (mappingResult == null)
|
|
|
|
- throw new ArgumentException("Invalid AsyncResult", "result");
|
|
|
|
-
|
|
|
|
- // Check if we need to wait for the operation to finish
|
|
|
|
- if (!result.IsCompleted)
|
|
|
|
- result.AsyncWaitHandle.WaitOne();
|
|
|
|
-
|
|
|
|
- // If we have a saved exception, it means something went wrong during the mapping
|
|
|
|
- // so we just rethrow the exception and let the user figure out what they should do.
|
|
|
|
- if (mappingResult.SavedMessage is ErrorMessage)
|
|
|
|
- {
|
|
|
|
- ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage;
|
|
|
|
- throw new MappingException(msg.ErrorCode, msg.Description);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //return result.AsyncState as Mapping;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- ///
|
|
|
|
- /// </summary>
|
|
|
|
- /// <param name="result"></param>
|
|
|
|
- public override void EndDeletePortMap(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- if (result == null)
|
|
|
|
- throw new ArgumentNullException("result");
|
|
|
|
-
|
|
|
|
- PortMapAsyncResult mappingResult = result as PortMapAsyncResult;
|
|
|
|
- if (mappingResult == null)
|
|
|
|
- throw new ArgumentException("Invalid AsyncResult", "result");
|
|
|
|
-
|
|
|
|
- // Check if we need to wait for the operation to finish
|
|
|
|
- if (!mappingResult.IsCompleted)
|
|
|
|
- mappingResult.AsyncWaitHandle.WaitOne();
|
|
|
|
-
|
|
|
|
- // If we have a saved exception, it means something went wrong during the mapping
|
|
|
|
- // so we just rethrow the exception and let the user figure out what they should do.
|
|
|
|
- if (mappingResult.SavedMessage is ErrorMessage)
|
|
|
|
- {
|
|
|
|
- ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage;
|
|
|
|
- throw new MappingException(msg.ErrorCode, msg.Description);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // If all goes well, we just return
|
|
|
|
- //return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public override Mapping[] EndGetAllMappings(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- if (result == null)
|
|
|
|
- throw new ArgumentNullException("result");
|
|
|
|
-
|
|
|
|
- GetAllMappingsAsyncResult mappingResult = result as GetAllMappingsAsyncResult;
|
|
|
|
- if (mappingResult == null)
|
|
|
|
- throw new ArgumentException("Invalid AsyncResult", "result");
|
|
|
|
-
|
|
|
|
- if (!mappingResult.IsCompleted)
|
|
|
|
- mappingResult.AsyncWaitHandle.WaitOne();
|
|
|
|
-
|
|
|
|
- if (mappingResult.SavedMessage is ErrorMessage)
|
|
|
|
- {
|
|
|
|
- ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage;
|
|
|
|
- if (msg.ErrorCode != 713)
|
|
|
|
- throw new MappingException(msg.ErrorCode, msg.Description);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return mappingResult.Mappings.ToArray();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Ends an async request to get the external ip address of the router
|
|
|
|
- /// </summary>
|
|
|
|
- public override IPAddress EndGetExternalIP(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- if (result == null) throw new ArgumentNullException("result");
|
|
|
|
-
|
|
|
|
- PortMapAsyncResult mappingResult = result as PortMapAsyncResult;
|
|
|
|
- if (mappingResult == null)
|
|
|
|
- throw new ArgumentException("Invalid AsyncResult", "result");
|
|
|
|
-
|
|
|
|
- if (!result.IsCompleted)
|
|
|
|
- result.AsyncWaitHandle.WaitOne();
|
|
|
|
-
|
|
|
|
- if (mappingResult.SavedMessage is ErrorMessage)
|
|
|
|
- {
|
|
|
|
- ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage;
|
|
|
|
- throw new MappingException(msg.ErrorCode, msg.Description);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (mappingResult.SavedMessage == null)
|
|
|
|
- return null;
|
|
|
|
- else
|
|
|
|
- return ((GetExternalIPAddressResponseMessage)mappingResult.SavedMessage).ExternalIPAddress;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public override Mapping EndGetSpecificMapping(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- if (result == null)
|
|
|
|
- throw new ArgumentNullException("result");
|
|
|
|
-
|
|
|
|
- GetAllMappingsAsyncResult mappingResult = result as GetAllMappingsAsyncResult;
|
|
|
|
- if (mappingResult == null)
|
|
|
|
- throw new ArgumentException("Invalid AsyncResult", "result");
|
|
|
|
-
|
|
|
|
- if (!mappingResult.IsCompleted)
|
|
|
|
- mappingResult.AsyncWaitHandle.WaitOne();
|
|
|
|
-
|
|
|
|
- if (mappingResult.SavedMessage is ErrorMessage)
|
|
|
|
- {
|
|
|
|
- ErrorMessage message = mappingResult.SavedMessage as ErrorMessage;
|
|
|
|
- if (message.ErrorCode != 0x2ca)
|
|
|
|
- {
|
|
|
|
- throw new MappingException(message.ErrorCode, message.Description);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (mappingResult.Mappings.Count == 0)
|
|
|
|
- return new Mapping(Protocol.Tcp, -1, -1);
|
|
|
|
-
|
|
|
|
- return mappingResult.Mappings[0];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
public override bool Equals(object obj)
|
|
public override bool Equals(object obj)
|
|
{
|
|
{
|
|
UpnpNatDevice device = obj as UpnpNatDevice;
|
|
UpnpNatDevice device = obj as UpnpNatDevice;
|
|
@@ -373,256 +196,6 @@ namespace Mono.Nat.Upnp
|
|
return (this.hostEndPoint.GetHashCode() ^ this.controlUrl.GetHashCode() ^ this.serviceDescriptionUrl.GetHashCode());
|
|
return (this.hostEndPoint.GetHashCode() ^ this.controlUrl.GetHashCode() ^ this.serviceDescriptionUrl.GetHashCode());
|
|
}
|
|
}
|
|
|
|
|
|
- private IAsyncResult BeginMessageInternal(MessageBase message, AsyncCallback storedCallback, object asyncState, AsyncCallback callback)
|
|
|
|
- {
|
|
|
|
- byte[] body;
|
|
|
|
- WebRequest request = message.Encode(out body);
|
|
|
|
- PortMapAsyncResult mappingResult = PortMapAsyncResult.Create(message, request, storedCallback, asyncState);
|
|
|
|
-
|
|
|
|
- if (body.Length > 0)
|
|
|
|
- {
|
|
|
|
- request.ContentLength = body.Length;
|
|
|
|
- request.BeginGetRequestStream(delegate (IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- Stream s = request.EndGetRequestStream(result);
|
|
|
|
- s.Write(body, 0, body.Length);
|
|
|
|
- request.BeginGetResponse(callback, mappingResult);
|
|
|
|
- }
|
|
|
|
- catch (Exception ex)
|
|
|
|
- {
|
|
|
|
- mappingResult.Complete(ex);
|
|
|
|
- }
|
|
|
|
- }, null);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- request.BeginGetResponse(callback, mappingResult);
|
|
|
|
- }
|
|
|
|
- return mappingResult;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void CompleteMessage(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- PortMapAsyncResult mappingResult = result.AsyncState as PortMapAsyncResult;
|
|
|
|
- mappingResult.CompletedSynchronously = result.CompletedSynchronously;
|
|
|
|
- mappingResult.Complete();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private MessageBase DecodeMessageFromResponse(Stream s, long length)
|
|
|
|
- {
|
|
|
|
- StringBuilder data = new StringBuilder();
|
|
|
|
- int bytesRead = 0;
|
|
|
|
- int totalBytesRead = 0;
|
|
|
|
- byte[] buffer = new byte[10240];
|
|
|
|
-
|
|
|
|
- // Read out the content of the message, hopefully picking everything up in the case where we have no contentlength
|
|
|
|
- if (length != -1)
|
|
|
|
- {
|
|
|
|
- while (totalBytesRead < length)
|
|
|
|
- {
|
|
|
|
- bytesRead = s.Read(buffer, 0, buffer.Length);
|
|
|
|
- data.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
|
|
|
|
- totalBytesRead += bytesRead;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- while ((bytesRead = s.Read(buffer, 0, buffer.Length)) != 0)
|
|
|
|
- data.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Once we have our content, we need to see what kind of message it is. It'll either a an error
|
|
|
|
- // or a response based on the action we performed.
|
|
|
|
- return MessageBase.Decode(this, data.ToString());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void EndCreatePortMapInternal(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- EndMessageInternal(result);
|
|
|
|
- CompleteMessage(result);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void EndMessageInternal(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- HttpWebResponse response = null;
|
|
|
|
- PortMapAsyncResult mappingResult = result.AsyncState as PortMapAsyncResult;
|
|
|
|
-
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- response = (HttpWebResponse)mappingResult.Request.EndGetResponse(result);
|
|
|
|
- }
|
|
|
|
- catch (WebException ex)
|
|
|
|
- {
|
|
|
|
- // Even if the request "failed" i want to continue on to read out the response from the router
|
|
|
|
- response = ex.Response as HttpWebResponse;
|
|
|
|
- if (response == null)
|
|
|
|
- mappingResult.SavedMessage = new ErrorMessage((int)ex.Status, ex.Message);
|
|
|
|
- }
|
|
|
|
- if (response != null)
|
|
|
|
- mappingResult.SavedMessage = DecodeMessageFromResponse(response.GetResponseStream(), response.ContentLength);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- finally
|
|
|
|
- {
|
|
|
|
- if (response != null)
|
|
|
|
- response.Close();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void EndDeletePortMapInternal(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- EndMessageInternal(result);
|
|
|
|
- CompleteMessage(result);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void EndGetAllMappingsInternal(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- EndMessageInternal(result);
|
|
|
|
-
|
|
|
|
- GetAllMappingsAsyncResult mappingResult = result.AsyncState as GetAllMappingsAsyncResult;
|
|
|
|
- GetGenericPortMappingEntryResponseMessage message = mappingResult.SavedMessage as GetGenericPortMappingEntryResponseMessage;
|
|
|
|
- if (message != null)
|
|
|
|
- {
|
|
|
|
- Mapping mapping = new Mapping(message.Protocol, message.InternalPort, message.ExternalPort, message.LeaseDuration);
|
|
|
|
- mapping.Description = message.PortMappingDescription;
|
|
|
|
- mappingResult.Mappings.Add(mapping);
|
|
|
|
- GetGenericPortMappingEntry next = new GetGenericPortMappingEntry(mappingResult.Mappings.Count, this);
|
|
|
|
-
|
|
|
|
- // It's ok to do this synchronously because we should already be on anther thread
|
|
|
|
- // and this won't block the user.
|
|
|
|
- byte[] body;
|
|
|
|
- WebRequest request = next.Encode(out body);
|
|
|
|
- if (body.Length > 0)
|
|
|
|
- {
|
|
|
|
- request.ContentLength = body.Length;
|
|
|
|
- request.GetRequestStream().Write(body, 0, body.Length);
|
|
|
|
- }
|
|
|
|
- mappingResult.Request = request;
|
|
|
|
- request.BeginGetResponse(EndGetAllMappingsInternal, mappingResult);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- CompleteMessage(result);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void EndGetExternalIPInternal(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- EndMessageInternal(result);
|
|
|
|
- CompleteMessage(result);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void EndGetSpecificMappingInternal(IAsyncResult result)
|
|
|
|
- {
|
|
|
|
- EndMessageInternal(result);
|
|
|
|
-
|
|
|
|
- GetAllMappingsAsyncResult mappingResult = result.AsyncState as GetAllMappingsAsyncResult;
|
|
|
|
- GetGenericPortMappingEntryResponseMessage message = mappingResult.SavedMessage as GetGenericPortMappingEntryResponseMessage;
|
|
|
|
- if (message != null)
|
|
|
|
- {
|
|
|
|
- Mapping mapping = new Mapping(mappingResult.SpecificMapping.Protocol, message.InternalPort, mappingResult.SpecificMapping.PublicPort, message.LeaseDuration);
|
|
|
|
- mapping.Description = mappingResult.SpecificMapping.Description;
|
|
|
|
- mappingResult.Mappings.Add(mapping);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- CompleteMessage(result);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- internal async Task<bool> GetServicesList()
|
|
|
|
- {
|
|
|
|
- // Create a HTTPWebRequest to download the list of services the device offers
|
|
|
|
- var requestOptions = new GetServicesMessage(this.serviceDescriptionUrl, this.hostEndPoint, _logger).Encode();
|
|
|
|
-
|
|
|
|
- requestOptions.BufferContent = false;
|
|
|
|
-
|
|
|
|
- using (var response = await _httpClient.Get(requestOptions).ConfigureAwait(false))
|
|
|
|
- {
|
|
|
|
- return ServicesReceived(response);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private bool ServicesReceived(Stream s)
|
|
|
|
- {
|
|
|
|
- int abortCount = 0;
|
|
|
|
- int bytesRead = 0;
|
|
|
|
- byte[] buffer = new byte[10240];
|
|
|
|
- StringBuilder servicesXml = new StringBuilder();
|
|
|
|
- XmlDocument xmldoc = new XmlDocument();
|
|
|
|
-
|
|
|
|
- while (true)
|
|
|
|
- {
|
|
|
|
- bytesRead = s.Read(buffer, 0, buffer.Length);
|
|
|
|
- servicesXml.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- xmldoc.LoadXml(servicesXml.ToString());
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- catch (XmlException)
|
|
|
|
- {
|
|
|
|
- // If we can't receive the entire XML within 500ms, then drop the connection
|
|
|
|
- // Unfortunately not all routers supply a valid ContentLength (mine doesn't)
|
|
|
|
- // so this hack is needed to keep testing our recieved data until it gets successfully
|
|
|
|
- // parsed by the xmldoc. Without this, the code will never pick up my router.
|
|
|
|
- if (abortCount++ > 50)
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- NatUtility.Log("{0}: Couldn't parse services list", HostEndPoint);
|
|
|
|
- System.Threading.Thread.Sleep(10);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- NatUtility.Log("{0}: Parsed services list", HostEndPoint);
|
|
|
|
- XmlNamespaceManager ns = new XmlNamespaceManager(xmldoc.NameTable);
|
|
|
|
- ns.AddNamespace("ns", "urn:schemas-upnp-org:device-1-0");
|
|
|
|
- XmlNodeList nodes = xmldoc.SelectNodes("//*/ns:serviceList", ns);
|
|
|
|
-
|
|
|
|
- foreach (XmlNode node in nodes)
|
|
|
|
- {
|
|
|
|
- //Go through each service there
|
|
|
|
- foreach (XmlNode service in node.ChildNodes)
|
|
|
|
- {
|
|
|
|
- //If the service is a WANIPConnection, then we have what we want
|
|
|
|
- string type = service["serviceType"].InnerText;
|
|
|
|
- NatUtility.Log("{0}: Found service: {1}", HostEndPoint, type);
|
|
|
|
- StringComparison c = StringComparison.OrdinalIgnoreCase;
|
|
|
|
- // TODO: Add support for version 2 of UPnP.
|
|
|
|
- if (type.Equals("urn:schemas-upnp-org:service:WANPPPConnection:1", c) ||
|
|
|
|
- type.Equals("urn:schemas-upnp-org:service:WANIPConnection:1", c))
|
|
|
|
- {
|
|
|
|
- this.controlUrl = service["controlURL"].InnerText;
|
|
|
|
- NatUtility.Log("{0}: Found upnp service at: {1}", HostEndPoint, controlUrl);
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- Uri u = new Uri(controlUrl);
|
|
|
|
- if (u.IsAbsoluteUri)
|
|
|
|
- {
|
|
|
|
- EndPoint old = hostEndPoint;
|
|
|
|
- this.hostEndPoint = new IPEndPoint(IPAddress.Parse(u.Host), u.Port);
|
|
|
|
- NatUtility.Log("{0}: Absolute URI detected. Host address is now: {1}", old, HostEndPoint);
|
|
|
|
- this.controlUrl = controlUrl.Substring(u.GetLeftPart(UriPartial.Authority).Length);
|
|
|
|
- NatUtility.Log("{0}: New control url: {1}", HostEndPoint, controlUrl);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- catch
|
|
|
|
- {
|
|
|
|
- NatUtility.Log("{0}: Assuming control Uri is relative: {1}", HostEndPoint, controlUrl);
|
|
|
|
- }
|
|
|
|
- NatUtility.Log("{0}: Handshake Complete", HostEndPoint);
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- //If we get here, it means that we didn't get WANIPConnection service, which means no uPnP forwarding
|
|
|
|
- //So we don't invoke the callback, so this device is never added to our lists
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Overridden.
|
|
/// Overridden.
|
|
/// </summary>
|
|
/// </summary>
|