FileZillaIt is a fast and reliable FTP client and server-side open source code program with a variety of features and intuitive interfaces. This article analyzes the source code of FileZilla.
After the service thread wakes up, it calls OnThreadMessage to process the WM_FILEZILLA_THREADMSG message. The parameter is FTM_NEWSOCKET and sockethandle. Then it enters the AddNewSocket method, indicating that a new client needs to be connected.
Void CServerThread: AddNewSocket (SOCKET sockethandle, bool ssl)
{
// Create a new CControlSocket class, which is also inherited from the CAsyncSocketEx class. After initialization, The CControlSocket class will take over the client connection.
CControlSocket * socket = new CControlSocket (this );
Socket-> Attach (sockethandle); // Add it to the FileZilla message mechanism to establish the relationship with the distribution thread.
CStdString ip;
Unsigned int port;
SOCKADDR_IN sockAddr;
Memset (& sockAddr, 0, sizeof (sockAddr ));
Int nSockAddrLen = sizeof (sockAddr );
BOOL bResult = socket-> GetPeerName (SOCKADDR *) & sockAddr, & nSockAddrLen); // obtain the information of the socket Client
If (bResult)
{
Port = ntohs (sockAddr. sin_port); // port
Ip = inet_ntoa (sockAddr. sin_addr); // ip address
}
Else
{
Socket-> m_RemoteIP = _ T ("ip unknown ");
Socket-> m_userid = 0;
Socket-> SendStatus (_ T ("Can't get remote IP, disconnected"), 1 );
Socket-> Close ();
Delete socket;
Return;
}
Socket-> m_RemoteIP = ip;
EnterCritSection (m_GlobalThreadsync );
Int userid = CalcUserID (); // automatically generates a customer ID for the current socket connection: userID
If (userid =-1)
{
LeaveCritSection (m_GlobalThreadsync );
Socket-> m_userid = 0;
Socket-> SendStatus (_ T ("Refusing connection, server too busy! "), 1 );
Socket-> Send (_ T ("421 Server too busy, closing connection. Please retry later! "));
Socket-> Close ();
Delete socket;
Return;
}
Socket-> m_userid = userid;
T_socketdata data;
Data. pSocket = socket;
Data. pThread = this;
M_userids [userid] = data; // m_userids is static and is defined as static std: map m_userids;
// You can ignore hammering.
// Check if remote IP is blocked due to hammering
Std: map: iterator iter = m_antiHammerInfo.find (sockAddr. sin_addr.s_addr );
If (iter! = M_antiHammerInfo.end ())
{
If (iter-> second> 10)
Socket-> AntiHammerIncrease (25 );//~ 6 secs delay
}
LeaveCritSection (m_GlobalThreadsync );
EnterCritSection (m_threadsync );
// Record the CControlSocket processed by this service thread
M_LocalUserIDs [userid] = socket;
LeaveCritSection (m_threadsync );
T_connectiondata_add * conndata = new t_connectiondata_add;
T_connop * op = new t_connop;
Op-> data = conndata;
Op-> op = USERCONTROL_CONNOP_ADD; // The new user is about to connect. It must be used in OnServerMessage of CServer.
Op-> userid = userid;
Conndata-> pThread = this;
Memset (& sockAddr, 0, sizeof (sockAddr ));
NSockAddrLen = sizeof (sockAddr );
BResult = socket-> GetPeerName (SOCKADDR *) & sockAddr, & nSockAddrLen );
If (bResult)
{
Conndata-> port = ntohs (sockAddr. sin_port );
# Ifdef _ UNICODE
_ Tcscpy (conndata-> ip, ConvFromLocal (inet_ntoa (sockAddr. sin_addr); // copy the string
# Else
_ Tcscpy (conndata-> ip, inet_ntoa (sockAddr. sin_addr ));
# Endif
}
// Send a message to the global hMainWnd,
// The wParam type of the message is FSM_CONNECTIONDATA, indicating that the message is a connection-related message. The parameter is t_connop.
// These are used to process the message in WindowProc of the CServer. After the message is processed, it will be displayed below the admin window.
// Information similar to 000001 (not logged in) 127.0.0.1
SendNotification (FSM_CONNECTIONDATA, (LPARAM) op );
If (ssl) // SSL-related, you can skip this step first.
If (! Socket-> InitImplicitSsl ())
Return;
Socket-> AsyncSelect (FD_READ | FD_WRITE | FD_CLOSE); // establishes a listener relationship for these events on the socket
// SendStatus still calls the SendNotification method, but the sent parameter is FSM_STATUSMESSAGE,
// Therefore, the processing in CServer is not the same
Socket-> SendStatus (_ T ("Connected, sending welcome message..."), 0 );
// In this case, the lower part of the admin window displays a message similar to (000003) 3:26:47-(not logged in) (127.0.0.1)> Connected, sending welcome message...
// Format the welcome information below
CStdString msg = m_pOptions-> GetOption (OPTION_WELCOMEMESSAGE );
If (m_RawWelcomeMessage! = Msg)
{
M_RawWelcomeMessage = msg;
M_ParsedWelcomeMessage.clear ();
Msg. Replace (_ T ("%"), _ T ("\ 001 "));
Msg. Replace (_ T ("% v"), GetVersionString ());
Msg. Replace (_ T ("\ 001"), _ T ("% "));
ASSERT (msg! = _ T (""));
Int oldpos = 0;
Msg. Replace (_ T ("\ r \ n"), _ T ("\ n "));
Int pos = msg. Find (_ T ("\ n "));
CStdString line;
While (pos! =-1)
{
ASSERT (pos );
M_ParsedWelcomeMessage.push_back (_ T ("220-") + msg. Mid (oldpos, pos-oldpos ));
Oldpos = pos + 1;
Pos = msg. Find (_ T ("\ n"), oldpos );
}
Line = msg. Mid (oldpos );
If (line! = _ T (""))
M_ParsedWelcomeMessage.push_back (_ T ("220") + line );
Else
{
M_ParsedWelcomeMessage.back () [3] = 0;
}
}
// HideStatus indicates whether to send this welcome message to admin port
Bool hideStatus = m_pOptions-> GetOptionVal (OPTION_WELCOMEMESSAGE_HIDE )! = 0;
ASSERT (! M_ParsedWelcomeMessage.empty ());
For (std: list : Iterator iter = m_ParsedWelcomeMessage.begin (); iter! = M_ParsedWelcomeMessage.end (); iter ++)
// Send the message to the socket Client and send the message to the admin port. The parameter sent is FSM_STATUSMESSAGE.
If (! Socket-> Send (* iter ,! HideStatus ))
Break;
// Run here. The welcome information appears on the client logon interface and in the admin window, similar:
// (000003) 3:27:19-(not logged in) (127.0.0.1)> 220-FileZilla Server version 0.9.18 beta
// (000003) 3:27:22-(not logged in) (127.0.0.1)> 220-written by Tim Kosse (Tim.Kosse@gmx.de)
// (000003) 3:27:29-(not logged in) (127.0.0.1)> 220 Please visit http://sourceforge.net/projects/filezilla/
Through the complete description in this article, you should know the source code of FileZilla and hope to help you!