// Called by Socket to kick off the ConnectAsync process.  We'll complete the user's SAEA
        // when it's done.  Returns true if the operation will be asynchronous, false if it has failed synchronously
        public bool StartConnectAsync(SocketAsyncEventArgs args, DnsEndPoint endPoint)
        {
            lock (_lockObject)
            {
                GlobalLog.Assert(endPoint.AddressFamily == AddressFamily.Unspecified ||
                                 endPoint.AddressFamily == AddressFamily.InterNetwork ||
                                 endPoint.AddressFamily == AddressFamily.InterNetworkV6,
                                 "MultipleConnectAsync.StartConnectAsync(): Unexpected endpoint address family - " + endPoint.AddressFamily.ToString());

                _userArgs = args;
                _endPoint = endPoint;

                // If Cancel() was called before we got the lock, it only set the state to Canceled: we need to
                // fail synchronously from here.  Once State.DnsQuery is set, the Cancel() call will handle calling AsyncFail.
                if (_state == State.Canceled)
                {
                    SyncFail(new SocketException((int)SocketError.OperationAborted));
                    return(false);
                }

                GlobalLog.Assert(_state == State.NotStarted, "MultipleConnectAsync.StartConnectAsync(): Unexpected object state");

                _state = State.DnsQuery;

                IAsyncResult result = DnsAPMExtensions.BeginGetHostAddresses(endPoint.Host, new AsyncCallback(DnsCallback), null);
                if (result.CompletedSynchronously)
                {
                    return(DoDnsCallback(result, true));
                }
                else
                {
                    return(true);
                }
            }
        }
        // Called when the DNS query completes (either synchronously or asynchronously).  Checks for failure and
        // starts the first connection attempt if it succeeded.  Returns true if the operation will be asynchronous,
        // false if it has failed synchronously.
        private bool DoDnsCallback(IAsyncResult result, bool sync)
        {
            Exception exception = null;

            lock (_lockObject)
            {
                // If the connection attempt was canceled during the dns query, the user's callback has already been
                // called asynchronously and we simply need to return.
                if (_state == State.Canceled)
                {
                    return(true);
                }

                GlobalLog.Assert(_state == State.DnsQuery, "MultipleConnectAsync.DoDnsCallback(): Unexpected object state");

                try
                {
                    _addressList = DnsAPMExtensions.EndGetHostAddresses(result);
                    GlobalLog.Assert(_addressList != null, "MultipleConnectAsync.DoDnsCallback(): EndGetHostAddresses returned null!");
                }
                catch (Exception e)
                {
                    _state    = State.Completed;
                    exception = e;
                }

                // If the dns query succeeded, try to connect to the first address
                if (exception == null)
                {
                    _state = State.ConnectAttempt;

                    _internalArgs            = new SocketAsyncEventArgs();
                    _internalArgs.Completed += InternalConnectCallback;

                    if (!RequiresUserConnectAttempt)
                    {
                        _internalArgs.SetBuffer(_userArgs.Buffer, _userArgs.Offset, _userArgs.Count);
                    }

                    exception = AttemptConnection();

                    if (exception != null)
                    {
                        // There was a synchronous error while connecting
                        _state = State.Completed;
                    }
                }
            }

            // Call this outside of the lock because it might call the user's callback.
            if (exception != null)
            {
                return(Fail(sync, exception));
            }
            else
            {
                return(true);
            }
        }