internal async Task <TcpClient> GetClientAsync(bool noTransportErrors = false) { if (_closed) { throw new ApplicationException("Attempt to reuse connection which is not supposed to be used anymore"); } //EtwTrace.Log.ConnectionWaitingForLock(_host, _port); await _connectionLock.WaitAsync(); //EtwTrace.Log.ConnectionGotLock(_host, _port); try { if (_client != null && !_client.Connected) { _log.Debug("Replacing closed connection {0}:{1} with a new one", _host, _port); EtwTrace.Log.ConnectionReplaceClosedClient(_host, _port); _client = null; } if (_client == null) { _client = new TcpClient(); EtwTrace.Log.ConnectionConnecting(_host, _port); await _client.ConnectAsync(_host, _port); EtwTrace.Log.ConnectionConnected(_host, _port); var currentClient = _client; Correlation = new ResponseCorrelation(async e => { await MarkSocketAsFailed(currentClient); if (_onError != null && !noTransportErrors) { _onError(e); } }, _host + ":" + _port + " conn object hash: " + GetHashCode()); // If there was a prior connection and loop task, cancel them before creating a new one. if (_loopTask != null && _loopTaskCancel != null) { _loopTaskCancel.Cancel(); _loopTask = null; } _loopTaskCancel = new CancellationTokenSource(); // Close connection in case of any exception. It is important, because in case of deserialization exception, // we are out of sync and can't continue. _loopTask = Correlation.CorrelateResponseLoop(_client, _loopTaskCancel.Token) .ContinueWith(async t => { _log.Debug("CorrelationLoop completed with status {0}. {1}", t.Status, t.Exception == null?"": string.Format("Closing connection because of error. {0}", t.Exception.Message)); await _connectionLock.WaitAsync(); //.ConfigureAwait(false); try { if (_client != null) { _client.Close(); EtwTrace.Log.ConnectionDisconnected(_host, _port); } } // ReSharper disable once EmptyGeneralCatchClause catch {} finally { _client = null; _connectionLock.Release(); } }); return(_client); } } catch (Exception e) { // some exception getting a connection, clear what we have for next time. _client = null; if (_onError != null && !noTransportErrors) { _onError(e); } throw; } finally { _connectionLock.Release(); //EtwTrace.Log.ConnectionLockRelease(_host, _port); } return(_client); }
internal async Task<TcpClient> GetClientAsync(bool noTransportErrors=false) { if (_closed) throw new ApplicationException("Attempt to reuse connection which is not supposed to be used anymore"); //EtwTrace.Log.ConnectionWaitingForLock(_host, _port); await _connectionLock.WaitAsync(); //EtwTrace.Log.ConnectionGotLock(_host, _port); try { if (_client != null && !_client.Connected) { _log.Debug("Replacing closed connection {0}:{1} with a new one", _host, _port); EtwTrace.Log.ConnectionReplaceClosedClient(_host, _port); _client = null; } if (_client == null) { _client = new TcpClient(); EtwTrace.Log.ConnectionConnecting(_host, _port); await _client.ConnectAsync(_host, _port); EtwTrace.Log.ConnectionConnected(_host, _port); var currentClient = _client; Correlation = new ResponseCorrelation(async e => { await MarkSocketAsFailed(currentClient); if(_onError != null && !noTransportErrors) _onError(e); }, _host+":"+_port+" conn object hash: " + GetHashCode()); // If there was a prior connection and loop task, cancel them before creating a new one. if (_loopTask != null && _loopTaskCancel != null) { _loopTaskCancel.Cancel(); _loopTask = null; } _loopTaskCancel = new CancellationTokenSource(); // Close connection in case of any exception. It is important, because in case of deserialization exception, // we are out of sync and can't continue. _loopTask = Correlation.CorrelateResponseLoop(_client, _loopTaskCancel.Token) .ContinueWith(async t => { _log.Debug("CorrelationLoop completed with status {0}. {1}", t.Status, t.Exception==null?"": string.Format("Closing connection because of error. {0}",t.Exception.Message)); await _connectionLock.WaitAsync();//.ConfigureAwait(false); try { if (_client != null) { _client.Close(); EtwTrace.Log.ConnectionDisconnected(_host, _port); } } // ReSharper disable once EmptyGeneralCatchClause catch {} finally { _client = null; _connectionLock.Release(); } }); return _client; } } catch(Exception e) { // some exception getting a connection, clear what we have for next time. _client = null; if (_onError != null && !noTransportErrors) _onError(e); throw; } finally { _connectionLock.Release(); //EtwTrace.Log.ConnectionLockRelease(_host, _port); } return _client; }