Пример #1
0
        /// <summary>
        /// 列文件名操作
        /// </summary>
        /// <param name="dataStream"></param>
        /// <param name="pathname"></param>
        /// <returns></returns>
        private Response NameListOperation(Stream dataStream, string pathname)
        {
            FtpLogEntry logEntry = new FtpLogEntry
            {
                Date       = DateTime.Now,
                CIP        = ClientIP,
                CSMethod   = "NLST",
                CSUsername = _username,
                SCStatus   = "226"
            };

            StreamWriter dataWriter = new StreamWriter(dataStream, _currentEncoding);

            var nameList = _virtualFileSystem.ListFileNames(pathname);

            foreach (var name in nameList)
            {
                dataWriter.WriteLine(name);
                dataWriter.Flush();
            }

            _log.Info(logEntry);
            OnLog(logEntry);
            return(GetResponse(FtpResponses.TRANSFER_SUCCESSFUL));
        }
Пример #2
0
        /// <summary>
        /// 文件追加操作
        /// </summary>
        /// <param name="dataStream"></param>
        /// <param name="pathname"></param>
        /// <returns></returns>
        private Response AppendOperation(Stream dataStream, string pathname)
        {
            long bytes = 0;

            FtpLogEntry logEntry = new FtpLogEntry
            {
                Date       = DateTime.Now,
                CIP        = ClientIP,
                CSMethod   = "APPE",
                CSUsername = _username,
                SCStatus   = "226",
                //CSBytes = bytes.ToString(CultureInfo.InvariantCulture)
            };

            using (FileStream fs = new FileStream(pathname, FileMode.Append, FileAccess.Write, FileShare.Read, BUFFER_SIZE, FileOptions.SequentialScan))
            {
                bytes = CopyStream(dataStream, fs, _performanceCounter.IncrementBytesReceived);
            }


            logEntry.CSBytes = bytes.ToString(CultureInfo.InvariantCulture);

            _log.Info(logEntry);
            OnLog(logEntry);

            _performanceCounter.IncrementFilesReceived();

            _virtualFileSystem.RefreshCurrentDirectory();

            return(GetResponse(FtpResponses.TRANSFER_SUCCESSFUL));
        }
Пример #3
0
        /// <summary>
        /// 列目录操作
        /// </summary>
        /// <param name="dataStream"></param>
        /// <param name="pathname"></param>
        /// <returns></returns>
        private Response ListOperation(Stream dataStream, string pathname)
        {
            DateTime now = DateTime.Now;

            FtpLogEntry logEntry = new FtpLogEntry
            {
                Date       = now,
                CIP        = ClientIP,
                CSMethod   = "LIST",
                CSUsername = _username,
                SCStatus   = "226"
            };

            StreamWriter dataWriter = new StreamWriter(dataStream, _currentEncoding);

            var dirList = _virtualFileSystem.ListFiles(pathname);

            dataWriter.WriteLine(dirList.Count);    //MARK:第一行表示数目
            foreach (var dir in dirList)
            {
                dataWriter.WriteLine(dir);
                dataWriter.Flush();
            }

            _log.Info(logEntry);
            OnLog(logEntry);
            return(GetResponse(FtpResponses.TRANSFER_SUCCESSFUL));
        }
Пример #4
0
        /// <summary>
        /// 下载操作
        /// </summary>
        /// <param name="dataStream"></param>
        /// <param name="pathname"></param>
        /// <returns></returns>
        private Response RetrieveOperation(Stream dataStream, string pathname)
        {
            long        bytes    = 0;
            FtpLogEntry logEntry = new FtpLogEntry
            {
                Date       = DateTime.Now,
                CIP        = ClientIP,
                CSMethod   = "RETR",
                CSUsername = _username,
                SCStatus   = "226",
            };

            using (FileStream fs = new FileStream(pathname, FileMode.Open, FileAccess.Read))
            {
                fs.Seek(_transPosition, SeekOrigin.Begin);
                //由于是异步调用的 因此不会阻塞
                bytes = CopyStream(fs, dataStream, _performanceCounter.IncrementBytesSent);
            }

            logEntry.SCBytes = bytes.ToString(CultureInfo.InvariantCulture);

            _log.Info(logEntry);
            OnLog(logEntry);

            _performanceCounter.IncrementFilesSent();

            _virtualFileSystem.RefreshCurrentDirectory();

            return(GetResponse(FtpResponses.TRANSFER_SUCCESSFUL));
        }
Пример #5
0
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (!_disposed)
                {
                    _disposed = true;

                    if (_currentUser != null)
                    {
                        if (_currentUser.IsAnonymous)
                        {
                            _performanceCounter.DecrementAnonymousUsers();
                        }
                        else
                        {
                            _performanceCounter.DecrementNonAnonymousUsers();
                        }
                    }

                    if (_connected)
                    {
                        _performanceCounter.DecrementCurrentConnections();
                    }

                    if (disposing)
                    {
                        if (_dataClient != null)
                        {
                            _dataClient.Close();
                            _dataClient = null;
                        }

                        if (_sslStream != null)
                        {
                            _sslStream.Dispose();
                            _sslStream = null;
                        }
                    }
                }
            }
            finally
            {
                FtpLogEntry logEntry = new FtpLogEntry()
                {
                    Date = DateTime.Now,
                    Info = LogInfo.ConnectionTerminated.ToString()
                };
                OnLog(logEntry);

                var serverConnInfos = ((FtpServer)CurrentServer).ConnectionInfos;
                if (serverConnInfos.Contains(ConnectionInfo))
                {
                    serverConnInfos.Remove(ConnectionInfo);
                }
                serverConnInfos.RemoveAll(t => t.ID == this.ID);

                base.Dispose(disposing);
            }
        }
Пример #6
0
        protected override void OnStop()
        {
            if (_timer != null)
            {
                _timer.Stop();
            }

            FtpLogEntry logEntry = new FtpLogEntry()
            {
                Date = DateTime.Now,
                Info = LogInfo.ServerStop.ToString()
            };

            OnLog(logEntry);
            Active = false;
        }
Пример #7
0
        protected override void OnConnected()
        {
            _performanceCounter = ((FtpServer)CurrentServer).ServerPerformanceCounter;

            _performanceCounter.IncrementCurrentConnections();

            ConnectionInfo.ID = ID;//FIXED:注意与下一句的先后顺序

            RegisterToServer();

            OnLog = ((FtpServer)CurrentServer).SendLog;

            FtpLogEntry logEntry = new FtpLogEntry()
            {
                Date = DateTime.Now,
                Info = LogInfo.ConnectionEstablished.ToString()
            };

            OnLog(logEntry);

            ConnectionInfo.IP = ClientIP;

            _connected = true;

            if (((FtpServer)CurrentServer).Config.Welcome != null)
            {
                Write(new Response {
                    Code = "220-", Text = "Connected"
                });
                foreach (var welcome in ((FtpServer)CurrentServer).Config.Welcome)
                {
                    Write(new Response {
                        Code = "", Text = welcome
                    });
                }
            }

            Write(GetResponse(FtpResponses.SERVICE_READY));
            //FIXED:SSL指令可以在登陆前执行
            _validCommands.AddRange(new string[] { "AUTH", "USER", "PASS", "ACCT", "QUIT", "HELP", "NOOP", "PBSZ", "PROT" });

            _dataClient = new TcpClient();

            Read();
        }
Пример #8
0
        protected override void OnStart()
        {
            _startTime = DateTime.Now;

            _timer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);

            _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);

            _timer.Start();
            foreach (var tcpListener in base.Listeners)
            {
                FtpLogEntry logEntry = new FtpLogEntry()
                {
                    Date  = DateTime.Now,
                    Info  = LogInfo.ServerStart.ToString(),
                    SPort = tcpListener.LocalEndpoint.ToString()
                };

                OnLog(logEntry);
            }
            Active = true;
        }
Пример #9
0
        /// <summary>
        /// 上传操作
        /// </summary>
        /// <param name="dataStream"></param>
        /// <param name="pathname"></param>
        /// <returns></returns>
        private Response StoreOperation(Stream dataStream, string pathname)
        {
            long bytes = 0;

            FtpLogEntry logEntry = new FtpLogEntry
            {
                Date       = DateTime.Now,
                CIP        = ClientIP,
                CSMethod   = "STOR",
                CSUsername = _username,
                SCStatus   = "226",
            };

            if (VPath.ContainsInvalidPathChars(pathname))
            {
                pathname = VPath.RemoveInvalidPathChars(pathname);
            }
            using (FileStream fs = new FileStream(pathname, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, BUFFER_SIZE, FileOptions.SequentialScan))
            {
                //if (_lastCommand.Code == "REST")
                //{
                //    fs.Seek(_transPosition, SeekOrigin.Begin);
                //}
                fs.Seek(_transPosition, SeekOrigin.Begin);
                bytes = CopyStream(dataStream, fs, _performanceCounter.IncrementBytesReceived);
            }

            logEntry.CSBytes = bytes.ToString(CultureInfo.InvariantCulture);

            _log.Info(logEntry);
            OnLog(logEntry);

            _performanceCounter.IncrementFilesReceived();

            _virtualFileSystem.RefreshCurrentDirectory();

            return(GetResponse(FtpResponses.TRANSFER_SUCCESSFUL));
        }
Пример #10
0
        protected override Response HandleCommand(Command cmd)
        {
            //Console.WriteLine(cmd.Raw);

            Response response = null;

            FtpLogEntry logEntry = new FtpLogEntry
            {
                Date   = DateTime.Now,
                CIP    = ClientIP,
                CSArgs = cmd.RawArguments
            };

            ConnectionInfo.LastCommand = cmd.Code;


            //请求的命令需要权限
            if (!_validCommands.Contains(cmd.Code))
            {
                response = CheckUser(); //如果被拒绝将直接发送权限认证的响应
            }

            // RNFR重命名后面必须立即接RNTO命令
            if (cmd.Code != "RNTO")
            {
                _renameFrom = null;
            }
            // REST重新开始后面必须立即接传输命令
            if (cmd.Code != "RETR" && cmd.Code != "STOR")
            {
                _transPosition = 0;
            }

            if (response == null)
            {
                switch (cmd.Code)
                {
                case "USER":        //用户名
                    response = User(cmd.Arguments.FirstOrDefault());
                    break;

                case "PASS":        //密码
                    response        = Password(cmd.Arguments.FirstOrDefault());
                    logEntry.CSArgs = "******";
                    break;

                case "CWD":         //切换目录
                    response = ChangeWorkingDirectory(cmd.RawArguments);
                    break;

                case "CDUP":        //切换到上级目录
                    response = ChangeWorkingDirectory("..");
                    break;

                case "QUIT":        //退出
                    if (((FtpServer)CurrentServer).Config.LogOutWelcome != null)
                    {
                        Write(new Response {
                            Code = "221-", Text = "Logging Out"
                        });
                        foreach (var welcome in ((FtpServer)CurrentServer).Config.LogOutWelcome)
                        {
                            Write(new Response {
                                Code = "", Text = welcome
                            });
                        }
                    }
                    response = GetResponse(FtpResponses.QUIT);
                    break;

                case "REIN":        //初始化
                    _currentUser          = null;
                    _username             = null;
                    _dataClient           = null;
                    _currentCulture       = CultureInfo.CurrentCulture;
                    _currentEncoding      = Encoding.ASCII;
                    ControlStreamEncoding = Encoding.ASCII;

                    response = GetResponse(FtpResponses.SERVICE_READY);
                    break;

                case "PORT":        //主动模式设置端口
                    response       = Port(cmd.RawArguments);
                    logEntry.CPort = _dataEndpoint.Port.ToString(CultureInfo.InvariantCulture);
                    break;

                case "PASV":        //进入被动模式
                    response       = Passive();
                    logEntry.SPort = ((IPEndPoint)_passiveListener.LocalEndpoint).Port.ToString(CultureInfo.InvariantCulture);
                    break;

                case "TYPE":        //设置传输类型
                    response = Type(cmd.Arguments.FirstOrDefault(), cmd.Arguments.Skip(1).FirstOrDefault());
                    break;

                case "STRU":        //设置结构
                    response = Structure(cmd.Arguments.FirstOrDefault());
                    break;

                case "MODE":        //设置模式
                    response = Mode(cmd.Arguments.FirstOrDefault());
                    break;

                case "RNFR":        //重命名
                    _renameFrom = cmd.RawArguments;
                    response    = GetResponse(FtpResponses.RENAME_FROM);
                    break;

                case "RNTO":        //重命名为
                    response = Rename(_renameFrom, cmd.RawArguments);
                    break;

                case "DELE":        //删除文件
                    response = Delete(cmd.RawArguments);
                    break;

                case "RMD":         //删除文件夹
                    response = RemoveDir(cmd.RawArguments);
                    break;

                case "MKD":         //建立文件夹
                    response = CreateDir(cmd.RawArguments);
                    break;

                case "PWD":         //显示目录
                    response = PrintWorkingDirectory();
                    break;

                case "RETR":        //下载文件  //FIXED:文件名含空格
                    response      = Retrieve(cmd.RawArguments);
                    logEntry.Date = DateTime.Now;
                    break;

                case "STOR":        //上传文件
                    response      = Store(cmd.RawArguments);
                    logEntry.Date = DateTime.Now;
                    break;

                case "STOU":        //上传文件(不覆盖现有文件)
                    response      = StoreUnique(cmd.RawArguments);
                    logEntry.Date = DateTime.Now;
                    break;

                case "APPE":        //追加
                    response      = Append(cmd.RawArguments);
                    logEntry.Date = DateTime.Now;
                    break;

                case "LIST":        //列出目录文件
                    response      = List(cmd.RawArguments);
                    logEntry.Date = DateTime.Now;
                    break;

                case "SYST":        //系统类型
                    response = GetResponse(FtpResponses.SYSTEM);
                    break;

                case "NOOP":        //空指令 只为获取服务器响应
                    response = GetResponse(FtpResponses.OK);
                    break;

                case "ACCT":        //要求账户(未实现)
                    response = Account(cmd.RawArguments);
                    break;

                case "ALLO":        //分配 (对于不需要分配存储空间的机器,它的作用等于NOOP)
                    response = GetResponse(FtpResponses.OK);
                    break;

                case "NLST":        //列文件名
                    response = NameList(cmd.RawArguments);
                    break;

                case "SITE":        //服务器系统相关命令 //TODO:可能在此处加入搜索
                    response = GetResponse(FtpResponses.NOT_IMPLEMENTED);
                    break;

                case "STAT":
                    response = GetResponse(FtpResponses.NOT_IMPLEMENTED);
                    break;

                case "HELP":        //帮助
                    response = GetResponse(FtpResponses.NOT_IMPLEMENTED);
                    break;

                case "SMNT":
                    response = GetResponse(FtpResponses.NOT_IMPLEMENTED);
                    break;

                case "REST":        //重新开始 //ADDED:尝试断点续传
                    response = Restart(cmd.RawArguments);
                    break;

                case "ABOR":        //中断传输,关闭数据连接
                    response = GetResponse(FtpResponses.NOT_IMPLEMENTED);
                    break;

                // Extensions defined by rfc 2228
                case "AUTH":        //权限验证 AUTH <验证方法>
                    response = Auth(cmd.RawArguments);
                    break;

                case "PBSZ":        //设置保护缓冲区大小,在SSL/TLS中永远是0
                    response = ProtectBufferSize(cmd.RawArguments);
                    break;

                case "PROT":        //保护级别
                    response = ProtectionLevel(cmd.Arguments.FirstOrDefault());
                    break;

                // Extensions defined by rfc 2389
                case "FEAT":        //显示扩展指令
                    response = GetResponse(FtpResponses.FEATURES);
                    break;

                case "OPTS":        //参数设置
                    response = Options(cmd.Arguments);
                    break;

                // Extensions defined by rfc 3659
                case "MDTM":                                           //回显文件修改时间,通常用于对时
                    response = FileModificationTime(cmd.RawArguments); //FIXED:只接受一个参数的 务必使用RawArg
                    break;

                case "SIZE":        //回显文件大小
                    response = FileSize(cmd.RawArguments);
                    break;

                case "MLSD":        //标准格式列目录
                    response = MachineListDirectory(cmd.RawArguments);
                    break;

                case "MLST":        //标准格式列文件信息
                    response = MachineListTime(cmd.RawArguments);
                    break;

                // Extensions defined by rfc 2428
                case "EPRT":        //扩展主动模式(IPv6)
                    response       = EPort(cmd.RawArguments);
                    logEntry.CPort = _dataEndpoint.Port.ToString(CultureInfo.InvariantCulture);
                    break;

                case "EPSV":        //扩展被动动模式(IPv6)
                    response       = EPassive();
                    logEntry.SPort = ((IPEndPoint)_passiveListener.LocalEndpoint).Port.ToString(CultureInfo.InvariantCulture);
                    break;

                // Extensions defined by rfc 2640
                case "LANG":        //切换服务端显示语言
                    response = Language(cmd.Arguments.FirstOrDefault());
                    break;

                default:
                    response = GetResponse(FtpResponses.NOT_IMPLEMENTED);
                    break;
                }
            }

            logEntry.CSMethod   = cmd.Code;
            logEntry.CSUsername = _username;
            logEntry.SCStatus   = response.Code;

            _log.Info(logEntry);
            OnLog(logEntry);

            _lastCommand = cmd;

            return(response);
        }