Exemple #1
0
        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);
            }
        }
Exemple #2
0
        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);
            }
        }