protected override async Task HandleMessageReceived(IPAddress localAddress, byte[] response, IPEndPoint remoteEndPoint, bool externalEvent, CancellationToken token) { if (token == CancellationToken.None) { token = Cancellation.Token; } string dataString = null; // No matter what, this method should never throw an exception. If something goes wrong // we should still be in a position to handle the next reply correctly. try { dataString = Encoding.UTF8.GetString(response); Log.InfoFormatted("uPnP Search Response: {0}", dataString); /* For UPnP Port Mapping we need ot find either WANPPPConnection or WANIPConnection. * Any other device type is no good to us for this purpose. See the IGP overview paper * page 5 for an overview of device types and their hierarchy. * http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf */ /* TODO: Currently we are assuming version 1 of the protocol. We should figure out which * version it is and apply the correct URN. */ string foundService = null; foreach (var type in SupportedServices.Concat(DiscoverDeviceMessage.SupportedServiceTypes)) { if (dataString.IndexOf(type, StringComparison.OrdinalIgnoreCase) != -1) { foundService = type; break; } } if (foundService == null && !externalEvent) { RaiseDeviceUnknown(localAddress, remoteEndPoint, dataString, NatProtocol.Upnp); return; } Log.InfoFormatted("uPnP Search Response: Router advertised a '{0}' service", foundService); var location = dataString.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .FirstOrDefault(t => t.StartsWith("LOCATION", StringComparison.OrdinalIgnoreCase)); if (location == null) { return; } var deviceLocation = location.Split(new[] { ':' }, 2).Skip(1).FirstOrDefault(); var deviceServiceUri = new Uri(deviceLocation); using (await Locker.DisposableWaitAsync(token).ConfigureAwait(false)) { // If we send 3 requests at a time, ensure we only fetch the services list once // even if three responses are received if (LastFetched.TryGetValue(deviceServiceUri, out DateTime last)) { if ((DateTime.Now - last) < TimeSpan.FromSeconds(20)) { return; } } LastFetched[deviceServiceUri] = DateTime.Now; } // Once we've parsed the information we need, we tell the device to retrieve it's service list // Once we successfully receive the service list, the callback provided will be invoked. Log.InfoFormatted("Fetching service list: {0}", deviceServiceUri); var d = await GetServicesList(localAddress, deviceServiceUri, token).ConfigureAwait(false); if (d != null) { RaiseDeviceFound(d); } } catch (OperationCanceledException) { throw; } catch (Exception ex) { Trace.WriteLine("Unhandled exception when trying to decode a device's response Send me the following data: "); Trace.WriteLine("ErrorMessage:"); Trace.WriteLine(ex.Message); Trace.WriteLine("Data string:"); Trace.WriteLine(dataString); } }
protected override async Task HandleMessageReceived(IPAddress localAddress, UdpReceiveResult result, CancellationToken token) { // Convert it to a string for easy parsing string dataString = null; var response = result.Buffer; // No matter what, this method should never throw an exception. If something goes wrong // we should still be in a position to handle the next reply correctly. try { dataString = Encoding.UTF8.GetString(response); NatUtility.Log("uPnP Search Response: {0}", dataString); /* For UPnP Port Mapping we need ot find either WANPPPConnection or WANIPConnection. * Any other device type is no good to us for this purpose. See the IGP overview paper * page 5 for an overview of device types and their hierarchy. * http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf */ /* TODO: Currently we are assuming version 1 of the protocol. We should figure out which * version it is and apply the correct URN. */ /* Some routers don't correctly implement the version ID on the URN, so we only search for the type * prefix. */ string log = "uPnP Search Response: Router advertised a '{0}' service"; StringComparison c = StringComparison.OrdinalIgnoreCase; if (dataString.IndexOf("urn:schemas-upnp-org:service:WANIPConnection:", c) != -1) { NatUtility.Log(log, "urn:schemas-upnp-org:service:WANIPConnection:1"); } else if (dataString.IndexOf("urn:schemas-upnp-org:service:WANPPPConnection:", c) != -1) { NatUtility.Log(log, "urn:schemas-upnp-org:service:WANPPPConnection:"); } else { return; } var location = dataString.Split(new [] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Select(t => t.Trim()) .FirstOrDefault(t => t.StartsWith("LOCATION", StringComparison.OrdinalIgnoreCase)); if (location == null) { return; } var deviceLocation = location.Split(new [] { ':' }, 2).Skip(1).FirstOrDefault(); var deviceServiceUri = new Uri(deviceLocation); using (await Locker.DisposableWaitAsync(token)) { // If we send 3 requests at a time, ensure we only fetch the services list once // even if three responses are received if (LastFetched.TryGetValue(deviceServiceUri, out DateTime last)) { if ((DateTime.Now - last) < TimeSpan.FromSeconds(20)) { return; } } LastFetched [deviceServiceUri] = DateTime.Now; } // Once we've parsed the information we need, we tell the device to retrieve it's service list // Once we successfully receive the service list, the callback provided will be invoked. NatUtility.Log("Fetching service list: {0}", deviceServiceUri); var d = await GetServicesList(localAddress, deviceServiceUri, token).ConfigureAwait(false); if (d != null) { RaiseDeviceFound(d); } } catch (Exception ex) { Trace.WriteLine("Unhandled exception when trying to decode a device's response Send me the following data: "); Trace.WriteLine("ErrorMessage:"); Trace.WriteLine(ex.Message); Trace.WriteLine("Data string:"); Trace.WriteLine(dataString); } }