/// <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 (SocketException ex) { LogMessage("GetHostEntryCallback", $"Socket Exception: {ex.Message}"); } catch (Exception ex) { LogMessage("GetHostEntryCallback", $"Exception: {ex}"); } // Log exceptions but don't throw them }
/// <summary> /// Resolve a host IP address to a host name /// </summary> /// <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 = null; try { deviceIpEndPoint = deviceIpEndPointObject as IPEndPoint; // Get the supplied device endpoint as an IPEndPoint // test whether the cast was successful if (deviceIpEndPoint is object) // The cast was successful so we can try to search for the host name { var 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 var timeOutTime = TimeSpan.FromSeconds(discoveryTime).Subtract(DateTime.Now - discoveryStartTime).Subtract(TimeSpan.FromSeconds(0.2d)); if (timeOutTime.TotalSeconds > Constants.MINIMUM_TIME_REMAINING_TO_UNDERTAKE_DNS_RESOLUTION) // We have more than the configured time left so we will attempt a reverse DNS name resolution { LogMessage("ResolveIpAddressToHostName", $"Resolving IP address: {deviceIpEndPoint.Address}, 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 // Execution continues here after either a DNS response is found or the request times out if (dnsWasResolved) // A response was received rather than timing out { LogMessage("ResolveIpAddressToHostName", $"{deviceIpEndPoint} has host name: {dnsResponse.HostName} IP address count: {dnsResponse.AddressList.Length} Alias count: {dnsResponse.Aliases.Length}"); foreach (IPAddress address in dnsResponse.AddressList) { LogMessage("ResolveIpAddressToHostName", $" Received {address.AddressFamily} address: {address}"); } foreach (string hostAlias in dnsResponse.Aliases) { LogMessage("ResolveIpAddressToHostName", $" Received alias: {hostAlias}"); } if (dnsResponse.AddressList.Length > 0) // We got a reply that contains host addresses so there may be a valid host name { lock (deviceListLockObject) { if (!string.IsNullOrEmpty(dnsResponse.HostName)) { 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 // DNS did not respond in time { LogMessage("ResolveIpAddressToHostName", $"***** DNS did not respond within timeout - unable to resolve IP address to host name *****"); } } else // There was insufficient time to query DNS { LogMessage("ResolveIpAddressToHostName", $"***** Insufficient time remains ({timeOutTime.TotalSeconds} seconds) to conduct a DNS query, ignoring request *****"); } } else // The IPEndPoint cast was not successful so we cannot carry out a DNS name search because we don't have the device's IP address { LogMessage("ResolveIpAddressToHostName", $"DNS resolution could not be undertaken - It was not possible to cast the supplied IPEndPoint object to an IPEndPoint type: {deviceIpEndPoint}."); } } catch (TimeoutException) { LogMessage("ResolveIpAddressToHostName", $"Timed out trying to resolve the DNS name for {(deviceIpEndPoint is null ? "Unknown IP address" : deviceIpEndPoint.ToString()) }"); } catch (Exception ex) { // Something went wrong, so log the issue and sent a message to the user LogMessage("ResolveIpAddressToHostName", $"Exception: {ex}"); } }