private void SendToServer(int length, AsyncSession session)
        {
            _totalWrite += length;
            int bytesToSend;

            try
            {
                lock (_encryptionLock)
                {
                    _encryptor.Encrypt(_connetionRecvBuffer, length, _connetionSendBuffer, out bytesToSend);
                }
            }
            catch (CryptoErrorException)
            {
                Logging.Debug("encryption error");
                Close();
                return;
            }
            _tcprelay.UpdateOutboundCounter(_server, bytesToSend);
            _startSendingTime = DateTime.Now;
            session.Remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None,
                                     PipeRemoteSendCallback, new object[] { session, bytesToSend });
            IStrategy strategy = _controller.GetCurrentStrategy();

            strategy?.UpdateLastWrite(_server);
        }
        private void SendToServer(int length)
        {
            _totalWrite += length;
            int bytesToSend;

            lock (_encryptionLock)
            {
                try
                {
                    _encryptor.Encrypt(_connetionRecvBuffer, length, _connetionSendBuffer, out bytesToSend);
                }
                catch (CryptoErrorException)
                {
                    Logging.Debug("encryption error");
                    Close();
                    return;
                }
            }
            _tcprelay.UpdateOutboundCounter(_server, bytesToSend);
            _startSendingTime = DateTime.Now;
            _remote.BeginSend(_connetionSendBuffer, 0, bytesToSend, SocketFlags.None,
                              PipeRemoteSendCallback, bytesToSend);
        }
        // local recv -> server send
        private async Task Upstream()
        {
            SaeaAwaitable localRecvSaea  = null;
            SaeaAwaitable serverSendSaea = null;

            try
            {
                while (IsRunning)
                {
                    localRecvSaea = _argsPool.Rent();
                    var token = await _localSocket.FullReceiveTaskAsync(localRecvSaea, TCPRelay.RecvSize);

                    var err         = token.SocketError;
                    var bytesRecved = token.BytesTotalTransferred;
                    Logging.Debug($"Upstream local recv: {err},{bytesRecved}");
                    if (err == SocketError.Success && bytesRecved <= 0)
                    {
                        _serverSocket.Shutdown(SocketShutdown.Send);
                        _remoteShutdown = true;
                        CheckClose();
                        return;
                    }
                    if (err != SocketError.Success)
                    {
                        Logging.Debug($"Upstream local recv socket err: {err}");
                        Close();
                        return;
                    }
                    Debug.Assert(bytesRecved <= TCPRelay.RecvSize);

                    serverSendSaea = _argsPool.Rent();
                    int encBufLen = -1;
                    lock (_encryptionLock)
                    {
                        _encryptor.Encrypt(localRecvSaea.Saea.Buffer,
                                           bytesRecved,
                                           serverSendSaea.Saea.Buffer,
                                           out encBufLen);
                    }
                    _argsPool.Return(localRecvSaea);
                    localRecvSaea = null;

                    _tcprelay.UpdateOutboundCounter(_server, encBufLen);

                    token = await _serverSocket.FullSendTaskAsync(serverSendSaea, encBufLen);

                    err = token.SocketError;
                    var bytesSent = token.BytesTotalTransferred;
                    Logging.Debug($"Upstream server send: {err},{bytesSent}");
                    if (err != SocketError.Success)
                    {
                        Close();
                        return;
                    }
                    _argsPool.Return(serverSendSaea);
                    serverSendSaea = null;
                    Debug.Assert(bytesSent == encBufLen);
                }
            }
            catch (AggregateException agex)
            {
                foreach (var ex in agex.InnerExceptions)
                {
                    Logging.LogUsefulException(ex);
                }
                Close();
            }
            catch (Exception e)
            {
                Logging.LogUsefulException(e);
                Close();
            }
            finally
            {
                _argsPool.Return(localRecvSaea);
                localRecvSaea = null;
                _argsPool.Return(serverSendSaea);
                serverSendSaea = null;
            }
        }