Beispiel #1
0
        /// <summary>
        /// Attempts to resolve an IP address or fully qualified domain name
        /// into host IP addresses.
        /// </summary>
        /// <param name="addressOrFQDN">The IP address or FQDN.</param>
        /// <param name="noCache">
        /// Optionally specify that the method is not to answer from the cache,
        /// even if the cache is enabled.
        /// </param>
        /// <returns>An empty result set if the lookup failed.</returns>
        public async Task <IEnumerable <IPAddress> > LookupAsync(string addressOrFQDN, bool noCache = false)
        {
            await SyncContext.Clear;

            // We can short-circuit things if the parameter is an IP address.

            if (NetHelper.TryParseIPv4Address(addressOrFQDN, out var address))
            {
                return(new IPAddress[] { address });
            }

            // Try to answer from the cache, if enabled.

            if (cache != null && !noCache)
            {
                lock (cache)
                {
                    if (cache.TryGetValue(addressOrFQDN, out var answer))
                    {
                        if (answer.TTD > SysTime.Now)
                        {
                            // The answer hasn't expired yet, so we'll return it.

                            return(answer.Addresses);
                        }
                    }
                }
            }

            // We're going to submit requests to all DNS clients in parallel and
            // return replies from the first one that answers.

            var readyEvent = new AsyncAutoResetEvent();
            var sync       = new object();
            var pending    = clients.Length;
            var results    = (IList <IPAddress>)null;

            foreach (var client in clients)
            {
                var task = Task.Run(
                    async() =>
                {
                    try
                    {
                        var addresses = await client.Lookup(addressOrFQDN);

                        if (addresses.Count > 0)
                        {
                            lock (sync)
                            {
                                if (results == null)
                                {
                                    results = addresses;
                                }
                            }
                        }

                        Interlocked.Decrement(ref pending);
                        readyEvent.Set();
                    }
                    catch (ResponseException)
                    {
                        // $todo(jefflill):
                        //
                        // I wish the underlying [DnsClient] didn't throw exceptions.  Perhaps
                        // I could extend the implementation to implement [TryResolve()].

                        Interlocked.Decrement(ref pending);
                        readyEvent.Set();
                    }
                });
            }

            while (pending > 0)
            {
                await readyEvent.WaitAsync();

                if (results != null)
                {
                    return(results);
                }
            }

            return(null);
        }