예제 #1
0
        /// <summary>
        /// Method used to send a soap request over http to a service endpoint.
        /// </summary>
        /// <param name="soapMessage">A byte array contining a soap request message.</param>
        /// <param name="endpointAddress">A string containing the endpoint address of a service that will receive
        /// the request. This must be a transport address in the format http://ip_address:port/service_address.</param>
        /// <param name="isOneway">True = don't wait for response, false means wait for a response.</param>
        /// <param name="isChuncked">If true true the message will be chunk encoded.</param>
        /// <returns>
        /// A DpwSoapResponse object containing a WsWsaHeader and a XmlReader or null if no response is received
        /// or parsing fails.
        /// </returns>
        public DpwsSoapResponse SendRequest(byte[] soapMessage, string endpointAddress, bool isOneway, bool isChuncked)
        {
            System.Ext.Console.Write(new string(System.Text.UTF8Encoding.UTF8.GetChars(soapMessage)));

            WsMessage response = SendRequest(soapMessage, endpointAddress, isOneway, isChuncked, null);

            if (isOneway)
            {
                return(null);
            }

            XmlReader   reader;
            WsWsaHeader header;

            try
            {
                reader = WsSoapMessageParser.ParseSoapMessage(response.Message, out header);
            }
            catch
            {
                System.Ext.Console.Write("ParseSoapMessage failed.");
                return(null);
            }

            return(new DpwsSoapResponse(header, reader));
        }
예제 #2
0
        /// <summary>
        /// Parses a Udp transport message and builds a header object and envelope document then calls processRequest
        /// on a service endpoint contained.
        /// </summary>
        /// <param name="soapRequest">A byte array containing a raw soap request message.  If null no check is performed.</param>
        /// <param name="messageCheck">A WsMessageCheck objct used to test for duplicate request.</param>
        /// <param name="remoteEP">The remote endpoint address of the requestor.</param>
        /// <returns>A byte array containing a soap response message returned from a service endpoint.</returns>
        public byte[] ProcessRequestMessage()
        {
            Debug.Assert(m_messageCheck != null && m_remoteEP != null);

            // Parse and validate the soap message
            WsWsaHeader header;
            XmlReader   reader;

            try
            {
                reader = WsSoapMessageParser.ParseSoapMessage(m_soapMessage, out header);
            }
            catch
            {
                return(null);
            }

            try
            {
                if (m_messageCheck.IsDuplicate(header.MessageID, m_remoteEP.ToString()) == true)
                {
                    System.Ext.Console.Write("Duplicate \"" + header.Action + "\" request received");
                    System.Ext.Console.Write("Request Ignored.");
                    return(null);
                }

                // Check Udp service endpoints collection for a target service.
                IWsServiceEndpoint serviceEndpoint = m_serviceEndpoints[header.To];
                if (serviceEndpoint != null && serviceEndpoint.ServiceOperations[header.Action] != null)
                {
                    // Don't block discovery processes.
                    serviceEndpoint.BlockingCall = false;
                    try
                    {
                        return(serviceEndpoint.ProcessRequest(header, reader));
                    }
                    catch
                    {
                        return(null);
                    }
                }

                // Return null if service endpoint was not found
                System.Ext.Console.Write("Udp service endpoint was not found.");
                System.Ext.Console.Write("  Endpoint Address: " + header.To);
                System.Ext.Console.Write("  Action: " + header.Action);
                return(null);
            }
            finally
            {
                reader.Close();
            }
        }
        /// <summary>
        /// Parses a GetResponse message.
        /// </summary>
        /// <param name="soapResponse">A byte array containing a response message.</param>
        /// <param name="messageID">The message ID sent in the original request.</param>
        /// <returns>
        /// A DpwsMetadata object containing a details about a service endpoint.
        /// </returns>
        internal DpwsMetadata ProcessGetResponse(byte[] soapResponse, string messageID)
        {
            // Parse and build header
            WsWsaHeader header = new WsWsaHeader();
            XmlReader   reader;

            try
            {
                reader = WsSoapMessageParser.ParseSoapMessage(soapResponse, ref header, m_version);
            }
            catch
            {
                return(null);
            }

            try
            {
                // Make sure this is a get response
                if (header.Action != WsWellKnownUri.WstNamespaceUri + "/GetResponse")
                {
                    return(null);
                }

                // Make sure the messageID matches the request ID
                if (header.RelatesTo != messageID)
                {
                    return(null);
                }

#if DEBUG
                int depth = reader.Depth;
#endif
                DpwsMetadata metaData = new DpwsMetadata(reader, m_version);
#if DEBUG
                Microsoft.SPOT.Debug.Assert(XmlReaderHelper.HasReadCompleteNode(depth, reader));
#endif
                return(metaData);
            }
            finally
            {
                reader.Close();
            }
        }
예제 #4
0
        /// <summary>
        /// Send an Http request to an endpoint and waits for a response.
        /// </summary>
        /// <param name="soapMessage">A byte array containing the soap message to be sent.</param>
        /// <param name="remoteEndpoint">A sting containing the name of a remote listening endpoint.</param>
        /// <returns>
        /// A WsMessage containing a soap response to the request. This array will be null for OneWay request.
        /// </returns>
        public WsMessage SendRequest(WsMessage request, Uri remoteEndpoint)
        {
            WsMessage response = new WsMessage(new WsWsaHeader(), null, WsPrefix.None);

            HttpTransportBindingElement httpClient = new HttpTransportBindingElement(new HttpTransportBindingConfig(remoteEndpoint));
            ClientBindingContext        ctx        = new ClientBindingContext(m_version);

            ctx.ReceiveTimeout = new TimeSpan(0, 0, 0, 0, ReceiveTimeout);
            ctx.OpenTimeout    = new TimeSpan(0, 0, 0, 0, RequestTimeout);
            ctx.SendTimeout    = new TimeSpan(0, 0, 0, 0, SendTimeout);

            httpClient.EndpointAddress = remoteEndpoint;

            Stream stream = null;

            try
            {
                httpClient.Open(ref stream, ctx);

                httpClient.ProcessOutputMessage(ref request, ctx);

                ctx.BindingProperties.Clear();

                httpClient.ProcessInputMessage(ref response, ctx);

                ctx.BindingProperties.Clear();

                if (response.Body is byte[])
                {
                    response.Reader = WsSoapMessageParser.ParseSoapMessage((byte[])response.Body, ref response.Header, m_version);
                }
            }
            finally
            {
                httpClient.Close(stream, ctx);
            }

            return(response);
        }
예제 #5
0
        private XmlReader ProcessResponse(byte[] response, String messageID, String action)
        {
            WsWsaHeader header = new WsWsaHeader();

            XmlReader reader = WsSoapMessageParser.ParseSoapMessage(response, ref header, m_version);

            if (header.Action == m_version.AddressingNamespace + "/fault")
            {
                WsFault.ParseFaultResponseAndThrow(reader);
            }
            else if (header.Action != m_version.EventingNamespace + "/" + action)
            {
                throw new XmlException();
            }

            // Make sure this response matches the request
            if (header.RelatesTo != messageID)
            {
                throw new XmlException();
            }

            return(reader);
        }
예제 #6
0
        private XmlReader ProcessResponse(byte[] response, String messageID, String action)
        {
            WsWsaHeader header;
            XmlReader   reader;

            reader = WsSoapMessageParser.ParseSoapMessage(response, out header);

            try
            {
                if (
                    (header.Action == WsWellKnownUri.WsaNamespaceUri_2004_08 + "/fault") ||
                    (header.Action == WsWellKnownUri.WsaNamespaceUri_2005_08 + "/fault")
                    )
                {
                    WsFault.ParseFaultResponseAndThrow(reader);
                }
                else if (header.Action != WsWellKnownUri.WseNamespaceUri + "/" + action)
                {
                    throw new XmlException();
                }

                // Make sure this response matches the request
                if (header.RelatesTo != messageID)
                {
                    throw new XmlException("Invalid message ID in response. Id does not match request ID.");
                }

                return(reader);
            }
            catch
            {
                // if something's wrong, close the reader, and rethrow the exception
                reader.Close();
                throw;
            }
        }
예제 #7
0
        /// <summary>
        /// Send an Http request containing an mtom message to an endpoint and waits for a response.
        /// </summary>
        /// <param name="bodyParts">A reference to the WsMtomBodyParts collection used to generate a mime multipart message.</param>
        /// <param name="endpointAddress">A string containing the endpoint address of a service that will receive
        /// <param name="isOneway">True = don't wait for response, false means wait for a response.</param>
        /// <param name="isChuncked">If true true the message will be chunk encoded.</param>
        /// <returns>
        /// A DpwSoapResponse object containing a WsWsaHeader and an XmlReader or null if no response is received
        /// or parsing fails.
        /// </returns>
        public DpwsSoapResponse SendRequest(ref WsMtomBodyParts bodyParts, string endpointAddress, bool isOneWay, bool isChuncked)
        {
            WsMtomParams mtomParams = new WsMtomParams();

            if (bodyParts.Boundary == null)
            {
                bodyParts.Boundary = Guid.NewGuid().ToString() + '-' + Guid.NewGuid().ToString().Substring(0, 33);
            }
            mtomParams.start    = bodyParts.Start;
            mtomParams.boundary = bodyParts.Boundary;
            WsMtom mtom = new WsMtom();

            byte[]    message  = mtom.CreateMessage(bodyParts);
            WsMessage response = SendRequest(message, endpointAddress, isOneWay, isChuncked, mtomParams);

            if (isOneWay)
            {
                return(null);
            }

            XmlReader   reader;
            WsWsaHeader header;

            try
            {
                reader    = WsSoapMessageParser.ParseSoapMessage(response.Message, out header);
                bodyParts = response.BodyParts;
            }
            catch
            {
                System.Ext.Console.Write("ParseSoapMessage failed.");
                return(null);
            }

            return(new DpwsSoapResponse(header, reader));
        }
예제 #8
0
        /// <summary>
        /// Use to send a resolve request to the ws-discovery address and receive a resolve match.
        /// </summary>
        /// <param name="message">A byte array containing a the resolve message.</param>
        /// <param name="messageID">
        /// A string containing the message ID of a resolve request. This ID will be used to validate against
        /// a ResolveMatch received if it don't match, the ResolveMatch is discarded.
        /// </param>
        /// <param name="timeout">
        /// A DateTime value containing the length of time this request will wait for resolve match.
        /// until the timeout value has expired.
        /// </param>
        /// <returns>A resolve match object.</returns>
        private DpwsServiceDescription SendResolveRequest(byte[] message, string messageID, long timeout)
        {
            WsMessageCheck messageCheck = new WsMessageCheck();

            DpwsServiceDescription resolveMatch = null;

            System.Ext.Console.Write("");
            System.Ext.Console.Write("Sending Resolve:");
            System.Ext.Console.Write(message);

            // Create a new UdpClient
            using (Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                uint       ipLocal = WsNetworkServices.GetLocalIPV4AddressValue();
                IPAddress  localIP = IPAddress.Parse(WsNetworkServices.GetLocalIPV4Address());
                IPEndPoint localEP = new IPEndPoint(localIP, 0);

                // Very important - Set default multicast interface for the underlying socket
                udpClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)ipLocal);
                udpClient.ReceiveTimeout = (int)timeout;

                udpClient.Bind(localEP);

                // Random back off implemented as per soap over udp specification
                // for unreliable multicast message exchange
                Thread th = SendWithBackoff(message, udpClient);

                // Wait for resolve match as long a timeout has not expired
                byte[]   resolveResponse = new byte[c_MaxUdpPacketSize];
                EndPoint remoteEP        = new IPEndPoint(IPAddress.Any, 0);
                int      responseLength;
                DpwsDiscoClientProcessor soapProcessor = new DpwsDiscoClientProcessor(m_version);

                while (true)
                {
                    // Since MF sockets does not have an IOControl method catch 10054 to get around the problem
                    // with Upd and ICMP.
                    try
                    {
                        // Wait for response
                        responseLength = udpClient.ReceiveFrom(resolveResponse, c_MaxUdpPacketSize, SocketFlags.None, ref remoteEP);
                    }
                    catch (SocketException se)
                    {
                        if ((SocketError)se.ErrorCode == SocketError.ConnectionReset)
                        {
                            Thread.Sleep(100);
                            continue;
                        }

                        if ((SocketError)se.ErrorCode == SocketError.TimedOut)
                        {
                            break;
                        }

                        throw se;
                    }

                    // If we received process resolve match
                    if (responseLength > 0)
                    {
                        System.Ext.Console.Write("ResolveMatches Response From: " + ((IPEndPoint)remoteEP).Address.ToString());
                        System.Ext.Console.Write(resolveResponse);

                        try
                        {
                            WsWsaHeader header = new WsWsaHeader();

                            XmlReader reader = WsSoapMessageParser.ParseSoapMessage(resolveResponse, ref header, m_version);

                            WsMessage msg = new WsMessage(header, null, WsPrefix.Wsdp);

                            msg.Reader = reader;

                            resolveMatch = soapProcessor.ProcessResolveMatch(msg, messageID, (IPEndPoint)remoteEP, messageCheck);
                            if (resolveMatch != null)
                            {
                                break;
                            }
                        }
                        catch (Exception e)
                        {
                            System.Ext.Console.Write(e.Message);
                        }
                    }
                }

                th.Join();
            }

            // Display results
            if (resolveMatch == null)
            {
                System.Ext.Console.Write("Resolve timed out.");
            }

            return(resolveMatch);
        }
예제 #9
0
        /// <summary>
        /// Sends a Probe request and parses ProbeMatches responses.
        /// </summary>
        /// <param name="filters">
        /// A DpwsServiceTypes object containing a collection of types a service must support to signal a match.
        /// Null = any type.
        /// </param>
        /// <param name="maxProbeMatches">
        /// An integer representing the maximum number of matches to reveive within the timout period. Pass 0 to receive
        /// as many matches as possible before the timeout expires.
        /// </param>
        /// <param name="timeout">
        /// An integer specifying a request timeout in milliseconds. Pass -1 to wait ReceiveTimeout.
        /// </param>
        /// <remarks>
        /// A Probe is used to discover services on a network. The Probe method sends a UDP request to the
        /// Dpws multicast address, 239.255.255.250:3702. Any service that implements types specified in the
        /// filters parameter should respond with a ProbeMatches message. The ProbeMatches mesgage is unicast
        /// back to the that client that made the request. If a null filter is supplied any Dpws complient
        /// service should reply with a ProbeMatches reponse. Probe waits DpwsDiceoveryCleint.ReceiveTimout
        /// for probe matches.
        /// </remarks>
        /// <returns>
        /// A collection of ProbeMatches objects.  A ProbeMatch object contains endpoint details used
        /// used to locate the actual service on a network and the types supported by the service.
        /// </returns>
        public DpwsServiceDescriptions Probe(DpwsServiceTypes filters, int maxProbeMatches, int timeout)
        {
            // Build the probe request message
            WsMessageCheck          messageCheck = new WsMessageCheck();
            string                  messageID    = null;
            WsMessage               probeRequest = BuildProbeRequest(DiscoVersion.DiscoveryWellKnownAddress, filters, out messageID);
            DpwsServiceDescriptions probeMatches = new DpwsServiceDescriptions();

            System.Ext.Console.Write("");
            System.Ext.Console.Write("Sending Probe:");
            System.Ext.Console.Write(probeRequest.Body as byte[]);
            System.Ext.Console.Write("");

            // Create a new UdpClient
            using (Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                // Very important - Set default multicast interface for the underlying socket

                uint       ipLocal = WsNetworkServices.GetLocalIPV4AddressValue();
                IPAddress  localIP = IPAddress.Parse(WsNetworkServices.GetLocalIPV4Address());
                IPEndPoint localEP = new IPEndPoint(localIP, 0);

                udpClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)ipLocal);
                udpClient.ReceiveTimeout = timeout;

                udpClient.Bind(localEP);

                // Random back off implemented as per soap over udp specification
                // for unreliable multicast message exchange
                Thread th = SendWithBackoff((byte[])probeRequest.Body, udpClient);

                // Create probe matches collection and set expiration loop timer
                byte[]   probeResponse = new byte[c_MaxUdpPacketSize];
                EndPoint remoteEP      = new IPEndPoint(IPAddress.Any, 0);
                int      responseLength;

                DpwsDiscoClientProcessor soapProcessor = new DpwsDiscoClientProcessor(m_version);

                while (true)
                {
                    // Since MF sockets does not have an IOControl method catch 10054 to get around the problem
                    // with Upd and ICMP.
                    try
                    {
                        // Wait for response
                        responseLength = udpClient.ReceiveFrom(probeResponse, c_MaxUdpPacketSize, SocketFlags.None, ref remoteEP);
                    }
                    catch (SocketException se)
                    {
                        if ((SocketError)se.ErrorCode == SocketError.ConnectionReset)
                        {
                            Thread.Sleep(100);
                            continue;
                        }

                        // Timeout
                        if ((SocketError)se.ErrorCode == SocketError.TimedOut)
                        {
                            break;
                        }

                        throw se;
                    }

                    // If we received process probe match
                    if (responseLength > 0)
                    {
                        System.Ext.Console.Write("");
                        System.Ext.Console.Write("ProbeMatches Response From: " + ((IPEndPoint)remoteEP).Address.ToString());
                        System.Ext.Console.Write(probeResponse);

                        // Process the response
                        try
                        {
                            WsWsaHeader header = new WsWsaHeader();

                            XmlReader reader = WsSoapMessageParser.ParseSoapMessage(probeResponse, ref header, m_version);

                            WsMessage msg = new WsMessage(header, null, WsPrefix.Wsdp);

                            msg.Reader = reader;

                            DpwsServiceDescriptions tempMatches = soapProcessor.ProcessProbeMatch(msg, messageID, (IPEndPoint)remoteEP, messageCheck);
                            if (tempMatches != null)
                            {
                                int count = maxProbeMatches < tempMatches.Count ? maxProbeMatches : tempMatches.Count;

                                for (int i = 0; i < count; i++)
                                {
                                    probeMatches.Add(tempMatches[i]);
                                }
                                maxProbeMatches -= count;
                            }
                        }
                        catch (Exception e)
                        {
                            System.Ext.Console.Write("");
                            System.Ext.Console.Write(e.Message);
                            System.Ext.Console.Write("");
                        }

                        // If maxProbeRequest is set check count
                        if (maxProbeMatches <= 0)
                        {
                            break;
                        }
                    }
                }

                th.Join();
            }

            // Display results
            if (probeMatches.Count == 0)
            {
                System.Ext.Console.Write("Probe timed out.");
            }
            else
            {
                System.Ext.Console.Write("Received " + probeMatches.Count + " probeMatches matches.");
            }

            return(probeMatches);
        }
예제 #10
0
        /// <summary>
        /// Parses a transport message and builds a header object and envelope document then calls processRequest
        /// on a service endpoint.
        /// </summary>
        /// <param name="soapRequest">WsRequestMessage object containing a raw soap message or mtom soap request.</param>
        /// <returns>WsResponseMessage object containing the soap response returned from a service endpoint.</returns>
        private WsMessage ProcessRequestMessage(WsMessage soapRequest)
        {
            // Parse and validate the soap message
            WsWsaHeader header;
            XmlReader   reader;

            try
            {
                reader = WsSoapMessageParser.ParseSoapMessage(soapRequest.Message, out header);
            }
            catch (WsFaultException e)
            {
                return(WsFault.GenerateFaultResponse(e));
            }

            try
            {
                // Now check for implementation specific service endpoints.
                IWsServiceEndpoint serviceEndpoint = null;
                string             endpointAddress = null;

                // If this is Uri convert it
                if (header.To.IndexOf("urn") == 0 || header.To.IndexOf("http") == 0)
                {
                    // Convert to address to Uri
                    Uri toUri;
                    try
                    {
                        toUri = new Uri(header.To);
                    }
                    catch
                    {
                        System.Ext.Console.Write("Unsupported Header.To Uri format: " + header.To);
                        return(WsFault.GenerateFaultResponse(header, WsFaultType.ArgumentException, "Unsupported Header.To Uri format"));
                    }

                    // Convert the to address to a Urn:uuid if it is an Http endpoint
                    if (toUri.Scheme == "urn")
                    {
                        endpointAddress = toUri.AbsoluteUri;
                    }
                    else if (toUri.Scheme == "http")
                    {
                        endpointAddress = "urn:uuid:" + toUri.AbsoluteUri.Substring(1);
                    }
                    else
                    {
                        endpointAddress = header.To;
                    }
                }
                else
                {
                    endpointAddress = "urn:uuid:" + header.To;
                }

                // Look for a service at the requested endpoint that contains an operation matching the Action
                // This hack is required because service spec writers determined that more than one service type
                // can live at a single endpoint address. Why you would want to break the object model and allow
                // this feature is unknown so for now we must hack.
                bool eventingReqFlag = true;
                for (int i = 0; i < m_serviceEndpoints.Count; ++i)
                {
                    if (m_serviceEndpoints[i].EndpointAddress == endpointAddress)
                    {
                        if (m_serviceEndpoints[i].ServiceOperations[header.Action] != null)
                        {
                            serviceEndpoint = m_serviceEndpoints[i];
                            eventingReqFlag = false;
                            break;
                        }
                    }
                }

                // Worst part of the hack: If no matching endpoint is found assume this is an event subscription
                // request and call the base eventing methods on any class. They had to be Global because of this feature.
                // Now the subscription manager must determine globally that a suitable web service is found. Yuch!!
                if (eventingReqFlag)
                {
                    serviceEndpoint = m_serviceEndpoints[0];
                }

                // If a matching service endpoint is found call operation
                if (serviceEndpoint != null)
                {
                    // If this is mtom, copy the requests body parts to the hosted services body parts
                    // prior to making the call
                    if (soapRequest.MessageType == WsMessageType.Mtom)
                    {
                        serviceEndpoint.BodyParts = soapRequest.BodyParts;
                    }

                    // Process the request
                    byte[] response;
                    try
                    {
                        response = serviceEndpoint.ProcessRequest(header, reader);
                    }
                    catch (WsFaultException e)
                    {
                        return(WsFault.GenerateFaultResponse(e));
                    }
                    catch (Exception e)
                    {
                        return(WsFault.GenerateFaultResponse(header, WsFaultType.Exception, e.ToString()));
                    }

                    // If the message response type is Soap return a SoapMessage type
                    if (serviceEndpoint.MessageType == WsMessageType.Soap)
                    {
                        if (response == null)
                        {
                            return(null);
                        }

                        return(new WsMessage(response));
                    }

                    // If the response is Mtom build an mtom response message
                    else // if (serviceEndpoint.MessageType == WsMessageType.Mtom)
                    {
                        return(new WsMessage(serviceEndpoint.BodyParts));
                    }
                }

                // Unreachable endpoint requested. Generate fault response
                return(WsFault.GenerateFaultResponse(header, WsFaultType.WsaDestinationUnreachable, "Unknown service endpoint"));
            }
            finally
            {
                reader.Close();
            }
        }
예제 #11
0
        private DpwsServiceDescriptions ProcessMatch(DpwsServiceDescription.ServiceDescriptionType type, byte[] response, string messageID, IPEndPoint remoteEP, WsMessageCheck messageCheck)
        {
            Microsoft.SPOT.Debug.Assert(type == DpwsServiceDescription.ServiceDescriptionType.ProbeMatch ||
                                        type == DpwsServiceDescription.ServiceDescriptionType.ResolveMatch);

            // Parse and build header
            WsWsaHeader header;
            XmlReader   reader;

            try
            {
                reader = WsSoapMessageParser.ParseSoapMessage(response, out header);
            }
            catch
            {
                return(null);
            }

            try
            {
                // Make sure this is a probe matches response
                String headerAction = (type == DpwsServiceDescription.ServiceDescriptionType.ProbeMatch) ?
                                      WsWellKnownUri.WsdNamespaceUri + "/ProbeMatches" :
                                      WsWellKnownUri.WsdNamespaceUri + "/ResolveMatches";

                if (header.Action != headerAction)
                {
                    return(null);
                }

                // Make sure this is not a duplicate probe response
                if (messageCheck != null)
                {
                    if (messageCheck.IsDuplicate(header.MessageID, remoteEP.ToString()) == true)
                    {
                        System.Ext.Console.Write("ProbeMatches / ResolveMatches - Duplicate response - " + header.Action + " received");
                        return(null);
                    }
                }

                // Make sure the messageID matches the request ID
                if (header.RelatesTo != messageID)
                {
                    return(null);
                }

                // Process the probe matches
#if DEBUG
                int depth = reader.Depth;
#endif
                DpwsServiceDescriptions matches = new DpwsServiceDescriptions(reader, type);
#if DEBUG
                Microsoft.SPOT.Debug.Assert(XmlReaderHelper.HasReadCompleteNode(depth, reader));
#endif

                return(matches);
            }
            finally
            {
                reader.Close();
            }
        }