/// <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> /// 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 void SendGreetingMessage(bool isHello) { // If Adhoc disco is turned off return. Adhoc disco is optional with a Discovery Proxy if (Device.SupressAdhoc == true) { return; } WsMessage greetingsMessage = null; if (isHello) { greetingsMessage = BuildHelloMessage(Device.DiscoveryVersion.DiscoveryWellKnownAddress, null, null); } else { greetingsMessage = BuildByeMessage(Device.DiscoveryVersion.DiscoveryWellKnownAddress, null, null); } byte[] greeting = (byte[])greetingsMessage.Body; System.Ext.Console.Write("UDP (" + (isHello ? "Hello" : "Bye") + ") multicast to: " + WsDiscovery.WsDiscoveryEndPoint.ToString()); System.Ext.Console.Write(greetingsMessage.Body as byte[]); // Create a UdpClient used to send Hello and Bye messages using (Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { // Very important - Set default multicast interface for the underlying socket udpClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)WsNetworkServices.GetLocalIPV4AddressValue()); // 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; } udpClient.SendTo(greeting, greeting.Length, SocketFlags.None, WsDiscovery.WsDiscoveryEndPoint); Thread.Sleep(backoff); } } }
/// <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); }
/// <summary> /// UDP resend timer callback. Resends repsonse data for UDP messages. /// </summary> /// <param name="arg"></param> static private void UdpTimer(object arg) { int cnt; UdpResend[] resend = null; // get a copy of the resend list so that we don't have to lock the list // while we resend lock (s_repeats) { cnt = s_repeats.Count; if (cnt > 0) { resend = (UdpResend[])s_repeats.ToArray(typeof(UdpResend)); } else { s_udpTimer.Change(-1, -1); } } if (cnt > 0) { using (Socket udpSendClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { IPEndPoint localEP = new IPEndPoint(s_localIP, 0); udpSendClient.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)WsNetworkServices.GetLocalIPV4AddressValue()); udpSendClient.Bind(localEP); for (int i = cnt - 1; i >= 0; i--) { udpSendClient.SendTo(resend[i].Data, resend[i].Data.Length, SocketFlags.None, resend[i].RemoteEndpoint); if (0 >= --((UdpResend)s_repeats[i]).RepeatCount) { s_repeats.RemoveAt(i); } } } } }