/// <summary> /// Close both active and passive data connection if opened /// </summary> private void CloseDataChannel() { Logging.Print("hit close data channel"); if (m_DataStream != null) { m_DataStream.Close(); m_DataStream = null; } if (m_ListenSocket != null) { m_ListenSocket.Close(); m_ListenSocket = null; } if (m_DataSocket != null) { m_DataSocket.Close(); m_DataSocket = null; } if (m_PassThreadW == true) { m_PassThreadW = false; } else if (m_ActThreadW == true) { m_ActThreadW = false; } m_DataReady = false; }
/// <summary> /// Data thread running in passive mode /// </summary> private void PassiveThread() { m_HostPort = 0; Logging.Print("Passive Mode Activate"); if (m_IsDisposed) { return; } // clean up data socket if (m_DataSocket != null) { m_DataSocket.Close(); m_DataSocket = null; } IPAddress hostIp = IPAddress.Any; IPEndPoint ep = new IPEndPoint(hostIp, m_HostPort); try { m_ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); m_ListenSocket.Bind(ep); m_ListenSocket.Listen(0); m_HostPort = (m_ListenSocket.LocalEndPoint as IPEndPoint).Port; m_PassThreadW = true; } catch (SocketException se) { Logging.Print(se.Message); } finally { m_DataReadyEvent.Set(); } try { m_DataSocket = m_ListenSocket.Accept(); m_DataStream = new NetworkStream(m_DataSocket); lock (m_SyncRoot) { m_DataReady = true; } m_DataChannelEstablished.Set(); } catch (SocketException se) { Logging.Print("Data Socket Exception: " + se.ErrorCode.ToString()); } finally { // do not need listen socket any longer Logging.Print("Passive Thread exit"); m_ListenSocket.Close(); m_ListenSocket = null; } }
// Methods internal FtpListenerSession(Socket control, IContextManager context) { m_CommandSocket = control; m_SendContext = context; Logging.Print("New connection established from " + control.RemoteEndPoint); m_HostIp = (control.LocalEndPoint as IPEndPoint).Address; m_DataReadyEvent = new AutoResetEvent(false); m_DataChannelEstablished = new ManualResetEvent(false); m_CommandThread = new Thread(WorkerThread); m_CommandThread.Start(); }
/// <summary> /// Work thread to handle new ftp sessions /// </summary> private void WorkerThread() { m_ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { m_ListenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); } catch {} IPAddress hostIp = new IPAddress(new byte[] { 0, 0, 0, 0 }); //IPAddress.Any; IPEndPoint ep = new IPEndPoint(hostIp, m_HostPort); m_ListenSocket.Bind(ep); m_ListenSocket.Listen(0); Socket aSocket = null; try { aSocket = m_ListenSocket.Accept(); try { aSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); } catch {} while (m_IsStarted) { // remove dead connections m_Sessions.CheckAlive(); // too many open connections if (m_Sessions.Count >= m_Sessions.Capacity) { aSocket.Close(); Logging.Print("Too many open connections"); } else { m_Sessions.AddSession(new FtpListenerSession(aSocket, this)); Logging.Print("number of active sessions: " + m_Sessions.Count); } aSocket = m_ListenSocket.Accept(); } } catch (SocketException) { } }
// Methods /// <summary> /// Default constructor /// </summary> private FtpListenerManager() { Logging.Print(" *** MiniFTPServer ***"); foreach (IPAddress item in System.Net.Dns.GetHostEntry("").AddressList) { m_HostIP = item; if (null != m_HostIP) { break; } } m_Sessions = new SessionPool(); m_Listeners = new ArrayList(); Logging.Print("Running in domain " + AppDomain.CurrentDomain.FriendlyName); }
/// <summary> /// read from the command socket /// </summary> /// <returns></returns> private string ReadCommand() { int idxEndLine = -1; string receiveBuffer = ""; int timeCountDown = SessionTimeOut; int len = 0; byte[] buffer; while (len == 0 || idxEndLine < 0) { if (len == 0) { Thread.Sleep(50); timeCountDown -= 50; } else { timeCountDown = SessionTimeOut; } if (timeCountDown <= 0) { m_IsAlive = false; break; } len = m_CommandSocket.Available; buffer = new byte[len]; len = m_CommandSocket.Receive(buffer, len, SocketFlags.None); receiveBuffer += new string(Encoding.UTF8.GetChars(buffer)); idxEndLine = receiveBuffer.IndexOf('\n'); } if (timeCountDown <= 0) { return(null); } receiveBuffer = receiveBuffer.Substring(0, idxEndLine - 1); Logging.Print("Get: " + receiveBuffer + " :" + SessionId.ToString() + " in domain " + AppDomain.CurrentDomain.FriendlyName); return(receiveBuffer); }
/// <summary> /// Start the ftp server /// </summary> internal void Start() { if (!m_IsStarted) { // Start the socket Logging.Print(" Host IP: " + m_HostIP.ToString()); m_Daemon = new Thread(WorkerThread); m_IsStarted = true; m_Daemon.Start(); if (m_DefaultListener != null) { if (!m_DefaultListener.IsListening) { m_DefaultListener.Start(); } } else { m_DefaultListener = new FtpDefaultListener(); m_DefaultListener.Start(); } } }
/// <summary> /// Data thread running in active mode /// </summary> private void ActiveThread() { Logging.Print("Active Mode Activate"); if (m_IsDisposed) { return; } // clean up data socket if (m_DataSocket != null) { m_DataSocket.Close(); m_DataSocket = null; } try { m_DataSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); m_DataSocket.Connect(new IPEndPoint(m_ClientIp, m_ClientPort)); m_DataStream = new NetworkStream(m_DataSocket); lock (m_SyncRoot) { m_DataReady = true; } m_DataChannelEstablished.Set(); } catch (SocketException se) { Logging.Print("Data Socket Exception: " + se.ErrorCode.ToString()); } finally { // do not need listen socket any longer Logging.Print("Active Thread exit"); } }
private void Run() { for (; ;) { FtpListenerContext context = this.GetContext(); if (context == null) { // the listener has been closed return; } try { switch (context.Request.Method) { case WebRequestMethodsEx.Ftp.ChangeDirectory: { String fsPath = MapToFilesystem(context.Request.QueryString); if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar) { fsPath = fsPath.Substring(0, fsPath.Length - 1); } context.Response.StatusCode = Directory.Exists(fsPath) ? FtpStatusCode.FileActionOK : FtpStatusCode.ActionNotTakenFileUnavailable; } break; case WebRequestMethods.Ftp.ListDirectory: case WebRequestMethods.Ftp.ListDirectoryDetails: { String fsPath = MapToFilesystem(context.Request.QueryString); if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar) { fsPath = fsPath.Substring(0, fsPath.Length - 1); } if (WriteDirInfo(fsPath, context.Response.OutputStream)) { context.Response.StatusCode = FtpStatusCode.ClosingData; } else { context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable; } } break; case WebRequestMethods.Ftp.MakeDirectory: { String fsPath = MapToFilesystem(context.Request.QueryString); if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar) { fsPath = fsPath.Substring(0, fsPath.Length - 1); } DirectoryInfo dinfo = Directory.CreateDirectory(fsPath); context.Response.StatusCode = (null != dinfo && dinfo.Exists) ? FtpStatusCode.PathnameCreated : FtpStatusCode.ActionNotTakenFileUnavailable; } break; case WebRequestMethods.Ftp.RemoveDirectory: { DirectoryInfo info = new DirectoryInfo(MapToFilesystem(context.Request.QueryString)); if (info.Exists) { info.Delete(); context.Response.StatusCode = FtpStatusCode.FileActionOK; } else { context.Response.StatusCode = FtpStatusCode.ActionNotTakenFilenameNotAllowed; } } break; case WebRequestMethods.Ftp.DownloadFile: { FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString)); if (info.Exists) { using (FileStream dataFile = new FileStream(MapToFilesystem(context.Request.QueryString), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { context.Response.OutputStream.Write(dataFile); } context.Response.StatusCode = FtpStatusCode.ClosingData; } else { context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable; } } break; case WebRequestMethods.Ftp.UploadFile: if (!UploadsAllowed) { Logging.Print("Uploads forbidden by configuration: " + context.Request.QueryString); context.Response.StatusCode = FtpStatusCode.FileActionAborted; } else { FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString)); FtpResponseStream istream = context.Request.InputStream; using (FileStream dataFile = new FileStream(MapToFilesystem(context.Request.QueryString), FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { istream.ReadTo(dataFile); dataFile.Close(); } context.Response.StatusCode = FtpStatusCode.ClosingData; } break; case WebRequestMethods.Ftp.GetFileSize: { FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString)); if (info.Exists) { context.Response.OutputStream.Write(((int)info.Length).ToString()); context.Response.StatusCode = FtpStatusCode.FileStatus; } else { context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable; } } break; case WebRequestMethods.Ftp.DeleteFile: { FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString)); if (info.Exists) { info.Delete(); context.Response.StatusCode = FtpStatusCode.FileActionOK; } else { context.Response.StatusCode = FtpStatusCode.ActionNotTakenFilenameNotAllowed; } } break; case WebRequestMethodsEx.Ftp.RenameFrom: { FileInfo fInfo = new FileInfo(MapToFilesystem(context.Request.QueryString)); String fsPath = MapToFilesystem(context.Request.QueryString); if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar) { fsPath = fsPath.Substring(0, fsPath.Length - 1); } DirectoryInfo dInfo = new DirectoryInfo(fsPath); if (fInfo.Exists) { context.Response.StatusCode = FtpStatusCode.FileCommandPending; context.Response.OutputStream.Close(); context = this.GetContext(); if (context.Request.Method != WebRequestMethodsEx.Ftp.RenameTo) { context.Response.StatusCode = FtpStatusCode.BadCommandSequence; } else { File.Move(fInfo.FullName, MapToFilesystem(context.Request.QueryString)); context.Response.StatusCode = FtpStatusCode.FileActionOK; } } else if (dInfo.Exists) { context.Response.StatusCode = FtpStatusCode.FileCommandPending; context.Response.OutputStream.Close(); context = this.GetContext(); if (context.Request.Method != WebRequestMethodsEx.Ftp.RenameTo) { context.Response.StatusCode = FtpStatusCode.BadCommandSequence; } else { fsPath = MapToFilesystem(context.Request.QueryString); if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar) { fsPath = fsPath.Substring(0, fsPath.Length - 1); } Directory.Move(dInfo.FullName, fsPath); context.Response.StatusCode = FtpStatusCode.FileActionOK; } } else { context.Response.StatusCode = FtpStatusCode.ActionNotTakenFilenameNotAllowed; } } break; default: context.Response.StatusCode = FtpStatusCode.FileActionAborted; break; } } catch (Exception e) { Logging.Print("could not process command: " + e); context.Response.StatusCode = FtpStatusCode.ActionAbortedLocalProcessingError; } context.Response.OutputStream.Close(); } }
/// <summary> /// Control thread /// TODO: separate the functionalities into functions to reduce maintenance cost /// </summary> private void WorkerThread() { FtpCommand command; FtpState state = FtpState.WaitUser; string tempName = null; // store old name for "rename from" command string response; int timeout = 0; try { while (m_IsAlive) { if (m_IsDisposed) { break; } else if (!m_Welcomed) { response = "220 MyFTP " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() + " Server [" + m_HostIp.ToString() + "] \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); m_Welcomed = true; } else if (m_CommandSocket == null) { Logging.Print("Session socket has been closed."); break; } else if (m_CommandSocket.Poll(1000, SelectMode.SelectRead)) { if (m_CommandSocket.Available == 0) { Logging.Print("REMOTE DISCONNECT " + m_CommandSocket.RemoteEndPoint.ToString()); m_IsAlive = false; break; } // read until find the end of a line command = FtpCommandCreator.Create(ReadCommand()); if (command == null) { break; } else { switch (command.Type) { case FtpCommandType.User: response = "331 " + command.Content + " login ok \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); state = FtpState.WaitPwd; tempName = command.Content; break; case FtpCommandType.Pass: if (state != FtpState.WaitPwd) { response = "332 Need Account for Login.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { UserAuthenticatorArgs args = new UserAuthenticatorArgs(tempName, command.Content); FtpListener.RaiseEvent(this, args); if (args.Result == UserAuthenticationResult.Approved) { User.UserName = tempName; User.PassWord = command.Content; response = "230 access granted for " + User.UserName + ", restrictions apply. \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); state = FtpState.WaitCommand; break; } else { response = "530 Login incorrect. \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); state = FtpState.WaitCommand; break; } } case FtpCommandType.Cwd: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitUser) { response = "332 Need Account for Login.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { if (command.Content == null) { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethodsEx.Ftp.ChangeDirectory, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Quit: m_IsAlive = false; CloseDataChannel(); response = "221 Goodbye.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); m_CommandSocket.Close(); m_CommandSocket = null; break; case FtpCommandType.Pasv: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { CloseDataChannel(); m_DataThread = new Thread(PassiveThread); m_DataThread.Start(); m_DataReadyEvent.WaitOne(); // wait until port has been successfully assigned byte[] addrs = m_HostIp.GetAddressBytes(); int upper = m_HostPort / 256; int lower = m_HostPort % 256; if (addrs.Length == 4) //IPv4 { response = "227 Entering Passive Mode ("; foreach (int i in addrs) { response += i.ToString() + ","; } response += upper.ToString() + "," + lower.ToString() + ")\r\n"; } else // currently do not support IPv6 { throw new NotImplementedException("currently does not support IPv6"); } m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Type: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { response = "200 Command OK.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.List: if (!m_DataModeON) { response = "425 Use PORT or PASV first.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { response = "150 Opening UTF8 mode data connection for *** \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.ListDirectoryDetails, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.NList: if (!m_DataModeON) { response = "425 Use PORT or PASV first.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { response = "150 Opening UTF8 mode data connection for *** \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.ListDirectory, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Port: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand && command.Content != null) { CloseDataChannel(); string[] epad = command.Content.Split(new char[] { ',' }); if (epad.Length != 6) { response = "500 Invalid PORT command.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); } else { try { m_ClientIp = IPAddress.Parse(epad[0] + "." + epad[1] + "." + epad[2] + "." + epad[3]); m_ClientPort = Int32.Parse(epad[4]) * 256 + Int32.Parse(epad[5]); if (m_ClientPort <= 0 || m_ClientPort > 65535) { response = "500 Invalid PORT command.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); } else { m_ActThreadW = true; m_DataThread = new Thread(ActiveThread); m_DataThread.Start(); response = "200 PORT command successful.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); } } catch (Exception) { response = "500 Invalid PORT command.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); } } break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Sys: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { response = "215 System Type: EMIC\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Feature: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { response = "211-Features:\r\n SIZE\r\n211 End\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Pwd: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { response = "257 \"" + m_CurrentDirectory.GetNetPath() + "\" is the current directory. \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Retr: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { if (!m_DataModeON) { response = "425 Use PORT or PASV first.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } response = "150 Opening BINARY mode data connection for " + command.Content + ". \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.DownloadFile, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Opts: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { if (command.Content == "utf8") { response = "213 Always in utf8 mode \r\n"; } else { response = "550 Requested action not taken. Mode not support. \r\n"; } m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Size: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.GetFileSize, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Store: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { if (!m_DataModeON) { response = "425 Use PORT or PASV first.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } response = "150 Opening BINARY mode data connection for " + command.Content + ". \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.UploadFile, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Noop: response = "200 NOOP command successful. \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; case FtpCommandType.Delete: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.DeleteFile, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.MkDir: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.MakeDirectory, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Rmd: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethods.Ftp.RemoveDirectory, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Rnfr: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethodsEx.Ftp.RenameFrom, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } case FtpCommandType.Rnto: if (state == FtpState.WaitPwd) { response = "331 Need Password.\r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } else if (state == FtpState.WaitCommand) { FtpListenerRequest request = new FtpListenerRequest(WebRequestMethodsEx.Ftp.RenameTo, m_CurrentDirectory.Combine(command.Content).GetNetPath(), this); FtpListenerContext context = new FtpListenerContext(this, request); m_SendContext.AddContext(context); break; } else { response = m_BadSequence; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } default: response = "502 Command not implemented. \r\n"; if (state == FtpState.WaitPwd) { state = FtpState.WaitUser; } m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); break; } } // reset time out timeout = 0; } else if (m_CommandSocket.Poll(1000, SelectMode.SelectError)) { Logging.Print("Disconnected unproperly."); break; } else { if (!m_Welcomed) { response = "220 MyFTP " + typeof(FtpListenerSession).Assembly.GetName().Version.ToString() + " Server [" + m_HostIp.ToString() + "] \r\n"; m_CommandSocket.Send(Encoding.UTF8.GetBytes(response)); m_Welcomed = true; } else { if (SessionTimeOut != -1) { if (timeout > SessionTimeOut) { m_IsAlive = false; Logging.Print("Connection time out."); break; } timeout += 50; } Thread.Sleep(50); } } } } catch (SocketException se) { Logging.Print("Control Socket Exception : " + se.ErrorCode.ToString()); } catch (IOException ioe) { Logging.Print("IOException: " + ioe.Message); } finally { m_IsAlive = false; if (m_CommandSocket != null) { m_CommandSocket.Close(); m_CommandSocket = null; } if (m_ListenSocket != null) { m_ListenSocket.Close(); m_CommandSocket = null; } Logging.Print("Client Disconnected."); } }