Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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;
        }