@@ -122,103 +122,62 @@ private void ConfigureConnectedSocket(Socket socket)
122122
123123 private void Connect ( Socket socket , EndPoint endPoint , CancellationToken cancellationToken )
124124 {
125- var state = 1 ; // 1 == connecting, 2 == connected, 3 == timedout, 4 == cancelled
125+ IAsyncResult connectOperation ;
126126
127- using ( new Timer ( _ => ChangeState ( 3 ) , null , _settings . ConnectTimeout , Timeout . InfiniteTimeSpan ) )
128- using ( cancellationToken . Register ( ( ) => ChangeState ( 4 ) ) )
127+ if ( endPoint is DnsEndPoint dnsEndPoint )
129128 {
130- try
131- {
132- var dnsEndPoint = endPoint as DnsEndPoint ;
133- if ( dnsEndPoint != null )
134- {
135- // mono doesn't support DnsEndPoint in its BeginConnect method.
136- socket . Connect ( dnsEndPoint . Host , dnsEndPoint . Port ) ;
137- }
138- else
139- {
140- socket . Connect ( endPoint ) ;
141- }
142- ChangeState ( 2 ) ; // note: might not actually go to state 2 if already in state 3 or 4
143- }
144- catch when ( state == 1 )
145- {
146- try { socket . Dispose ( ) ; } catch { }
147- throw ;
148- }
149- catch when ( state >= 3 )
150- {
151- // a timeout or operation cancelled exception will be thrown instead
152- }
129+ // mono doesn't support DnsEndPoint in its BeginConnect method.
130+ connectOperation = socket . BeginConnect ( dnsEndPoint . Host , dnsEndPoint . Port , null , null ) ;
131+ }
132+ else
133+ {
134+ connectOperation = socket . BeginConnect ( endPoint , null , null ) ;
135+ }
153136
154- if ( state == 3 )
155- {
156- var message = string . Format ( "Timed out connecting to {0}. Timeout was {1}." , endPoint , _settings . ConnectTimeout ) ;
157- throw new TimeoutException ( message ) ;
158- }
159- if ( state == 4 ) { throw new OperationCanceledException ( ) ; }
137+ WaitHandle . WaitAny ( [ connectOperation . AsyncWaitHandle , cancellationToken . WaitHandle ] , _settings . ConnectTimeout ) ;
138+
139+ if ( ! connectOperation . IsCompleted )
140+ {
141+ try { socket . Dispose ( ) ; } catch { }
142+
143+ cancellationToken . ThrowIfCancellationRequested ( ) ;
144+ throw new TimeoutException ( $ "Timed out connecting to { endPoint } . Timeout was { _settings . ConnectTimeout } .") ;
160145 }
161146
162- void ChangeState ( int to )
147+ try
163148 {
164- var from = Interlocked . CompareExchange ( ref state , to , 1 ) ;
165- if ( from == 1 && to >= 3 )
166- {
167- try { socket . Dispose ( ) ; } catch { } // disposing the socket aborts the connection attempt
168- }
149+ socket . EndConnect ( connectOperation ) ;
150+ }
151+ catch
152+ {
153+ try { socket . Dispose ( ) ; } catch { }
154+ throw ;
169155 }
170156 }
171157
172158 private async Task ConnectAsync ( Socket socket , EndPoint endPoint , CancellationToken cancellationToken )
173159 {
174- var state = 1 ; // 1 == connecting, 2 == connected, 3 == timedout, 4 == cancelled
160+ var timeoutTask = Task . Delay ( _settings . ConnectTimeout , cancellationToken ) ;
161+ var connectTask = socket . ConnectAsync ( endPoint ) ;
162+
163+ await Task . WhenAny ( connectTask , timeoutTask ) . ConfigureAwait ( false ) ;
175164
176- using ( new Timer ( _ => ChangeState ( 3 ) , null , _settings . ConnectTimeout , Timeout . InfiniteTimeSpan ) )
177- using ( cancellationToken . Register ( ( ) => ChangeState ( 4 ) ) )
165+ if ( ! connectTask . IsCompleted )
178166 {
179- try
180- {
181- var dnsEndPoint = endPoint as DnsEndPoint ;
182- #if ! NET472
183- await socket . ConnectAsync ( endPoint ) . ConfigureAwait ( false ) ;
184- #else
185- if ( dnsEndPoint != null )
186- {
187- // mono doesn't support DnsEndPoint in its BeginConnect method.
188- await Task . Factory . FromAsync ( socket . BeginConnect ( dnsEndPoint . Host , dnsEndPoint . Port , null , null ) , socket . EndConnect ) . ConfigureAwait ( false ) ;
189- }
190- else
191- {
192- await Task . Factory . FromAsync ( socket . BeginConnect ( endPoint , null , null ) , socket . EndConnect ) . ConfigureAwait ( false ) ;
193- }
194- #endif
195- ChangeState ( 2 ) ; // note: might not actually go to state 2 if already in state 3 or 4
196- }
197- catch when ( state == 1 )
198- {
199- try { socket . Dispose ( ) ; } catch { }
200- throw ;
201- }
202- catch when ( state >= 3 )
203- {
204- // a timeout or operation cancelled exception will be thrown instead
205- }
167+ try { socket . Dispose ( ) ; } catch { }
206168
207- if ( state == 3 )
208- {
209- var message = string . Format ( "Timed out connecting to {0}. Timeout was {1}." , endPoint , _settings . ConnectTimeout ) ;
210- throw new TimeoutException ( message ) ;
211- }
212- if ( state == 4 ) { throw new OperationCanceledException ( ) ; }
169+ cancellationToken . ThrowIfCancellationRequested ( ) ;
170+ throw new TimeoutException ( $ "Timed out connecting to { endPoint } . Timeout was { _settings . ConnectTimeout } .") ;
213171 }
214172
215- void ChangeState ( int to )
173+ try
216174 {
217- var from = Interlocked . CompareExchange ( ref state , to , 1 ) ;
218- if ( from == 1 && to >= 3 )
219- {
220- try { socket . Dispose ( ) ; } catch { } // disposing the socket aborts the connection attempt
221- }
175+ await connectTask . ConfigureAwait ( false ) ;
176+ }
177+ catch
178+ {
179+ try { socket . Dispose ( ) ; } catch { }
180+ throw ;
222181 }
223182 }
224183
0 commit comments