예제 #1
0
        /// <summary>
        /// Disconnect the client and dispose of background workers.
        /// Do not reuse the object after disposal.
        /// </summary>
        /// <param name="disposing">Indicate if resources should be disposed.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _Settings.Logger?.Invoke(_Header + "disposing");

                if (Connected)
                {
                    Disconnect();
                }

                if (_WriteLock != null)
                {
                    _WriteLock.Dispose();
                }

                if (_ReadLock != null)
                {
                    _ReadLock.Dispose();
                }

                _Settings   = null;
                _Events     = null;
                _Callbacks  = null;
                _Statistics = null;
                _Keepalive  = null;

                _SourceIp = null;
                _ServerIp = null;

                _Client     = null;
                _DataStream = null;
                _TcpStream  = null;
                _SslStream  = null;

                _SslCertificate           = null;
                _SslCertificateCollection = null;
                _WriteLock = null;
                _ReadLock  = null;

                _DataReceiver         = null;
                _MonitorSyncResponses = null;
            }
        }
예제 #2
0
        /// <summary>
        /// Connect to the server.
        /// </summary>
        public void Connect()
        {
            if (Connected)
            {
                throw new InvalidOperationException("Already connected to the server.");
            }

            _Client     = new TcpClient();
            _Statistics = new WatsonTcpStatistics();

            IAsyncResult asyncResult    = null;
            WaitHandle   waitHandle     = null;
            bool         connectSuccess = false;

            if (!_Events.IsUsingMessages && !_Events.IsUsingStreams)
            {
                throw new InvalidOperationException("One of either 'MessageReceived' or 'StreamReceived' events must first be set.");
            }

            if (_Keepalive.EnableTcpKeepAlives)
            {
                EnableKeepalives();
            }

            if (_Mode == Mode.Tcp)
            {
                #region TCP

                _Settings.Logger?.Invoke(_Header + "connecting to " + _ServerIp + ":" + _ServerPort);

                _Client.LingerState = new LingerOption(true, 0);
                asyncResult         = _Client.BeginConnect(_ServerIp, _ServerPort, null, null);
                waitHandle          = asyncResult.AsyncWaitHandle;

                try
                {
                    connectSuccess = waitHandle.WaitOne(TimeSpan.FromSeconds(_Settings.ConnectTimeoutSeconds), false);
                    if (!connectSuccess)
                    {
                        _Client.Close();
                        throw new TimeoutException("Timeout connecting to " + _ServerIp + ":" + _ServerPort);
                    }

                    _Client.EndConnect(asyncResult);

                    _SourceIp   = ((IPEndPoint)_Client.Client.LocalEndPoint).Address.ToString();
                    _SourcePort = ((IPEndPoint)_Client.Client.LocalEndPoint).Port;
                    _TcpStream  = _Client.GetStream();
                    _DataStream = _TcpStream;
                    _SslStream  = null;

                    Connected = true;
                }
                catch (Exception e)
                {
                    _Events.HandleExceptionEncountered(this, new ExceptionEventArgs(e));
                    throw;
                }
                finally
                {
                    waitHandle.Close();
                }

                #endregion TCP
            }
            else if (_Mode == Mode.Ssl)
            {
                #region SSL

                _Settings.Logger?.Invoke(_Header + "connecting with SSL to " + _ServerIp + ":" + _ServerPort);

                _Client.LingerState = new LingerOption(true, 0);
                asyncResult         = _Client.BeginConnect(_ServerIp, _ServerPort, null, null);
                waitHandle          = asyncResult.AsyncWaitHandle;

                try
                {
                    connectSuccess = waitHandle.WaitOne(TimeSpan.FromSeconds(_Settings.ConnectTimeoutSeconds), false);
                    if (!connectSuccess)
                    {
                        _Client.Close();
                        throw new TimeoutException("Timeout connecting to " + _ServerIp + ":" + _ServerPort);
                    }

                    _Client.EndConnect(asyncResult);

                    _SourceIp   = ((IPEndPoint)_Client.Client.LocalEndPoint).Address.ToString();
                    _SourcePort = ((IPEndPoint)_Client.Client.LocalEndPoint).Port;

                    if (_Settings.AcceptInvalidCertificates)
                    {
                        _SslStream = new SslStream(_Client.GetStream(), false, new RemoteCertificateValidationCallback(AcceptCertificate));
                    }
                    else
                    {
                        _SslStream = new SslStream(_Client.GetStream(), false);
                    }

                    _SslStream.AuthenticateAsClient(_ServerIp, _SslCertificateCollection, SslProtocols.Tls12, !_Settings.AcceptInvalidCertificates);

                    if (!_SslStream.IsEncrypted)
                    {
                        throw new AuthenticationException("Stream is not encrypted");
                    }

                    if (!_SslStream.IsAuthenticated)
                    {
                        throw new AuthenticationException("Stream is not authenticated");
                    }

                    if (_Settings.MutuallyAuthenticate && !_SslStream.IsMutuallyAuthenticated)
                    {
                        throw new AuthenticationException("Mutual authentication failed");
                    }

                    _DataStream = _SslStream;

                    Connected = true;
                }
                catch (Exception e)
                {
                    _Events.HandleExceptionEncountered(this, new ExceptionEventArgs(e));
                    throw;
                }
                finally
                {
                    waitHandle.Close();
                }

                #endregion SSL
            }
            else
            {
                throw new ArgumentException("Unknown mode: " + _Mode.ToString());
            }

            _TokenSource = new CancellationTokenSource();
            _Token       = _TokenSource.Token;

            _DataReceiver         = Task.Run(() => DataReceiver(), _Token);
            _MonitorSyncResponses = Task.Run(() => MonitorForExpiredSyncResponses(), _Token);
            _Events.HandleServerConnected(this, new ConnectionEventArgs((_ServerIp + ":" + _ServerPort)));
            _Settings.Logger?.Invoke(_Header + "connected");
        }