Exemplo n.º 1
0
        /// <summary>
        /// Add context to the right listener
        ///     share the same prefix
        ///     the longer prefix wins
        /// </summary>
        /// <param name="context"></param>
        internal void AddContext(FtpListenerContext context)
        {
            // Decide which listen should this context added to
            int         prefixLength      = -1;
            FtpListener candidateListener = null;

            foreach (FtpListener listener in m_Listeners)
            {
                if (listener.IsListening)
                {
                    int length = listener.CheckPrefix(context.Request.QueryString);
                    if (length > prefixLength)
                    {
                        candidateListener = listener;
                        prefixLength      = length;
                    }
                }
            }
            if (candidateListener != null)
            {
                candidateListener.AddContext(context);
            }
            else
            {
                if (m_DefaultListener == null)
                {
                    m_DefaultListener = new FtpDefaultListener();
                    m_DefaultListener.Start();
                }
                m_DefaultListener.AddContext(context);
            }
        }
        protected virtual void Run()
        {
            for (; ;)
            {
                FtpListenerContext context = this.GetContext();
                if (context == null)
                {
                    // the listener has been closed
                    return;
                }
                FtpResponseStream stream = context.Response.OutputStream;
                switch (context.Request.Method)
                {
                case WebRequestMethodsEx.Ftp.ChangeDirectory:
                    context.Response.StatusCode = DirectoryExists(context.Request.QueryString) ? FtpStatusCode.FileActionOK : FtpStatusCode.ActionNotTakenFileUnavailable;
                    break;

                case WebRequestMethods.Ftp.ListDirectory:
                case WebRequestMethods.Ftp.ListDirectoryDetails:
                    WriteDirInfo(context.Request.QueryString, stream);
                    context.Response.StatusCode = FtpStatusCode.ClosingData;
                    break;

                case WebRequestMethods.Ftp.RemoveDirectory:
                    context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                    break;

                default:
                    context.Response.StatusCode = FtpStatusCode.ActionAbortedLocalProcessingError;
                    break;
                }
                stream.Close();
            }
        }
Exemplo n.º 3
0
 void IContextManager.AddContext(FtpListenerContext context)
 {
     AddContext(context);
 }
 /// <summary>
 /// Add context to the right listener
 ///     share the same prefix
 ///     the longer prefix wins
 /// </summary>
 /// <param name="context"></param>
 internal void AddContext(FtpListenerContext context)
 {
     // Decide which listen should this context added to
     int prefixLength = -1;
     FtpListener candidateListener = null;
     foreach (FtpListener listener in m_Listeners)
     {
         if (listener.IsListening)
         {
             int length = listener.CheckPrefix(context.Request.QueryString);
             if (length > prefixLength)
             {
                 candidateListener = listener;
                 prefixLength = length;
             }
         }
     }
     if (candidateListener != null)
     {
         candidateListener.AddContext(context);
     }
     else
     {
         if (m_DefaultListener == null)
         {
             m_DefaultListener = new FtpDefaultListener();
             m_DefaultListener.Start();
         }
         m_DefaultListener.AddContext(context);
     }
 }
 void IContextManager.AddContext(FtpListenerContext context)
 {
     AddContext(context);
 } 
        /// <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.");
            }
        }
Exemplo n.º 7
0
        private static void ProcessClientRequest()
        {
            Debug.Print("Welcome to the FTP Service.");

            FtpListener.AuthenticationEvent += (object sender, UserAuthenticatorArgs e) =>
            {
                if (e.User == "anonymous")
                {
                    Debug.Print("hi anonymous");
                    e.Result = UserAuthenticationResult.Approved;
                }
            };

            // a custom listener will be looking after the "special" directory in the ROOT volumes only
            FtpListener listener = new FtpListener();

            listener.Prefixes.Add(virtualROOT + "special/");
            listener.Start();

            // all other directories will be handled by the standard listener, on both volumes
            FtpListener listener_root = new FtpFilesystemListener(virtualROOT, @"\ROOT\");

            listener_root.Start();
            FtpListener listener_winfs = new FtpFilesystemListener(virtualWINFS, @"\WINFS\");

            listener_winfs.Start();

            for (; ;)
            {
                FtpListenerContext context = listener.GetContext();
                Stream             stream  = context.Response.OutputStream;

                switch (context.Request.Method)
                {
                case WebRequestMethodsEx.Ftp.ChangeDirectory:

                    string path      = context.Request.QueryString.Substring(virtualROOT.Length);
                    int    markerIdx = path.IndexOf('/');
                    if (markerIdx != -1)
                    {
                        path = path.Substring(0, markerIdx);
                        string dir = @"\ROOT\" + path;
                        if (Directory.Exists(dir) && monitoredDirectory == dir)
                        {
                            Debug.Print("Changed to the monitored directory");
                            context.Response.StatusCode = FtpStatusCode.FileActionOK;
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                        }
                    }
                    else
                    {
                        Directory.SetCurrentDirectory(@"\ROOT");
                        context.Response.StatusCode = FtpStatusCode.FileActionOK;
                    }
                    stream.Close();
                    break;

                case WebRequestMethods.Ftp.ListDirectory:
                case WebRequestMethods.Ftp.ListDirectoryDetails:
                {
                    DirectoryInfo cd = new DirectoryInfo(monitoredDirectory);
                    foreach (FileInfo fi in cd.GetFiles())
                    {
                        (stream as FtpResponseStream).Write(fi);
                    }
                    foreach (DirectoryInfo di in cd.GetDirectories())
                    {
                        (stream as FtpResponseStream).Write(di);
                    }
                    context.Response.StatusCode = FtpStatusCode.ClosingData;
                    stream.Close();
                }
                break;

                case WebRequestMethods.Ftp.DownloadFile:
                    DirectoryInfo info     = new DirectoryInfo(monitoredDirectory);
                    string        prefix   = virtualROOT + info.Name + "/";
                    string        download = context.Request.QueryString.Substring(prefix.Length);
                    string        file     = monitoredDirectory + @"\" + download;
                    if (!File.Exists(file))
                    {
                        throw new Exception("File does not exists!");
                    }

                    using (FileStream fs = new FileStream(file, FileMode.Open))
                    {
                        (stream as FtpResponseStream).Write(fs);
                        context.Response.StatusCode = FtpStatusCode.ClosingData;
                        stream.Close();
                    }
                    break;

                default:
                    context.Response.StatusCode = FtpStatusCode.CommandNotImplemented;
                    stream.Close();
                    break;
                }
            }
        }
        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.");
            }
        }
        private void WorkerThread()
        {
            for (; ;)
            {
                FtpListenerContext context = this.GetContext();
                string             log     = "Get new context. Request type: " + context.Request.Method + " Query string: " + context.Request.QueryString;
                m_Logging.Add(log);
                FtpResponseStream stream = context.Response.OutputStream;
                switch (context.Request.Method)
                {
                case WebRequestMethodsEx.Ftp.ChangeDirectory:
                    bool accepted = false;
                    foreach (string prefix in m_Prefixes)
                    {
                        if (context.Request.QueryString == prefix)
                        {
                            accepted = true;
                            break;
                        }
                    }
                    if (accepted)
                    {
                        context.Response.StatusCode = FtpStatusCode.FileActionOK;
                    }
                    else
                    {
                        context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                    }
                    break;

                case WebRequestMethods.Ftp.ListDirectoryDetails:
                    foreach (FileInfo info in m_FileInfo)
                    {
                        stream.Write(info);
                    }
                    stream.Write(new FileInfo("\\log"));
                    context.Response.StatusCode = FtpStatusCode.ClosingData;
                    break;

                case WebRequestMethods.Ftp.GetFileSize:
                    if (context.Request.QueryString.IndexOf("log") >= 0)
                    {
                        int length = 0;
                        foreach (string s in m_Logging)
                        {
                            length += s.Length + 2;
                        }
                        stream.Write(length.ToString());
                        context.Response.StatusCode = FtpStatusCode.FileStatus;
                    }
                    else
                    {
                        context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                    }
                    break;

                default:
                    context.Response.StatusCode = FtpStatusCode.ActionAbortedLocalProcessingError;
                    break;
                }
                stream.Close();
            }
        }