Filezilla FTP Server Source Code Analysis 11
After an FTP client establishes a socket connection with the filezilla server through the FTP localhost command, the filezilla server displays the welcome information, which is displayed on the screen (we use the FTP command in Windows as the sample ):
Connected to Dell.
220-filezilla server version 0.9.18 Beta
220-written by Tim kosse (Tim.Kosse@gmx.de)
220 please visit http://sourceforge.net/projects/filezilla/
User (Dell :( none )):
Enter the user name. If the user enters the WHG and press enter, the FTP client translates the characters entered by the user into the standard FTP command "User WHG" and sends them to the server, this is because ccontrolsocket listens to this socket, And the Recv-related events are finally distributed to the onreceive method of ccontrolsocket through the distribution mechanism mentioned above. Below I will look at this method:
M_antihammeringwaittime does not know what the function is. When tracing source code, its initial value is 0, so skip this step first.
The lower part is to get the speed limit speedlimit. If there is no limit, it is-1.
Next:
Int numread = receive (buffer, Len); // call Recv to obtain the socket data, and put the data with the length of Len into the buffer.
After successful reading, put the received data in the buffer in one byte into m_recvbuffer:
M_recvbuffer [m_nrecvbufferpos ++] = buffer [I];
Then put the received m_recvbuffer into m_recvlinebuffer:
M_recvlinebuffer.push_back (m_recvbuffer );
M_recvlinebuffer is equivalent to a command pool, which stores commands sent by users but not yet processed.
Finally, after the Recv is processed, call parsecommand () to explain the command.
First, getcommand () is used to obtain the TOP Command in m_recvlinebuffer and interpret it as the command and The args parameter. For example, the command user WHG is interpreted as command = user, argS = WHG.
The following cycle:
For (INT I = 0; I <(sizeof (commands)/sizeof (t_command); I ++)
Check whether the command is included in all commands of the pre-defined FTP server commands to verify the validity of the command just received. If the command is not in commands, it is displayed that the command is an illegal command, send the client
Send (_ T ("500 syntax error, command unrecognized ."));
Even if the command is legal, if the parameter is incorrect (bhasargs specifies whether a parameter is required for this command), that is, some commands must contain parameters while ARGs does not, it will send:
Send (_ T ("501 syntax error "));
Below:
If (! M_recvlinebuffer.empty ())
M_powner-> postthreadmessage (wm_filezilla_threadmsg, ftm_command, m_userid );
If there are still unprocessed commands in the command buffer, the message is sent to cserverthread, which processes the message in method onthreadmessage:
Else if (wparam = ftm_command)
{// Process a command sent from a client
Ccontrolsocket * socket = getcontrolsocket (lparam );
If (socket)
Socket-> parsecommand ();
}
In the getcontrolsocket () method:
Ccontrolsocket * cserverthread: getcontrolsocket (INT userid)
{
Ccontrolsocket * ret = 0;
Entercritsection (m_threadsync );
// The following map is user-> ccontrolsocket, that is, to find the ccontrolsocket that serves this userid through userid
STD: Map <int, ccontrolsocket *>: iterator iter = m_localuserids.find (userid );
If (ITER! = M_localuserids.end ())
Ret = ITER-> second;
Leavecritsection (m_threadsync );
Return ret;
}
It can be seen that the role of sending this message is to allow ccontrolsocket to continue to call parsecommand () to process the next command.
Return to the original parsecommand (). If the command parameter is correct, check whether the command must be logged on before use (specified by bvalidbeforelogon). For example, the GET command must be logged on first, the USER command is not required. If you must log on first, send:
Send (_ T ("530 please log in with user and pass first ."));
The following is the same:
M_powner-> postthreadmessage (wm_filezilla_threadmsg, ftm_command, m_userid );
If all commands are qualified, the following code is displayed:
Switch (ncommandid)
To process different commands. Because the command_user command is used, let's take a look at the processing process:
After some processing
Send (_ T ("331 Password required for") + ARGs );
Ask the user to enter the password, which will be displayed on the client screen:
331 Password required for WHG
Password:
After the user enters the password, press Enter. Then the FTP client translates it into a standard FTP command "Pass 123456" and sends it to the server. Let's take a look at how parsecommand () processes this:
Case command_pass:
Else if (douserlogin (ARGs ))
Send (_ T ("230 logged on "));
After douserlogin () determines that the logon is successful, send the Successful Logon Message to the client. Otherwise, an error message is sent:
Send (_ T ("530 login or password incorrect! "));
Take a closer look at cpermissions: checkuserlogin () and you will find that the password is MD5 encrypted. When you create a cserverthread, the member variables related to permissions are initialized:
M_ppermissions = new cpermissions;
In cpermissions: Init (), call readsettings () to read all user information (including passwords) from the configuration file to the memory, therefore, the password verification is only a string comparison in the memory.
After the user successfully logs on, the FTP client displays:
C:/Documents and Settings/Administrator> FTP localhost
Connected to Dell.
220-filezilla server version 0.9.18 Beta
220-written by Tim kosse (Tim.Kosse@gmx.de)
220 please visit http://sourceforge.net/projects/filezilla/
User (Dell :( none): WHG
331 Password required for WHG
Password:
230 logged on
Ftp>
The following FTP server is waiting for the new FTP command.