// 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); } }