/// <summary> /// Initializes the device. This method builds the colletion of internal device services, sets /// the devices transport address and adds DPWS required namespaces to the devices namespace collection. /// </summary> public static void Initialize(Binding binding, ProtocolVersion v) { m_binding = binding; string addr = binding.Transport.EndpointAddress.AbsoluteUri; int index = addr.LastIndexOf('/'); m_address = "urn:uuid:" + addr.Substring(index + 1); SubscriptionManager = new DpwsWseSubscriptionMgr(binding, v); if (v != null) { // Add disco services to udp service endpoints collection m_discoveryService = new DpwsDeviceDiscoService(v); m_discoGreeting = new DpwsDiscoGreeting(v); // Create a new udp service host and add the discovery endpoints WsUdpServiceHost.Instance.AddServiceEndpoint(m_discoveryService); } // Add metadata get service endpoint m_discoMexService = new DpwsDeviceMexService(v); m_hostedServices.DiscoMexService = m_discoMexService; // Add direct probe service endpoint if (m_discoveryService != null) { m_hostedServices.Add(m_discoveryService); } // Create a new http service host and add hosted services endpoints m_httpServiceHost = new WsHttpServiceHost(m_binding, m_hostedServices); System.Ext.Console.Write("IP Address: " + WsNetworkServices.GetLocalIPV4Address()); }
/// <summary> /// Creates an instance of the UDP binding element /// </summary> /// <param name="cfg">The configuration associated with this binding element.</param> public UdpTransportBindingElement(UdpTransportBindingConfig cfg) { m_config = cfg; if (s_localIP == null) { s_localIP = IPAddress.Parse(WsNetworkServices.GetLocalIPV4Address()); } }
/// <summary> /// Method used to send Hello and Bye messages /// </summary> /// <param name="greetingType">An integer representing the type of greeting 0 = Hello, 1 = Bye.</param> public static void SendGreetingMessage(bool isHello) { // If Adhoc disco is turned off return. Adhoc disco is optional with a Discovery Proxy if (Device.SupressAdhoc == true) { return; } byte[] greetingsMessage = null; if (isHello) { greetingsMessage = BuildHelloMessage(Device.DiscoVersion.WellKnownAddress, null, null); } else { greetingsMessage = BuildByeMessage(Device.DiscoVersion.WellKnownAddress, null, null); } // Create a UdpClient used to send Hello and Bye messages Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Very important - Set default multicast interface for the underlying socket byte[] ipBytes = IPAddress.Parse(WsNetworkServices.GetLocalIPV4Address()).GetAddressBytes(); long longIP = (long)((ipBytes[0] + (ipBytes[1] << 0x08) + (ipBytes[2] << 0x10) + (ipBytes[3] << 0x18)) & 0xFFFFFFFF); udpClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)longIP); if (DiscoveryEP == null) { DiscoveryEP = new IPEndPoint(new IPAddress(DiscoveryAddress), DiscoveryPort); } // Random back off implemented as per soap over udp specification // for unreliable multicast message exchange Random rand = new Random(); int backoff = 0; for (int i = 0; i < MulticastUdpRepeat; ++i) { if (i == 0) { backoff = rand.Next(UdpMaxDelay - UdpMinDelay) + UdpMinDelay; } else { backoff = backoff * 2; backoff = backoff > UdpUpperDelay ? UdpUpperDelay : backoff; } Thread.Sleep(backoff); udpClient.SendTo(greetingsMessage, greetingsMessage.Length, SocketFlags.None, DiscoveryEP); } udpClient.Close(); }
/// <summary> /// Creates an instance of the configuration for the HTTP transport /// </summary> /// <param name="serviceUrn">The service Urn.</param> /// <param name="port">The servce port.</param> public HttpTransportBindingConfig(string serviceUrn, int port) { this.ServiceUrn = new Uri(serviceUrn); string transport = "http://" + WsNetworkServices.GetLocalIPV4Address() + ":" + port + "/"; if (serviceUrn.IndexOf("urn:uuid:") == 0) { this.EndpointAddress = new Uri(transport + serviceUrn.Substring(9), UriKind.Absolute); // strip off urn:uuid: } else { this.EndpointAddress = new Uri(transport + serviceUrn, UriKind.Absolute); } }
/// <summary> /// Processes a message /// </summary> /// <param name="stream">The message being processed.</param> /// <param name="ctx">The context associated with the message.</param> /// <returns>The handling status for this operation.</returns> protected override ChainResult OnProcessInputMessage(ref WsMessage msg, BindingContext ctx) { byte[] soapMessage = null; byte[] buffer = new byte[MaxUdpPacketSize]; while (true) { EndPoint remoteEndpoint = new IPEndPoint(IPAddress.Any, 0); int size = m_udpReceiveClient.ReceiveFrom(buffer, MaxUdpPacketSize, SocketFlags.None, ref remoteEndpoint); // If the stack is set to ignore request from this address do so if (m_config.IgnoreRequestsFromThisIp && ((IPEndPoint)m_remoteEndpoint).Address.ToString() == WsNetworkServices.GetLocalIPV4Address()) { continue; } if (size > 0) { soapMessage = new byte[size]; Array.Copy(buffer, soapMessage, size); } else { System.Ext.Console.Write("UDP Receive returned 0 bytes"); } m_remoteEndpoint = remoteEndpoint; break; } System.Ext.Console.Write("UDP Request From: " + m_remoteEndpoint.ToString()); System.Ext.Console.Write(soapMessage); msg.Body = soapMessage; return(ChainResult.Continue); }
/// <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); }
/// <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); }
public virtual WsMessage ProbeMatch(WsMessage probe, DpwsHostedService matchedService) { XmlReader reader = probe.Reader; WsWsaHeader header = probe.Header; // Performance debugging DebugTiming timeDebuger = new DebugTiming(); long startTime = timeDebuger.ResetStartTime(""); // Build ProbeMatch using (XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { // If a Host exist write the Host namespace WsXmlNamespaces additionalPrefixes = null; if (Device.Host != null) { additionalPrefixes = new WsXmlNamespaces(); additionalPrefixes.Add(Device.Host.ServiceNamespace); } WsWsaHeader matchHeader = new WsWsaHeader( this.Version.DiscoveryNamespace + "/ProbeMatches", // Action header.MessageID, // RelatesTo this.Version.AnonymousUri, // To null, null, null); // ReplyTo, From, Any WsMessage msg = new WsMessage(matchHeader, null, WsPrefix.Wsd | WsPrefix.Wsdp, additionalPrefixes, new WsAppSequence(Device.AppSequence, Device.SequenceID, Device.MessageID)); WsSoapMessageWriter smw = new WsSoapMessageWriter(this.Version); smw.WriteSoapMessageStart(xmlWriter, msg); // Performance debuging timeDebuger.PrintElapsedTime("*****Write Header Took"); // write body xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "ProbeMatches", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "ProbeMatch", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "EndpointReference", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "Address", null); xmlWriter.WriteString(matchedService == null ? Device.EndpointAddress : matchedService.EndpointAddress); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); // Write hosted service types xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "Types", null); WriteDeviceServiceTypes(xmlWriter); xmlWriter.WriteEndElement(); // End Types xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "XAddrs", null); string transport = Device.TransportAddress; if (matchedService != null) { int idx = transport.LastIndexOf('/'); if (idx != -1) { transport = transport.Substring(0, idx + 1); transport += matchedService.EndpointAddress.Substring(matchedService.EndpointAddress.IndexOf("urn:uuid:") + 9); } } int idx2 = transport.ToLower().IndexOf("localhost"); if (idx2 != -1) { transport = transport.Substring(0, idx2) + WsNetworkServices.GetLocalIPV4Address() + transport.Substring(idx2 + 9 /*localhost*/); } xmlWriter.WriteString(transport); xmlWriter.WriteEndElement(); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "MetadataVersion", null); xmlWriter.WriteString(Device.MetadataVersion.ToString()); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); smw.WriteSoapMessageEnd(xmlWriter); msg.Body = xmlWriter.ToArray(); // Performance debuging timeDebuger.PrintTotalTime(startTime, "***ProbeMatch Took"); // Delay probe match as per Ws-Discovery specification (2.4 Protocol Assignments) Thread.Sleep(new Random().Next(Device.ProbeMatchDelay)); // Return stream buffer return(msg); } }
public virtual WsMessage ResolveMatch(WsMessage message) { XmlReader reader = message.Reader; WsWsaHeader header = message.Header; bool match = false; string epAddr = ""; reader.ReadStartElement("Resolve", this.Version.DiscoveryNamespace); if (reader.IsStartElement("EndpointReference", this.Version.AddressingNamespace) == false) { return(null); } WsWsaEndpointRef epRef = new WsWsaEndpointRef(reader, this.Version.AddressingNamespace); epAddr = epRef.Address.AbsoluteUri; if (Device.EndpointAddress != epAddr) { // If the destination endpoint is ours send a resolve match else return null int servicesCount = Device.HostedServices.Count; DpwsHostedService hostedService; for (int i = 0; i < servicesCount; i++) { hostedService = (DpwsHostedService)Device.HostedServices[i]; // Skip internal services if (hostedService.ServiceTypeName == "Internal") { continue; } if (hostedService.EndpointAddress == epAddr) { match = true; break; } } if (!match) { return(null); } } // Build ResolveMatch using (XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { // If a Host exist write the Host namespace WsXmlNamespaces additionalPrefixes = null; if (Device.Host != null) { additionalPrefixes = new WsXmlNamespaces(); additionalPrefixes.Add(Device.Host.ServiceNamespace); } WsWsaHeader matchHeader = new WsWsaHeader( this.Version.DiscoveryNamespace + "/ResolveMatches", // Action header.MessageID, // RelatesTo this.Version.AnonymousUri, // To null, null, null); // ReplyTo, From, Any WsMessage msg = new WsMessage(matchHeader, null, WsPrefix.Wsd | WsPrefix.Wsdp, additionalPrefixes, new WsAppSequence(Device.AppSequence, Device.SequenceID, Device.MessageID)); WsSoapMessageWriter smw = new WsSoapMessageWriter(this.Version); smw.WriteSoapMessageStart(xmlWriter, msg); // write body xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "ResolveMatches", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "ResolveMatch", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "EndpointReference", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "Address", null); xmlWriter.WriteString(epRef.Address.AbsoluteUri); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteEndElement(); // End EndpointReference // Write hosted service types xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "Types", null); WriteDeviceServiceTypes(xmlWriter); xmlWriter.WriteEndElement(); // End Types string transport = Device.TransportAddress; if (match) { int idx = transport.LastIndexOf('/'); if (idx != -1) { transport = transport.Substring(0, idx + 1); transport += epAddr.Substring(epAddr.IndexOf("urn:uuid:") + 9); } } int idx2 = transport.ToLower().IndexOf("localhost"); if (idx2 != -1) { transport = transport.Substring(0, idx2) + WsNetworkServices.GetLocalIPV4Address() + transport.Substring(idx2 + 9 /*localhost*/); } xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "XAddrs", null); xmlWriter.WriteString(transport); xmlWriter.WriteEndElement(); // End XAddrs xmlWriter.WriteStartElement(WsNamespacePrefix.Wsd, "MetadataVersion", null); xmlWriter.WriteString(Device.MetadataVersion.ToString()); xmlWriter.WriteEndElement(); // End MetadataVersion xmlWriter.WriteEndElement(); // End ResolveMatch xmlWriter.WriteEndElement(); // End ResolveMatches smw.WriteSoapMessageEnd(xmlWriter); msg.Body = xmlWriter.ToArray(); // Return stream buffer return(msg); } }
/// <summary> /// Listens for Udp request on 239.255.255.250:3702 /// </summary> /// <remarks>On initialization it sends a Discovery Hello message and listens on the Ws-Discovery /// endpoint for a request. When a request arrives it starts a UdpProcess thread that processes the message. /// The number of UdpProcessing threads are limited by the Device.MaxUdpRequestThreads property. /// </remarks> public void Listen() { // Create a duplicate message tester. WsMessageCheck messageCheck = new WsMessageCheck(40); // Create remote endpoint reference, start listening byte[] buffer = new byte[c_MaxUdpPacketSize]; int size; bool threadPoolDepletedFlag = false; m_servicesRunning = !m_requestStop; while (!m_requestStop) { try { // If threads ara availble receive next message. If we are waiting on threads let the socket // buffer request until we get a thread. This will work until the reveice buffer is depleted // at which time request will be dropped if (m_threadManager.ThreadsAvailable == true) { threadPoolDepletedFlag = false; EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); size = m_udpReceiveClient.ReceiveFrom(buffer, c_MaxUdpPacketSize, SocketFlags.None, ref remoteEP); // If the stack is set to ignore request from this address do so if (this.IgnoreRequestFromThisIP == true && ((IPEndPoint)remoteEP).Address.ToString() == WsNetworkServices.GetLocalIPV4Address()) { continue; } if (size > 0) { byte[] soapMessage = new byte[size]; Array.Copy(buffer, soapMessage, size); System.Ext.Console.Write("UDP Request From: " + remoteEP.ToString()); System.Ext.Console.Write(new String(System.Text.Encoding.UTF8.GetChars(soapMessage))); // Try to get a processing thread and process the request m_threadManager.StartNewThread(new WsUdpMessageProcessor(m_serviceEndpoints, soapMessage, (IPEndPoint)remoteEP, messageCheck)); } else { System.Ext.Console.Write("UDP Receive returned 0 bytes"); } } else { if (threadPoolDepletedFlag == false) { System.Ext.Console.Write("Udp service host waiting for a thread..."); threadPoolDepletedFlag = true; } } } catch (SocketException se) { // Since the MF Socket does not have IOControl that would be used to turn off ICMP notifications // for UDP, catch 10054 and try to continue if (se.ErrorCode == 10054) { continue; } } catch (Exception e) { System.Ext.Console.Write(e.Message + " " + e.InnerException); } Thread.Sleep(100); } }
/// <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(); System.Ext.Console.Write(""); System.Ext.Console.Write("Sending Resolve:"); System.Ext.Console.Write(new string(new UTF8Encoding().GetChars(message))); // Create a new UdpClient Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint localEP = new IPEndPoint(IPAddress.Any, m_discoResponsePort); udpClient.Bind(localEP); // Very important - Set default multicast interface for the underlying socket byte[] ipBytes = IPAddress.Parse(WsNetworkServices.GetLocalIPV4Address()).GetAddressBytes(); long longIP = (long)((ipBytes[0] + (ipBytes[1] << 0x08) + (ipBytes[2] << 0x10) + (ipBytes[3] << 0x18)) & 0xFFFFFFFF); udpClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)longIP); // Random back off implemented as per soap over udp specification // for unreliable multicast message exchange SendWithBackoff(message, udpClient); // Wait for resolve match as long a timeout has not expired DpwsServiceDescription resolveMatch = null; byte[] resolveResponse = new byte[c_MaxUdpPacketSize]; EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); int responseLength; long endTime = (long)(DateTime.Now.Ticks + (timeout * 10000)); DpwsDiscoClientProcessor soapProcessor = new DpwsDiscoClientProcessor(); while (DateTime.Now.Ticks < endTime) { if (udpClient.Available > 0) { // 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 (se.ErrorCode == 10054) { continue; } throw se; } // If we received process resolve match if (responseLength > 0) { System.Ext.Console.Write(""); System.Ext.Console.Write("ResolveMatches Response From: " + ((IPEndPoint)remoteEP).Address.ToString()); System.Ext.Console.Write(new String(System.Text.Encoding.UTF8.GetChars(resolveResponse))); try { resolveMatch = soapProcessor.ProcessResolveMatch(resolveResponse, messageID, (IPEndPoint)remoteEP, messageCheck); if (resolveMatch != null) { break; } } catch (Exception e) { System.Ext.Console.Write(""); System.Ext.Console.Write(e.Message); System.Ext.Console.Write(""); } } } Thread.Sleep(10); } udpClient.Close(); udpClient = null; // Display results if (resolveMatch == null) { System.Ext.Console.Write("Resolve timed out."); } return(resolveMatch); }
/// <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; byte[] probeRequest = BuildProbeRequest(DiscoVersion.WellKnownAddress, filters, out messageID); System.Ext.Console.Write(""); System.Ext.Console.Write("Sending Probe:"); System.Ext.Console.Write(new string(new UTF8Encoding().GetChars(probeRequest))); System.Ext.Console.Write(""); // Create a new UdpClient Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint localEP = new IPEndPoint(IPAddress.Any, m_discoResponsePort); udpClient.Bind(localEP); // Very important - Set default multicast interface for the underlying socket byte[] ipBytes = IPAddress.Parse(WsNetworkServices.GetLocalIPV4Address()).GetAddressBytes(); long longIP = (long)((ipBytes[0] + (ipBytes[1] << 0x08) + (ipBytes[2] << 0x10) + (ipBytes[3] << 0x18)) & 0xFFFFFFFF); udpClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)longIP); // Random back off implemented as per soap over udp specification // for unreliable multicast message exchange SendWithBackoff(probeRequest, udpClient); // Create probe matches collection and set expiration loop timer DpwsServiceDescriptions probeMatches = new DpwsServiceDescriptions(); byte[] probeResponse = new byte[c_MaxUdpPacketSize]; EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); int responseLength; // Multiply receive time by 10000 to convert milliseconds to 100 nano ticks long endTime = (long)(DateTime.Now.Ticks + (timeout < 0 ? m_receiveTimeout * 10000 : timeout * 10000)); DpwsDiscoClientProcessor soapProcessor = new DpwsDiscoClientProcessor(); // Build probe matches collection as long as timeout has not expired int noReceived = 0; while (DateTime.Now.Ticks < endTime) { if (udpClient.Available > 0) { // If maxProbeRequest is set check count if (maxProbeMatches > 0) { if (noReceived > maxProbeMatches) { break; } } // 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 (se.ErrorCode == 10054) { continue; } 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(new String(System.Text.Encoding.UTF8.GetChars(probeResponse))); // Process the response try { DpwsServiceDescriptions tempMatches = soapProcessor.ProcessProbeMatch(probeResponse, messageID, (IPEndPoint)remoteEP, messageCheck); if (tempMatches != null) { int count = tempMatches.Count; for (int i = 0; i < count; i++) { probeMatches.Add(tempMatches[i]); } } } catch (Exception e) { System.Ext.Console.Write(""); System.Ext.Console.Write(e.Message); System.Ext.Console.Write(""); } // Increment the number received counter ++noReceived; } } else { Thread.Sleep(1); } } udpClient.Close(); udpClient = null; // Display results if (probeMatches == null) { System.Ext.Console.Write("Probe timed out."); } else { System.Ext.Console.Write("Received " + probeMatches.Count + " probeMatches matches."); } return(probeMatches); }