Common data for a FtpConnection
상속: IDisposable
예제 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpConnection"/> class.
        /// </summary>
        /// <param name="socket">The socket to use to communicate with the client.</param>
        /// <param name="logger">The logger for the FTP connection.</param>
        /// <param name="options">The options for the FTP connection.</param>
        /// <param name="serviceProvider">The service provider used to query services.</param>
        public FtpConnection(
            [NotNull] TcpClient socket,
            [NotNull] IOptions <FtpConnectionOptions> options,
            [NotNull] IServiceProvider serviceProvider,
            [CanBeNull] ILogger <IFtpConnection> logger = null)
        {
            var endpoint = (IPEndPoint)socket.Client.RemoteEndPoint;

            RemoteAddress = new Address(endpoint.Address.ToString(), endpoint.Port);

            var properties = new Dictionary <string, object>
            {
                ["RemoteAddress"] = RemoteAddress.ToString(true),
                ["RemoteIp"]      = RemoteAddress.IPAddress?.ToString(),
                ["RemotePort"]    = RemoteAddress.Port,
            };

            _loggerScope = logger?.BeginScope(properties);

            _socket      = socket;
            Log          = logger;
            SocketStream = OriginalStream = socket.GetStream();
            Encoding     = options.Value.DefaultEncoding ?? Encoding.ASCII;
            Data         = new FtpConnectionData(new BackgroundCommandHandler(this));

            // Lazy is required, because we need access to the FTP connection in the command handler constructor
            _commandHandlersDict = new Lazy <IReadOnlyDictionary <string, IFtpCommandHandler> >(
                () =>
            {
                var commandHandlers = serviceProvider.GetRequiredService <IEnumerable <IFtpCommandHandler> >().ToList();
                var dict            = commandHandlers
                                      .SelectMany(x => x.Names, (item, name) => new { Name = name, Item = item })
                                      .ToLookup(x => x.Name, x => x.Item, StringComparer.OrdinalIgnoreCase)
                                      .ToDictionary(x => x.Key, x => x.Last());

                var extensions = serviceProvider.GetRequiredService <IEnumerable <IFtpCommandHandlerExtension> >().ToList();
                foreach (var handler in commandHandlers)
                {
                    extensions.AddRange(handler.GetExtensions());
                }

                // Register extensions with commands
                foreach (var extension in extensions)
                {
                    if (dict.TryGetValue(extension.ExtensionFor, out var handler))
                    {
                        if (handler is IFtpCommandHandlerExtensionHost extensionHost)
                        {
                            foreach (var name in extension.Names)
                            {
                                extensionHost.Extensions.Add(name, extension);
                            }
                        }
                    }
                }

                return(dict);
            });
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpConnection"/> class.
        /// </summary>
        /// <param name="server">The server this connection belongs to</param>
        /// <param name="socket">The socket to use to communicate with the client</param>
        /// <param name="encoding">The encoding to use for the LIST/NLST commands</param>
        public FtpConnection([NotNull] FtpServer server, [NotNull] ITcpSocketClient socket, [NotNull] Encoding encoding)
        {
            Server = server;
            _socket = socket;
            RemoteAddress = new Address(socket.RemoteAddress, socket.RemotePort);
            SocketStream = OriginalStream = socket.GetStream();
            Encoding = encoding;
            Data = new FtpConnectionData(this);
            var commandHandlers = Server.CommandsHandlerFactory.CreateCommandHandlers(this).ToList();
            CommandHandlers = commandHandlers
                .SelectMany(x => x.Names, (item, name) => new { Name = name, Item = item })
                .ToDictionary(x => x.Name, x => x.Item, StringComparer.OrdinalIgnoreCase);

            // Add stand-alone extensions
            AddExtensions(Server.CommandsHandlerFactory.CreateCommandHandlerExtensions(this));

            // Add extensions provided by command handlers
            foreach (var commandHandler in commandHandlers)
                AddExtensions(commandHandler.GetExtensions());
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpConnection"/> class.
        /// </summary>
        /// <param name="socket">The socket to use to communicate with the client.</param>
        /// <param name="connectionAccessor">The accessor to get the connection that is active during the <see cref="FtpCommandHandler.Process"/> method execution.</param>
        /// <param name="commandHandlerExtensions">The registered command handler extensions.</param>
        /// <param name="logger">The logger for the FTP connection.</param>
        /// <param name="options">The options for the FTP connection.</param>
        /// <param name="commandHandlers">The registered command handlers.</param>
        public FtpConnection(
            [NotNull] TcpClient socket,
            [NotNull] IOptions <FtpConnectionOptions> options,
            [NotNull] IFtpConnectionAccessor connectionAccessor,
            [NotNull, ItemNotNull] IEnumerable <IFtpCommandHandler> commandHandlers,
            [NotNull, ItemNotNull] IEnumerable <IFtpCommandHandlerExtension> commandHandlerExtensions,
            [CanBeNull] ILogger <IFtpConnection> logger = null)
        {
            var endpoint = (IPEndPoint)socket.Client.RemoteEndPoint;

            RemoteAddress = new Address(endpoint.Address.ToString(), endpoint.Port);

            var properties = new Dictionary <string, object>
            {
                ["RemoteAddress"] = RemoteAddress.ToString(true),
                ["RemoteIp"]      = RemoteAddress.IPAddress?.ToString(),
                ["RemotePort"]    = RemoteAddress.Port,
            };

            _loggerScope = logger?.BeginScope(properties);

            _socket             = socket;
            _connectionAccessor = connectionAccessor;
            Log             = logger;
            SocketStream    = OriginalStream = socket.GetStream();
            Encoding        = options.Value.DefaultEncoding ?? Encoding.ASCII;
            PromiscuousPasv = options.Value.PromiscuousPasv;
            Data            = new FtpConnectionData(new BackgroundCommandHandler(this));

            var commandHandlersList = commandHandlers.ToList();
            var dict = commandHandlersList
                       .SelectMany(x => x.Names, (item, name) => new { Name = name, Item = item })
                       .ToLookup(x => x.Name, x => x.Item, StringComparer.OrdinalIgnoreCase)
                       .ToDictionary(x => x.Key, x => x.Last());

            _extensions = commandHandlerExtensions.ToList();

            CommandHandlers = dict;
        }
예제 #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpConnection"/> class.
        /// </summary>
        /// <param name="server">The server this connection belongs to</param>
        /// <param name="socket">The socket to use to communicate with the client</param>
        /// <param name="encoding">The encoding to use for the LIST/NLST commands</param>
        public FtpConnection([NotNull] FtpServer server, [NotNull] ITcpSocketClient socket, [NotNull] Encoding encoding)
        {
            Server        = server;
            _socket       = socket;
            RemoteAddress = new Address(socket.RemoteAddress, socket.RemotePort);
            SocketStream  = OriginalStream = socket.GetStream();
            Encoding      = encoding;
            Data          = new FtpConnectionData(this);
            var commandHandlers = Server.CommandsHandlerFactory.CreateCommandHandlers(this).ToList();

            CommandHandlers = commandHandlers
                              .SelectMany(x => x.Names, (item, name) => new { Name = name, Item = item })
                              .ToDictionary(x => x.Name, x => x.Item, StringComparer.OrdinalIgnoreCase);

            // Add stand-alone extensions
            AddExtensions(Server.CommandsHandlerFactory.CreateCommandHandlerExtensions(this));

            // Add extensions provided by command handlers
            foreach (var commandHandler in commandHandlers)
            {
                AddExtensions(commandHandler.GetExtensions());
            }
        }
예제 #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpConnection"/> class.
        /// </summary>
        /// <param name="socketAccessor">The accessor to get the socket used to communicate with the client.</param>
        /// <param name="options">The options for the FTP connection.</param>
        /// <param name="portOptions">The <c>PORT</c> command options.</param>
        /// <param name="connectionAccessor">The accessor to get the connection that is active during the <see cref="FtpCommandHandler.Process"/> method execution.</param>
        /// <param name="catalogLoader">The catalog loader for the FTP server.</param>
        /// <param name="serverCommandExecutor">The executor for server commands.</param>
        /// <param name="serviceProvider">The service provider for the connection.</param>
        /// <param name="secureDataConnectionWrapper">Wraps a data connection into an SSL stream.</param>
        /// <param name="sslStreamWrapperFactory">The SSL stream wrapper factory.</param>
        /// <param name="logger">The logger for the FTP connection.</param>
        public FtpConnection(
            TcpSocketClientAccessor socketAccessor,
            IOptions <FtpConnectionOptions> options,
            IOptions <PortCommandOptions> portOptions,
            IFtpConnectionAccessor connectionAccessor,
            IFtpCatalogLoader catalogLoader,
            IServerCommandExecutor serverCommandExecutor,
            IServiceProvider serviceProvider,
            SecureDataConnectionWrapper secureDataConnectionWrapper,
            ISslStreamWrapperFactory sslStreamWrapperFactory,
            ILogger <FtpConnection>?logger = null)
        {
            var socket = socketAccessor.TcpSocketClient ?? throw new InvalidOperationException("The socket to communicate with the client was not set");

            ConnectionServices = serviceProvider;

            ConnectionId = "FTP-" + Guid.NewGuid().ToString("N");

            _dataPort = portOptions.Value.DataPort;
            var remoteEndPoint = _remoteEndPoint = (IPEndPoint)socket.Client.RemoteEndPoint;

#pragma warning disable 618
            RemoteAddress = new Address(remoteEndPoint.Address.ToString(), remoteEndPoint.Port);
#pragma warning restore 618

            var properties = new Dictionary <string, object?>
            {
                ["RemoteAddress"] = remoteEndPoint.ToString(),
                ["RemoteIp"]      = remoteEndPoint.Address.ToString(),
                ["RemotePort"]    = remoteEndPoint.Port,
                ["ConnectionId"]  = ConnectionId,
            };

            _loggerScope = logger?.BeginScope(properties);

            _socket                      = socket;
            _connectionAccessor          = connectionAccessor;
            _serverCommandExecutor       = serverCommandExecutor;
            _secureDataConnectionWrapper = secureDataConnectionWrapper;
            _serverCommandChannel        = Channel.CreateBounded <IServerCommand>(new BoundedChannelOptions(3));

            _logger = logger;

            var parentFeatures    = new FeatureCollection();
            var connectionFeature = new ConnectionFeature(
                (IPEndPoint)socket.Client.LocalEndPoint,
                remoteEndPoint);
            var secureConnectionFeature = new SecureConnectionFeature();

            var applicationInputPipe  = new Pipe();
            var applicationOutputPipe = new Pipe();
            var socketPipe            = new DuplexPipe(_socketCommandPipe.Reader, _socketResponsePipe.Writer);
            var connectionPipe        = new DuplexPipe(applicationOutputPipe.Reader, applicationInputPipe.Writer);

            var originalStream = socketAccessor.TcpSocketStream ?? socket.GetStream();
            _streamReaderService = new ConnectionClosingNetworkStreamReader(
                originalStream,
                _socketCommandPipe.Writer,
                _cancellationTokenSource);
            _streamWriterService = new StreamPipeWriterService(
                originalStream,
                _socketResponsePipe.Reader,
                _cancellationTokenSource.Token);

            _networkStreamFeature = new NetworkStreamFeature(
                new SecureConnectionAdapter(
                    socketPipe,
                    connectionPipe,
                    sslStreamWrapperFactory,
                    _cancellationTokenSource.Token),
                applicationOutputPipe.Writer);

            parentFeatures.Set <IConnectionFeature>(connectionFeature);
            parentFeatures.Set <ISecureConnectionFeature>(secureConnectionFeature);
            parentFeatures.Set <IServerCommandFeature>(new ServerCommandFeature(_serverCommandChannel));
            parentFeatures.Set <INetworkStreamFeature>(_networkStreamFeature);

            var features = new FeatureCollection(parentFeatures);
#pragma warning disable 618
            Data = new FtpConnectionData(
                options.Value.DefaultEncoding ?? Encoding.ASCII,
                features,
                catalogLoader);
#pragma warning restore 618

            Features = features;

            _commandReader = ReadCommandsFromPipeline(
                applicationInputPipe.Reader,
                _ftpCommandChannel.Writer,
                _cancellationTokenSource.Token);
        }
예제 #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpConnection"/> class.
        /// </summary>
        /// <param name="socket">The socket to use to communicate with the client.</param>
        /// <param name="options">The options for the FTP connection.</param>
        /// <param name="portOptions">The <c>PORT</c> command options.</param>
        /// <param name="connectionAccessor">The accessor to get the connection that is active during the <see cref="FtpCommandHandler.Process"/> method execution.</param>
        /// <param name="catalogLoader">The catalog loader for the FTP server.</param>
        /// <param name="serverCommandExecutor">The executor for server commands.</param>
        /// <param name="serviceProvider">The service provider for the connection.</param>
        /// <param name="secureDataConnectionWrapper">Wraps a data connection into an SSL stream.</param>
        /// <param name="serverMessages">The server messages.</param>
        /// <param name="sslStreamWrapperFactory">The SSL stream wrapper factory.</param>
        /// <param name="logger">The logger for the FTP connection.</param>
        public FtpConnection(
            [NotNull] TcpClient socket,
            [NotNull] IOptions <FtpConnectionOptions> options,
            [NotNull] IOptions <PortCommandOptions> portOptions,
            [NotNull] IFtpConnectionAccessor connectionAccessor,
            [NotNull] IFtpCatalogLoader catalogLoader,
            [NotNull] IServerCommandExecutor serverCommandExecutor,
            [NotNull] IServiceProvider serviceProvider,
            [NotNull] SecureDataConnectionWrapper secureDataConnectionWrapper,
            [NotNull] IFtpServerMessages serverMessages,
            [NotNull] ISslStreamWrapperFactory sslStreamWrapperFactory,
            [CanBeNull] ILogger <FtpConnection> logger = null)
        {
            ConnectionServices = serviceProvider;

            ConnectionId = "FTP-" + Guid.NewGuid().ToString("N");

            _dataPort = portOptions.Value.DataPort;
            var endpoint      = (IPEndPoint)socket.Client.RemoteEndPoint;
            var remoteAddress = _remoteAddress = new Address(endpoint.Address.ToString(), endpoint.Port);

            var properties = new Dictionary <string, object>
            {
                ["RemoteAddress"] = remoteAddress.ToString(true),
                ["RemoteIp"]      = remoteAddress.IPAddress?.ToString(),
                ["RemotePort"]    = remoteAddress.Port,
                ["ConnectionId"]  = ConnectionId,
            };

            _loggerScope = logger?.BeginScope(properties);

            _socket                      = socket;
            _connectionAccessor          = connectionAccessor;
            _serverCommandExecutor       = serverCommandExecutor;
            _secureDataConnectionWrapper = secureDataConnectionWrapper;
            _serverMessages              = serverMessages;
            _serverCommandChannel        = Channel.CreateBounded <IServerCommand>(new BoundedChannelOptions(3));

            _logger = logger;

            var parentFeatures    = new FeatureCollection();
            var connectionFeature = new ConnectionFeature(
                (IPEndPoint)socket.Client.LocalEndPoint,
                remoteAddress);
            var secureConnectionFeature = new SecureConnectionFeature(socket);

            var applicationInputPipe  = new Pipe();
            var applicationOutputPipe = new Pipe();
            var socketPipe            = new DuplexPipe(_socketCommandPipe.Reader, _socketResponsePipe.Writer);
            var connectionPipe        = new DuplexPipe(applicationOutputPipe.Reader, applicationInputPipe.Writer);

            _networkStreamFeature = new NetworkStreamFeature(
                new SecureConnectionAdapter(
                    socketPipe,
                    connectionPipe,
                    sslStreamWrapperFactory,
                    _cancellationTokenSource.Token),
                new ConnectionClosingNetworkStreamReader(
                    secureConnectionFeature.OriginalStream,
                    _socketCommandPipe.Writer,
                    _cancellationTokenSource),
                new StreamPipeWriterService(
                    secureConnectionFeature.OriginalStream,
                    _socketResponsePipe.Reader,
                    _cancellationTokenSource.Token),
                applicationOutputPipe.Writer);

            parentFeatures.Set <IConnectionFeature>(connectionFeature);
            parentFeatures.Set <ISecureConnectionFeature>(secureConnectionFeature);
            parentFeatures.Set <IServerCommandFeature>(new ServerCommandFeature(_serverCommandChannel));
            parentFeatures.Set <INetworkStreamFeature>(_networkStreamFeature);

            var features = new FeatureCollection(parentFeatures);

#pragma warning disable 618
            Data = new FtpConnectionData(
                options.Value.DefaultEncoding ?? Encoding.ASCII,
                features,
                catalogLoader);
#pragma warning restore 618

            Features = features;

            _commandReader = ReadCommandsFromPipeline(
                applicationInputPipe.Reader,
                _ftpCommandChannel.Writer,
                _cancellationTokenSource.Token);
        }