Exemplo n.º 1
0
        async Task <ResponseMessage> DecodeMessageFromResponse(Stream s, int length)
        {
            StringBuilder data = new StringBuilder();
            int           bytesRead;

            byte[] buffer = BufferHelpers.Rent();
            try {
                // Read out the content of the message, hopefully picking everything up in the case where we have no contentlength
                if (length != -1)
                {
                    while (length > 0)
                    {
                        bytesRead = await s.ReadAsync(buffer, 0, Math.Min(buffer.Length, length)).ConfigureAwait(false);

                        data.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
                        length -= bytesRead;
                    }
                }
                else
                {
                    while ((bytesRead = await s.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) != 0)
                    {
                        data.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
                    }
                }
            } finally {
                BufferHelpers.Release(buffer);
            }

            // Once we have our content, we need to see what kind of message it is. If we received
            // an error message we will immediately throw a MappingException.
            var dataString = data.ToString();

            Log.InfoFormatted("uPnP Response: {0}, {1}", Environment.NewLine, dataString);
            return(ResponseMessage.Decode(this, dataString));
        }
Exemplo n.º 2
0
        async Task <UpnpNatDevice> ServicesReceived(IPAddress localAddress, Uri deviceServiceUri, HttpWebResponse response, CancellationToken token)
        {
            Stream s = response.GetResponseStream();

            if (response.StatusCode != HttpStatusCode.OK)
            {
                Log.ErrorFormatted("Couldn't get services list from: {0}. Return code was: {1}", response.ResponseUri, response.StatusCode);
                return(null); // FIXME: This the best thing to do??
            }

            int           abortCount  = 0;
            StringBuilder servicesXml = new StringBuilder();
            XmlDocument   xmldoc      = new XmlDocument();

            byte[] buffer = BufferHelpers.Rent();
            try {
                while (true)
                {
                    var bytesRead = await s.ReadAsync(buffer, 0, buffer.Length, token).ConfigureAwait(false);

                    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 5 seconds, 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++ > 5000)
                        {
                            return(null);
                        }
                        Log.InfoFormatted("Couldn't parse services list from {0}", response.ResponseUri);
                        await Task.Delay(10, token).ConfigureAwait(false);
                    }
                }
            } finally {
                BufferHelpers.Release(buffer);
            }

            Log.InfoFormatted("Parsed services list {0}", response.ResponseUri);
            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)
                {
                    string serviceType = service["serviceType"].InnerText;
                    Log.InfoFormatted("Found service {1} from service list {0}", response.ResponseUri, serviceType);
                    // TODO: Add support for version 2 of UPnP.
                    if (SupportedServices.Contains(serviceType, StringComparer.OrdinalIgnoreCase))
                    {
                        var        controlUrl     = new Uri(service["controlURL"].InnerText, UriKind.RelativeOrAbsolute);
                        IPEndPoint deviceEndpoint = new IPEndPoint(IPAddress.Parse(response.ResponseUri.Host), response.ResponseUri.Port);
                        Log.InfoFormatted("Found upnp control uri at {1} from service url {0}", response.ResponseUri, controlUrl.OriginalString);
                        try {
                            if (controlUrl.IsAbsoluteUri)
                            {
                                deviceEndpoint = new IPEndPoint(IPAddress.Parse(controlUrl.Host), controlUrl.Port);
                                Log.InfoFormatted("New control url {1} for device endpoint {0}", deviceEndpoint, controlUrl);
                            }
                            else
                            {
                                controlUrl = new Uri(deviceServiceUri, controlUrl.OriginalString);
                            }
                        } catch {
                            controlUrl = new Uri(deviceServiceUri, controlUrl.OriginalString);
                            Log.InfoFormatted("{0}: Assuming control Uri is relative: {1}", deviceEndpoint, controlUrl);
                        }
                        Log.InfoFormatted("Handshake Complete for {0}", deviceEndpoint);
                        return(new UpnpNatDevice(localAddress, deviceEndpoint, controlUrl, serviceType));
                    }
                }
            }

            //If we get here, it means that we didn't get WANIPConnection/WANPPPConnection service, which means no uPnP forwarding
            //So we don't invoke the callback, so this device is never added to our lists
            return(null);
        }