/// <summary> /// Resolve a host IP address to a host name /// </summary> /// <param name="hostIp"></param> /// <param name="HostPort"></param> /// <returns></returns> /// <remarks>This first makes a DNS query and uses the result if found. If not found it then tries a Microsoft DNS call which also searches the local hosts and makes a netbios query. /// If this returns an answer it is use. Otherwise the IP address is returned as the host name</remarks> private void ResolveIpAddressToHostName(object deviceIpEndPointObject) { IPEndPoint deviceIpEndPoint = deviceIpEndPointObject as IPEndPoint; // Get the supplied device endpoint as an IPEndPoint DnsResponse dnsResponse = new DnsResponse(); // Create a new DnsResponse to hold and return the // Calculate the remaining time before this discovery needs to finish and only undertake DNS resolution if sufficient time remains TimeSpan timeOutTime = TimeSpan.FromSeconds(discoveryTime).Subtract(DateTime.Now - discoveryStartTime).Subtract(TimeSpan.FromSeconds(0.2)); if (timeOutTime.TotalSeconds > 0.2) { LogMessage("ResolveIpAddressToHostName", $"Resolving IP address: {deviceIpEndPoint.Address.ToString()}, Timeout: {timeOutTime}"); Dns.BeginGetHostEntry(deviceIpEndPoint.Address.ToString(), new AsyncCallback(GetHostEntryCallback), dnsResponse); // Wait here until the resolve completes and the callback calls .Set() bool dnsWasResolved = dnsResponse.CallComplete.WaitOne(timeOutTime); // Wait for the remaining discovery time less a small amount if (dnsWasResolved) // A response was received rather than timing out { LogMessage("ResolveIpAddressToHostName", $"{deviceIpEndPoint.ToString()} has host name: {dnsResponse.HostName} IP address count: {dnsResponse.AddressList.Length} Alias count: { dnsResponse.Aliases.Length}"); if (dnsResponse.AddressList.Length > 0) { lock (deviceListLockObject) { alpacaDeviceList[deviceIpEndPoint].HostName = dnsResponse.HostName; } RaiseAnAlpacaDevicesChangedEvent(); // Device list was changed so set the changed flag } else { LogMessage("ResolveIpAddressToHostName", $"***** DNS responded with a name ({dnsResponse.HostName}) but this has no associated IP addresses and is probably a NETBIOS name *****"); } foreach (IPAddress address in dnsResponse.AddressList) { LogMessage("ResolveIpAddressToHostName", $"Address: {address}"); } foreach (string alias in dnsResponse.Aliases) { LogMessage("ResolveIpAddressToHostName", $"Alias: {alias}"); } } else { LogMessage("ResolveIpAddressToHostName", $"***** DNS did not respond within timeout - unable to resolve IP address to host name *****"); } } else { LogMessage("ResolveIpAddressToHostName", $"***** Insufficient time remains ({timeOutTime.TotalSeconds} seconds) to conduct a DNS query, ignoring request *****"); } }
/// <summary> /// Record the IPs in the state object for later use. /// </summary> private void GetHostEntryCallback(IAsyncResult ar) { try { DnsResponse dnsResponse = (DnsResponse)ar.AsyncState; // Turn the state object into the DnsResponse type dnsResponse.IpHostEntry = Dns.EndGetHostEntry(ar); // Save the returned IpHostEntry and populate other fields based on its parameters dnsResponse.CallComplete.Set(); // Set the wait handle so that the caller knows that the asynchronous call has completed and that the response has been updated } catch (Exception ex) { LogMessage("GetHostEntryCallback", $"Exception: {ex.ToString()}"); // Log exceptions but don't throw them } }