FtpSession.cs
资源名称:FtpServer.rar [点击查看]
上传用户:xuelanruo
上传日期:2015-04-02
资源大小:163k
文件大小:35k
源码类别:
Ftp服务器
开发平台:
C#
- /*
- Ftp Dot Net FtpSession Class : manage each client-session
- Copyright (C)
- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Last modification : 04/26/2004 by Simon FERQUEL
- */
- using System;
- using System.IO;
- using System.Data;
- using System.Collections;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;
- namespace FtpServerLibrary
- {
- /// <summary>
- /// Description r閟um閑 de FtpSession.
- /// </summary>
- public class FtpSession
- {
- private Socket m_pClientSocket = null; // Socket du client
- private FtpServer m_pServer = null; // Server parent
- private long m_SessionID ; // Identificateur de la session
- private string m_UserName = ""; // Nom de l'utilisateur
- private string m_CurrentDir = "/"; // R閜ertoire courrant
- private string m_renameFrom = "";
- private bool m_PassiveMode = false; // Flag mode passif
- private TcpListener m_pPassiveListener = null; // Listener en cas de mode passif
- private IPEndPoint m_pDataConEndPoint = null; // "EndPoint" pour la connection de donn閑s
- private bool m_Authenticated = false; // Flag utilisateur authentifi?
- private int m_BadCmdCount = 0; // Nombre de commandes erron閑s
- private DateTime m_SessionStartTime; // Date de d閎ut de session
- private EndPoint m_rmtEndPoint; // adresse du client
- private int m_offset = 0; // offset utile en cas d'usage de l'option "resume"
- private Hashtable m_vPaths; // Liste des r閜ertoire virtuels appliqu閟 ?l'utilisateur
- public void Close()
- {
- try{this.m_pClientSocket.Close();}
- catch{}
- try{this.m_pPassiveListener.Stop();}
- catch{}
- }
- #region Propri閠閟
- public long SessionID
- {
- get{return m_SessionID;}
- }
- public EndPoint RemoteEndPoint
- {
- get{return this.m_rmtEndPoint;}
- }
- private string m_ftproot = "";
- public Socket ClientSocket
- {
- get{return this.m_pClientSocket;}
- }
- #endregion
- /// <summary>
- /// Constructeur par defaut
- /// </summary>
- /// <param name="clientSocket">Socket du client connect?/param>
- /// <param name="server">instance ded FtpServer</param>
- /// <param name="sessionID">Num閞o de session</param>
- public FtpSession(Socket clientSocket,FtpServer server,long sessionID)
- {
- this.m_pClientSocket=clientSocket;
- this.m_rmtEndPoint=clientSocket.RemoteEndPoint;
- this.m_pServer=server;
- this.m_SessionID=sessionID;
- this.m_SessionStartTime=System.DateTime.Now;
- }
- /// <summary>
- /// M閠hode permettant d'envoyer un message au client
- /// </summary>
- /// <param name="data">Message ?envoyer</param>
- private void SendData(string data)
- {
- Byte[] byte_data = System.Text.Encoding.Default.GetBytes(data.ToCharArray());
- m_pClientSocket.Send(byte_data,byte_data.Length,0);
- }
- /// <summary>
- /// Fonction permettant de lire une commande tap閑 par le client.
- /// </summary>
- /// <param name="clientSocket">Socket du client</param>
- /// <param name="timeOut">Nombre de secondes maximum pour la lecture</param>
- /// <returns></returns>
- private string ReadLine(Socket clientSocket,int timeOut)
- {
- long lastDataTime = DateTime.Now.Ticks; //date de derni鑢e r閏eption
- ArrayList lineBuf = new ArrayList(); //Buffer
- byte prevByte = 0;
- while(true)
- {
- if(clientSocket.Available > 0)
- {
- // On lit un octet
- byte[] currByte = new byte[1];
- int countRecieved = clientSocket.Receive(currByte,1,SocketFlags.None);
- // Si un octet est re鐄 (parfois ?la premi鑢e tentative, le client n'envoie rien)
- if(countRecieved == 1)
- {
- //on stocke l'octet dans le buffer
- lineBuf.Add(currByte[0]);
- // Si on arrive en fin de ligne, on renvoie la commande
- if((prevByte == (byte)'r' && currByte[0] == (byte)'n'))
- {
- byte[] retVal = new byte[lineBuf.Count-2]; // On enl鑦e les caract鑢es de fin de ligne
- lineBuf.CopyTo(0,retVal,0,lineBuf.Count-2);
- return System.Text.Encoding.Default.GetString(retVal).Trim();
- }
- // on update la valeur de prevByte
- prevByte = currByte[0];
- //On met ?jour la date de derni鑢e r閏eption
- lastDataTime = DateTime.Now.Ticks;
- }
- }
- else
- {
- //Si le Timeout est atteint on lance une excepion
- if(DateTime.Now.Ticks > lastDataTime + ((long)(timeOut)) * 10000)
- {
- throw new ReadException(ReadReplyCode.TimeOut,"Read timeout");
- }
- System.Threading.Thread.Sleep(100);//N閏essaire pour des raisons 関identes de performance
- }
- }
- }
- /// <summary>
- /// Boucle de lecture et traitement des messages du client
- /// </summary>
- public void StartProcessing()
- {
- //le serveur est pr阾
- this.SendData(Messages.MessReady());
- long lastCmdTime = DateTime.Now.Ticks; //Date de 閏eption de la derni鑢e commande
- string lastCmd = "";
- //Tant que le session time out n'est pas atteint ou que la commande "QUIT" n'est pas demand閑, on boucle
- try
- {
- while(true)
- {
- //Si des donn閑s arrivent, on commence ?les lire.
- if (this.m_pClientSocket.Available >0)
- {
- try
- {
- lastCmd=this.ReadLine(m_pClientSocket,this.m_pServer.SessionIdleTimeOut);//Lecture de la Commande
- if(!SwitchCommand(lastCmd))//Si la commande est "QUIT" on quitte la boucle de traitement
- {
- break;
- }
- }
- catch(ReadException rX)
- {
- //On verifie que le nombre maximum d'erreurs de commandes n'est pas atteint
- if(m_BadCmdCount > m_pServer.MaxBadCommands-1)
- {
- SendData(Messages.MessTooManyBadCmds());//On envoie un message
- break;//et on quitte la boucle de traitement
- }
- m_BadCmdCount++;
- switch(rX.ReadReplyCode)//En fonction du type d'ereur (pour l'instant TimeOut et Unknown) on envoie un message
- {
- case ReadReplyCode.TimeOut:
- SendData(Messages.CmdTimeOut());
- break;
- case ReadReplyCode.UnknownError:
- SendData(Messages.UnknownError());
- break;
- }
- }
- catch
- {
- if(!this.m_pClientSocket.Connected)break;//Si le socket a 閠?d閏onnect? on quitte la boucle
- SendData(Messages.UnknownError());//Sinon on envoie un message d'erreur inconnu
- }
- //On update la date de la derni鑢e commande
- lastCmdTime = DateTime.Now.Ticks;
- }
- else
- {
- //On verifie qu'on n'aie pas atteint le timeOut
- if(DateTime.Now.Ticks > lastCmdTime + ((long)(m_pServer.SessionIdleTimeOut)) * 10000)
- {
- // Notification de fermeture de session
- SendData("500 Session timeout, OK FTP server signing offrn");
- break;
- }
- // On attends 100 ms afin d'閏onomiser le cpu (sinon la boucle mange trop de ressources).
- Thread.Sleep(100);
- }
- }
- //Fermeture du Socket
- if(m_pClientSocket.Connected)
- {
- m_pClientSocket.Close();
- }
- //Destruction de la session
- this.m_pServer.RemoveSession(this.m_SessionID);
- }
- catch
- {
- this.m_pServer.RemoveSession(this.m_SessionID);
- }
- }
- /// <summary>
- /// En fonction de la commande utilisateur donn閑, cette fonction appelle la fonction ad閝uate
- /// </summary>
- /// <param name="commandTxt">Commande envoy閑</param>
- /// <returns>True si la session doit continuer, false si elle doit s'arr阾er (commande QUIT par exemple)</returns>
- private bool SwitchCommand(string commandTxt)
- {
- string[] cmdParts = commandTxt.TrimStart().Split(new char[]{' '});
- string command = cmdParts[0].ToUpper().Trim();
- switch(command)
- {
- case "QUIT":
- QUIT();
- return false;
- case "USER":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- USER(args);
- }
- else
- {
- USER(cmdParts[1]);
- }
- }
- break;
- case "TYPE":
- if (cmdParts.Length!=2)SendData(Messages.UnknownError());
- else TYPE(cmdParts[1]);
- break;
- case "PASS":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- PASS(args);
- }
- else
- {
- PASS(cmdParts[1]);
- }
- }
- break;
- case "PWD":
- PWD();
- break;
- case "XPWD":
- PWD();
- break;
- case "SYST":
- SYST();
- break;
- case "PORT":
- if (cmdParts.Length!=2)SendData(Messages.UnknownError());
- else PORT(cmdParts[1]);
- break;
- case "PASV":
- PASV();
- break;
- case "LIST":
- if (cmdParts.Length>1){
- if (cmdParts[1].Trim().ToLower()=="-a"||cmdParts[1].Trim().ToLower()=="-l"||cmdParts[1].Trim().ToLower()=="-al")
- {
- string[] parts=new string[cmdParts.Length-1];
- parts[0]=cmdParts[0];
- for (int i=2;i<cmdParts.Length;i++)
- parts[i-1]=cmdParts[i];
- cmdParts=parts;
- }
- }
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- LIST(args);
- }
- else if(cmdParts.Length==2)LIST(cmdParts[1]);
- else LIST(String.Empty);
- break;
- case "NLST":
- if (cmdParts.Length>1)
- {
- if (cmdParts[1].Trim().ToLower()=="-a"||cmdParts[1].Trim().ToLower()=="-l"||cmdParts[1].Trim().ToLower()=="-al")
- {
- string[] parts=new string[cmdParts.Length-1];
- parts[0]=cmdParts[0];
- for (int i=2;i<cmdParts.Length;i++)
- parts[i-1]=cmdParts[i];
- cmdParts=parts;
- }
- }
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- LIST(args);
- }
- else if(cmdParts.Length==2)NLST(cmdParts[1]);
- else NLST(String.Empty);
- break;
- case "CWD":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- CWD(args);
- }
- else
- {
- CWD(cmdParts[1]);
- }
- }
- break;
- case "RETR":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- RETR(args);
- }
- else
- {
- RETR(cmdParts[1]);
- }
- }
- break;
- case "STOR":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- STOR(args);
- }
- else
- {
- STOR(cmdParts[1]);
- }
- }
- break;
- case "DELE":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- DELE(args);
- }
- else
- {
- DELE(cmdParts[1]);
- }
- }
- break;
- case "RMD":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- RMD(args);
- }
- else
- {
- RMD(cmdParts[1]);
- }
- }
- break;
- case "APPE":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- APPE(args);
- }
- else
- {
- APPE(cmdParts[1]);
- }
- }
- break;
- case "RNFR":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- RNFR(args);
- }
- else
- {
- RNFR(cmdParts[1]);
- }
- }
- break;
- case "RNTO":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- RNTO(args);
- }
- else
- {
- RNTO(cmdParts[1]);
- }
- }
- break;
- case "MKD":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- MKD(args);
- }
- else
- {
- MKD(cmdParts[1]);
- }
- }
- break;
- case "REST":
- if (cmdParts.Length<2)SendData(Messages.UnknownError());
- else
- {
- if (cmdParts.Length>2)
- {
- string args="";
- for(int i=1;i<cmdParts.Length;i++)
- {
- args+=cmdParts[i]+" ";
- }
- REST(args);
- }
- else
- {
- REST(cmdParts[1]);
- }
- }
- break;
- case "CDUP" :
- CWD("..");
- break;
- case "NOOP" :
- NOOP();
- break;
- default:
- SendData("500 Invalid command " + command + "rn");
- break;
- }
- return true;
- }
- /// <summary>
- /// Cette fonction ne fait absoluement rien
- /// </summary>
- private void NOOP()
- {
- SendData("200 OK rn");
- }
- /// <summary>
- /// Cr閍tion d'un nouveau r閜ertoire
- /// </summary>
- /// <param name="argsText">nom du r閜ertoire</param>
- private void MKD(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- try
- {
- new DirectoryInfo(file).Create();
- SendData("257 Directory Created. rn");
- }
- catch
- {
- SendData(Messages.AccesDenied());
- return;
- }
- }
- /// <summary>
- /// Juste avant un RNTO permet de sp閏ifi?le nom du fichier ?renomer
- /// </summary>
- /// <param name="argsText"></param>
- private void RNFR(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir)||!(System.IO.File.Exists(file)||System.IO.Directory.Exists(file)))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- this.m_renameFrom=file;
- SendData("350 Please specify destination name.rn");
- }
- /// <summary>
- /// Etape suivant le RNFR
- /// </summary>
- /// <param name="argsText"></param>
- private void RNTO(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- if(this.m_renameFrom.Length<1)
- {
- SendData("503 Bad sequence of commands. rn");
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- try
- {
- (new System.IO.FileInfo(this.m_renameFrom)).MoveTo(file);
- SendData("250 Directory renamed.rn");
- }
- catch
- {
- try
- {
- (new System.IO.DirectoryInfo(this.m_renameFrom)).MoveTo(file);
- SendData("250 Directory renamed.rn");
- }
- catch
- {
- SendData("550 Error renameing directory or file .rn");
- }
- }
- this.m_renameFrom="";
- }
- /// <summary>
- /// Cette m閠hode permet de d閒inir l'offset a partir duquel un fichier est t閘閏harg?
- /// (n閏essaire pour la fonction resume)
- /// </summary>
- /// <param name="argsText">offset</param>
- private void REST(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- try
- {
- this.m_offset=Convert.ToInt32(argsText);
- SendData("350 Restarting at "+this.m_offset.ToString()+"rn");
- }
- catch
- {
- SendData("554 bad argument for RESTrn");
- }
- }
- /// <summary>
- /// Cette m閠hode permet ?l'utilisateur d'envoyer la "fin" d'un fichier
- /// </summary>
- /// <param name="argsText">fichier ?compl閠er</param>
- private void APPE(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- FileStream fs;
- try
- {
- fs=new FileStream(file,FileMode.OpenOrCreate,FileAccess.Write);
- fs.Position=fs.Length;
- }
- catch
- {
- SendData(Messages.AccesDenied());
- return;
- }
- Socket socket=this.GetDataConnection();
- try
- {
- if(socket==null||fs==null)
- {
- throw new Exception();
- }
- int readed = 1;
- byte[] buffer=new byte[4096];
- while(readed>0)
- {
- readed=socket.Receive(buffer);
- fs.Write(buffer,0,readed);
- }
- socket.Shutdown(SocketShutdown.Both);
- socket.Close();
- SendData(Messages.TrComplete());
- }
- catch
- {
- SendData(Messages.TrFailed());
- socket.Close();
- }
- fs.Close();
- }
- /// <summary>
- /// Cette m閠hode permet au client de suprimer un fichier
- /// </summary>
- /// <param name="argsText">fichier ?supprimer</param>
- private void DELE(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir)||!System.IO.File.Exists(file))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- try
- {
- new FileInfo(file).Delete();
- SendData(Messages.DeleOk());
- }
- catch
- {
- SendData(Messages.AccesDenied());
- }
- }
- /// <summary>
- /// Suppression d'un r閜ertoire
- /// </summary>
- /// <param name="argsText"></param>
- private void RMD(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir)||!System.IO.Directory.Exists(file))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- try
- {
- new DirectoryInfo(file).Delete();
- SendData(Messages.DeleOk());
- }
- catch
- {
- SendData(Messages.AccesDenied());
- }
- }
- /// <summary>
- /// Cette m閠hode permet au client d'envoyer un fichier
- /// </summary>
- /// <param name="argsText">Nom du fichier envoy?/param>
- private void STOR(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file, out newCurdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- FileStream fs;
- try
- {
- fs=new FileStream(file,FileMode.OpenOrCreate,FileAccess.Write);
- fs.Position=this.m_offset;
- fs.SetLength(this.m_offset);
- }
- catch
- {
- SendData(Messages.AccesDenied());
- return;
- }
- Socket socket=this.GetDataConnection();
- try
- {
- if(socket==null||fs==null)
- {
- throw new Exception();
- }
- int readed = 1;
- byte[] buffer=new byte[4096];
- while(readed>0)
- {
- readed=socket.Receive(buffer);
- fs.Write(buffer,0,readed);
- }
- socket.Shutdown(SocketShutdown.Both);
- socket.Close();
- SendData(Messages.TrComplete());
- }
- catch
- {
- SendData(Messages.TrFailed());
- socket.Close();
- }
- fs.Close();
- }
- /// <summary>
- /// Cette m閠hode permet au client de t閘閏harger un fichier
- /// </summary>
- /// <param name="argsText">Fichier ?t閘閏harger (relatif au r閜ertoire courant)</param>
- private void RETR(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string file;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,argsText,this.m_vPaths,out file,out newCurdir)||!System.IO.File.Exists(file))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- FileStream fs;
- try
- {
- Socket socket=this.GetDataConnection();
- fs=new FileStream(file,FileMode.Open,FileAccess.Read);
- fs.Position=this.m_offset;
- if(socket==null || fs==null)
- {
- throw new Exception();
- }
- int readed = 1;
- byte[] buffer=new byte[4096];
- while(readed > 0)
- {
- readed=fs.Read(buffer,0,buffer.Length);
- socket.Send(buffer,readed,SocketFlags.None);
- }
- socket.Shutdown(SocketShutdown.Both);
- socket.Close();
- SendData(Messages.TrComplete());
- }
- catch
- {
- SendData(Messages.TrFailed());
- return;
- }
- fs.Close();
- }
- /// <summary>
- /// Cette m閠hode envoie un message comme quoi la connection va 阾re ferm閑
- /// (elle correspond ?la commande client "QUIT")
- /// </summary>
- private void QUIT()
- {
- SendData(Messages.SignOff());
- }
- /// <summary>
- /// Cette m閠hode permet ?l'utilisateur de rentrer son login
- /// </summary>
- /// <param name="argsText">login</param>
- private void USER(string argsText)
- {
- if(m_Authenticated)
- {
- SendData(Messages.AlreadyAuth());
- return;
- }
- if(m_UserName.Length > 0)
- {
- SendData(Messages.UserButNotPass());
- return;
- }
- string userName = argsText;
- SendData(Messages.PassReq(argsText));
- m_UserName = userName;
- }
- /// <summary>
- /// Cette m閠hode permet ?l'utilisateur de saisir son mot de passe
- /// </summary>
- /// <param name="argsText">Mot de passe</param>
- private void PASS(string argsText)
- {
- if(m_Authenticated)
- {
- SendData(Messages.AlreadyAuth());
- return;
- }
- if(m_UserName.Length == 0)
- {
- SendData(Messages.EnterUser());
- return;
- }
- try
- {
- if((this.m_ftproot=Helpers.GetFtpRoot(this.m_UserName))==string.Empty)
- {
- SendData("530 Bad Home");
- return;
- }
- }
- catch(Exception e)
- {
- SendData(e.Message);
- }
- this.m_vPaths=Helpers.VPaths(this.m_UserName);
- // Authentification de l'utilisateur
- if(WinAuth.Auth(m_UserName,argsText))
- {
- m_Authenticated = true;
- SendData(Messages.PassOk());
- }
- else
- {
- SendData(Messages.AuthFailed());
- m_UserName = ""; // R閕nitialisation du nom d'utilisateur
- }
- }
- /// <summary>
- /// Informe l'utilisateur sur le r閜ertoire courrant
- /// </summary>
- private void PWD()
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- SendData(Messages.Pwd(m_CurrentDir));
- }
- /// <summary>
- /// Informe l'utilisateur sur le syst鑝e surlequel tourne le serveur
- /// </summary>
- private void SYST()
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- SendData("215 Windows_NTrn");
- }
- /// <summary>
- /// D閒init le type de donn閑 transitant entre client et serveur
- /// </summary>
- /// <param name="argsText">type</param>
- private void TYPE(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- if(argsText.Trim().ToUpper() == "A" || argsText.Trim().ToUpper() == "I")
- {
- SendData(Messages.TypeSet(argsText));
- }
- else
- {
- SendData(Messages.InvalidType(argsText));
- }
- }
- /// <summary>
- /// La m閠hode port permet de d閒inir l'adresse TCP/IP de la connection de donn閑 avec le client.
- /// En mode PORT, c'est le client qui 閏oute la connection de donn閑, en mode PASV, c'est le serveur.
- /// </summary>
- /// <param name="argsText">suite de 6 octets (sous forme d閏imale) repr閟entant l'ip et le port. i1,i2,i3,i4,p1,p2 (avec p1 octet de poid fort et p2 octet de poid faible)</param>
- private void PORT(string argsText)
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- //on s閜are d'abord les diff閞entes parties de l'adresse
- string[] parts = argsText.Split(',');
- //on v閞ifie la syntaxe
- if(parts.Length != 6)
- {
- SendData(Messages.SyntaxError());
- return;
- }
- //On d閒init l'adresse ip
- string ip=parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3];
- //le port est d閒init par un calcul au niveau bit : la premi鑢e partie est d閏al閑 de 8bits vers l gauche et addition閑 avec la deuxi鑝e partie.
- int port = (Convert.ToInt32(parts[4]) << 8) | Convert.ToInt32(parts[5]);
- m_pDataConEndPoint = new IPEndPoint(System.Net.Dns.GetHostByAddress(ip).AddressList[0],port);
- this.m_PassiveMode=false;
- SendData(Messages.PortCmdSuccess());
- }
- /// <summary>
- /// La m閠hode pasv permet de d閒inir l'adresse TCP/IP de la connection de donn閑 avec le client.
- /// En mode PORT, c'est le client qui 閏oute la connection de donn閑, en mode PASV, c'est le serveur.
- /// </summary>
- private void PASV()
- {
- if(!m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- //On commence par chercher un port libre pour lancer l'閏oute
- int port = 1025;
- while(true)
- {
- try
- {
- m_pPassiveListener = new TcpListener(IPAddress.Any,port);
- m_pPassiveListener.Start();
- //Si on arrive jusqu'ici, c'est que le port est libre
- break;
- }
- catch
- {
- port++;
- }
- }
- //A partir du socket, on recr?une chaine de type i1,i2,i3,i4,p1,p2
- string ip = m_pClientSocket.LocalEndPoint.ToString();
- ip = ip.Substring(0,ip.IndexOf(":"));
- ip=ip.Replace(".",",");
- //la premi鑢e partie du port est cr殚e en d閜la鏰nt les 8 bits de poids fort vers la droite,
- //la deuxi鑝e est cr閑 en ne prenant que les 8 bits de poids faible (2^8=256)
- ip += "," + (port >> 8) + "," + (port & 255);
- SendData(Messages.PasvCmdSuccess(ip));
- m_PassiveMode = true;
- }
- /// <summary>
- /// Retourne au client la liste du contenu du r閜ertoire courant (ou de celui donn?en argument) avec des d閠ails
- /// </summary>
- private void LIST(string args)
- {
- //l'utilisateur doit 阾re identifi?
- if(!this.m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- try
- {
- string cdir;
- string newCurdir;
- //on formate le r閜ertoire voulu
- //On v閞ifie la validit?du r閜ertoire et on r閏up鑢e le chemin physique que l'on teste ensuite
- //la fct?IsValidDir ne v閞ifie aps la pr閟ence du r閜ertoire car elle est aussi utilis閑 pour cr閑r des fichiers ou des r閜ertoires.
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,args,this.m_vPaths,out cdir,out newCurdir)||!System.IO.Directory.Exists(cdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- //on r閏up鑢e ensuite tous les fichiers et r閜ertoires contenus ainsi que leur propri閠閟
- //pour ensuite les envoyer par le sockets
- ArrayList files=new ArrayList();
- try
- {
- files.AddRange(System.IO.Directory.GetDirectories(cdir));
- files.AddRange(Helpers.VPathsInDir(this.m_CurrentDir,this.m_vPaths));
- files.AddRange(System.IO.Directory.GetFiles(cdir));
- }
- catch
- {
- SendData(Messages.AccesDenied());
- return;
- }
- //On r閏up鑢e le socket de donn閑s
- Socket socket=this.GetDataConnection();
- string msg="";
- foreach (string file in files)
- {
- if(System.IO.File.Exists(file))
- {
- /*msg+=System.IO.File.GetLastWriteTime(file).ToString("MM-dd-yy hh:mm")+" ";
- msg+=new System.IO.FileInfo(file).Length.ToString()+" ";
- msg+=System.IO.Path.GetFileName(file)+"rn";
- */
- msg+="-rwxrwxrwx 0 0 0 ";
- msg+=new System.IO.FileInfo(file).Length.ToString()+" ";
- msg+=MonthFromInt(System.IO.File.GetLastWriteTime(file).Month)+" "+System.IO.File.GetLastWriteTime(file).ToString("dd hh:mm")+" ";
- msg+=System.IO.Path.GetFileName(file)+"rn";
- }
- else if(System.IO.Directory.Exists(file))
- {
- /*
- msg+=System.IO.Directory.GetLastWriteTime(file).ToString("MM-dd-yy hh:mm")+" ";
- msg+=" <DIR> "+System.IO.Path.GetFileName(file)+"rn";
- */
- msg+="drwxrwxrwx 0 0 0 ";
- msg+=" 4096 ";
- msg+=MonthFromInt(System.IO.Directory.GetLastWriteTime(file).Month)+" "+System.IO.Directory.GetLastWriteTime(file).ToString("dd hh:mm")+" ";
- msg+=System.IO.Path.GetFileName(file)+"rn";
- }
- else
- {
- msg+="drwxrwxrwx 0 0 0 ";
- msg+=" 4096 ";
- msg+=MonthFromInt(System.DateTime.Now.Month)+" "+System.DateTime.Now.ToString("dd hh:mm")+" ";
- msg+=file+"rn";
- }
- }
- byte[] toSend=System.Text.Encoding.Default.GetBytes(msg);
- socket.Send(toSend);
- socket.Shutdown(SocketShutdown.Both);
- socket.Close();
- SendData(Messages.TrComplete());
- }
- catch
- {
- SendData(Messages.TrFailed());
- }
- }
- private string MonthFromInt(int month)
- {
- switch(month)
- {
- case 1 :
- return "jan";
- break;
- case 2 :
- return "feb";
- break;
- case 3 :
- return "mar";
- break;
- case 4 :
- return "apr";
- break;
- case 5 :
- return "may";
- break;
- case 6 :
- return "jun";
- break;
- case 7 :
- return "jul";
- break;
- case 8 :
- return "aug";
- break;
- case 9 :
- return "sep";
- break;
- case 10 :
- return "oct";
- break;
- case 11 :
- return "nov";
- break;
- case 12 :
- return "dec";
- break;
- default :
- return "";
- }
- }
- /// <summary>
- /// Retourne au client la liste du contenu du r閜ertoire courant (ou de celui donn?en argument) sans d閠ails
- /// </summary>
- private void NLST(string args)
- {
- //l'utilisateur doit 阾re identifi?
- if(!this.m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- try
- {
- string cdir;
- string newCurdir;
- //on formate le r閜ertoire voulu
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,args,this.m_vPaths,out cdir, out newCurdir)||!System.IO.Directory.Exists(cdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- ArrayList files=new ArrayList();
- try
- {
- files.AddRange(System.IO.Directory.GetDirectories(cdir));
- files.AddRange(Helpers.VPathsInDir(this.m_CurrentDir,this.m_vPaths));
- files.AddRange(System.IO.Directory.GetFiles(cdir));
- }
- catch
- {
- SendData(Messages.AccesDenied());
- return;
- }
- //On r閏up鑢e le socket de donn閑s
- Socket socket=this.GetDataConnection();
- string msg="";
- foreach (string file in files)
- {
- if(System.IO.File.Exists(file))
- {
- msg+=System.IO.Path.GetFileName(file)+"rn";
- }
- else if(System.IO.Directory.Exists(file))
- {
- msg+=System.IO.Path.GetFileName(file)+"rn";
- }
- else
- {
- msg+=file+"rn";
- }
- }
- byte[] toSend=System.Text.Encoding.Default.GetBytes(msg);
- socket.Send(toSend);
- socket.Shutdown(SocketShutdown.Both);
- socket.Close();
- SendData(Messages.TrComplete());
- }
- catch
- {
- SendData(Messages.TrFailed());
- }
- }
- /// <summary>
- /// Changement de r閜ertoire courrant
- /// </summary>
- /// <param name="args">R閜ertoire</param>
- private void CWD(string args)
- {
- try
- {
- if(!this.m_Authenticated)
- {
- SendData(Messages.AuthReq());
- return;
- }
- string cdir;
- string newCurdir;
- if(!Helpers.IsValidDir(this.m_ftproot,this.m_CurrentDir,args.Trim(),this.m_vPaths,out cdir, out newCurdir)||
- !System.IO.Directory.Exists(cdir))
- {
- SendData(Messages.AccesDenied());
- return;
- }
- this.m_CurrentDir=newCurdir;
- SendData(Messages.CwdOk());
- }
- catch
- {
- SendData(Messages.AccesDenied());
- }
- }
- /// <summary>
- /// Fonction permettant d'obtenir le socket de donn閑
- /// </summary>
- /// <returns>Socket de donn閑s</returns>
- private Socket GetDataConnection()
- {
- Socket socket = null;
- try
- {
- //si on est en mode passif
- if(m_PassiveMode)
- {
- long startTime = DateTime.Now.Ticks;
- // On attend que le server est re鐄 une requ鑤e de connection
- while(!m_pPassiveListener.Pending())
- {
- System.Threading.Thread.Sleep(50);
- // Time out apr鑣 30 secondes
- if((DateTime.Now.Ticks - startTime) / 10000 > 20000)
- {
- throw new Exception("Ftp server didn't respond !");
- }
- }
- //On accepte le socket
- socket = m_pPassiveListener.AcceptSocket();
- SendData(Messages.DataOpen());
- }
- else //Si en mode actif
- {
- SendData(Messages.DataOpening());
- socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
- socket.Connect(m_pDataConEndPoint);
- }
- }
- catch
- {
- SendData("425 Can't open data connection.rn");
- return null;
- }
- m_PassiveMode = false;
- return socket;
- }
- }
- }