Click here to Skip to main content
Click here to Skip to main content

A Complete FTP Server

By , 30 May 2005
 

Sample Image

Description

This article presents a fully functional implementation of a FTP server. It can handle multiple connections at the same time (multi threaded) and has most of the features you would find in other commercial/shareware FTP servers. The server handles all basic FTP commands and offers easy user account management.

This article describes the most important classes of the application:

CFTPServer

This class is in fact the FTP server, and controls all other classes needed for the server to work. Although CFTPServer is part of a dialog based application, it does not rely on a User Interface and can easily be implemented in a service or console application as well.

  • BOOL Start()

    Activates the FTP server. It opens a listening socket (port 21) to accept connections.

  • void Stop()

    Deactivates the server and disconnects all connected clients by terminating the running threads.

  • BOOL IsActive()

    Is FTP server active?

  • void SetMaxUsers(int nValue)

    Set maximum number of users.

  • void SetPort(int nValue)

    Set listening port for new connections.

  • void SetTimeout(int nValue)

    Set connection timeout (in ms). When a client does not send any commands for nValue ms, the server will close the connection.

  • void SetWelcomeMessage(LPCTSTR lpszText)

    Set the text that will be displayed when the client logs on.

  • void Initialize(CFTPEventSink *pEventSink)

    Set the event sink. The event sink will be the window (or any class) that receives the events generated by the FTP server. See CFTPEventSink description for more info.

CFTPEventSink

To be able to 'send' events from the CFTPServer class to the main application, I used multiple inheritance and virtual functions. The CFTPEventSink is just a helper class that contains nothing else than virtual functions, when you derive your class from CFTPEventSink these virtual functions become a kind of events. The class CFTPServer has a reference to this class and calls the virtual functions when it needs to notify the application.

The following 'events' are available:

  • void OnFTPUserConnected(DWORD nThreadID, LPCTSTR lpszUser, LPCSTR lpszAddress);

    A client has successfully connected.

  • void OnFTPUserDisconnected(DWORD nThreadID, LPCTSTR lpszUser);

    A client has disconnected.

  • void OnFTPStatusChange(int nType, LPCTSTR lpszText);

    FTP server status has changed (file downloaded/uploaded).

  • void OnFTPReceivedBytesChange(int nBytes);

    The number of received bytes has changed.

  • void OnFTPSentBytesChange(int nBytes);

    The number of sent bytes received has changed.

  • void OnFTPStatisticChange(int nType, int nValue);

    A statistic has changed, for example the number of downloaded or uploaded files.

Other helper classes:

CUserManager

The class CUserManager handles all user and file related stuff. It checks the connected users for their access rights and converts remote to local paths. CUserManager uses serializing for storing and loading the user settings.

CListenSocket

This socket is part of CFTPServer and accepts incoming connections. When a clients connects to the server, CListenSocket accepts the connection and creates a new thread (CConnectThread) that will take care of all further communication between the client and the server. After the thread has been created, CListenSocket will return to its waiting state.

CConnectThread

This thread will handle all communication between the client and the server using CConnectSocket.

CConnectSocket

This socket class will process all incoming FTP commands and send back the response to the client.

CDataSocket

When data needs to be send or received, a CDataSocket will be created by CConnectSocket. The CDataSocket class will transfer this data (such as directory listings and files) on a separate port.

All the other classes are just UI related and are only included to make it look a little bit fancier.

CFTPServer Usage:

To use the class in your application, you need to do the following:

  1. Add the class to your application.
  2. Derive your main class from CFTPEventSink.
  3. Override the virtual functions of CFTPEventSink; these are the events that come from the server.
  4. Initialize the eventsink.
  5. Start the server.
class CMyDlg : public CDialog, CFTPEventSink
{
    ...

    CFTPServer m_FTPSERVER;
    
    virtual void OnFTPUserConnected(DWORD nThreadID, 
                 LPCTSTR lpszUser, LPCSTR lpszAddress);
    virtual void OnFTPUserDisconnected(DWORD nThreadID, LPCTSTR lpszUser);
    virtual void OnFTPStatusChange(int nType, LPCTSTR lpszText);
    virtual void OnFTPReceivedBytesChange(int nBytes);
    virtual void OnFTPSentBytesChange(int nBytes);
    virtual void OnFTPStatisticChange(int nType, int nValue);

    ...
}


BOOL CMyDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    
    ...

    // initialize event sink
    m_FTPSERVER.Initialize(this);
    // set maximum users to 10
    m_FTPSERVER.SetMaxUsers(10);
    // accept new connections on port 21
    m_FTPSERVER.SetPort(21);
    // activate server
    m_FTPSERVER.Start();

    return TRUE;
}

Contacting the Author

For any updates to this article, check my site.

Credits

Inspired by FileZilla Server.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Pablo van der Meer
Web Developer
Netherlands Netherlands
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralAsking a Guarantee of Permission For Us From DevelopermemberViolet_Lotus21 Apr '12 - 7:36 
We have a project for our examination on university. I hope , the developer permits us to develop the program. Your program is the best of our team view.
 
We need ASAP response from developer.
 
Thank's
 
Best Regards
 
5 Serangkai Team
 
Developer
 
Andrew Reza
GeneralMy vote of 5memberdarvenLee25 Aug '10 - 21:57 
I found that its function can be realized ,so I recommend
GeneralHave a doubt in pasv commandmemberSabari Girishwar Rao10 Oct '09 - 7:07 
I have a small doubt in pasv command. My local system is connected to net using a broadband modem where it is connected via a router. If i want to connect to my ftp server from out side over net i need to use my external ip and its working fine getting connected, but it works only till executing the pasv command and no file list is displayed, my doubt is when responding for the pasv command i can send only my internal ip and a new connection to view the file list is not getting connected.
 
Below is the sample code. Actually this is working fine few months back, recently i had changed most of the parts and i dont know what happend to this.
 

// Here ClientSocket is the existing socket connection with the client
// Port is the temporary port for passiv mode
string EndPoint = ClientSocket.LocalEndPoint.ToString();
EndPoint = EndPoint.Substring(0, EndPoint.IndexOf(":"));
EndPoint = EndPoint.Replace(".", ",") + "," + (Port >> 8) + "," + (Port & 255);
 
Obtaining an external ip and sending it in in pasv response may work fine, but it was not an actual solution as the same code was working before few months back. Can you please help me out to solve this porblem. I am working on my college project with this and i need it as soon as possible. Thank you...
GeneralTrying to understand what the dummy window for message routing is trying to domembertom2349928 Feb '09 - 6:55 
I am wondering what the following means in the overall scope of the program that the code is doing ? I am new to Visual C++ (MFC) and needed help understanding what this doing.
 
BOOL CFTPServer::Start()
{
// create dummy window for message routing
if (!CWnd::CreateEx(0, AfxRegisterWndClass(0), "FTP Server Notification Sink", WS_POPUP, 0,0,0,0, NULL, 0))
{
.......
......
 
}
GeneralA question about STOR commandmemberJason( J.Zhang)10 Dec '08 - 21:13 
Hi
 
Thanks for your greate job first.
 
I have a question about stor command.
When control socket recive a "stor" command,control socket calls CreateDataConnection to connect to client and then prepare to recive the file.
If OnConnect be called just after connect. And client sends file at once, control socket have no time to
call RetrieveFile and PrepareReceiveFile won't be called. So File cannot be recviced correctly.
 
What's your opinion?
 
Thanks
Questionhow to find ftp address for my servermemberNprabahar23 Sep '08 - 7:39 
I am unable to get the server address for the ftp server which is installed in my pc. kindly tel me how to logon to the server.
 
As per my understanding ftp://username@ftpaddress
AnswerRe: how to find ftp address for my servermembertom234998 Mar '09 - 17:00 
It would be the IP address of the computer which you have installed FTP Server on. Also if you have changed the port number you will need to modify the address to include the port number if its not 21.
GeneralConverting application to objectmembermcunha982 Jul '08 - 5:01 
Not is possible convert this application to a library/component for use with another applications (compiling something like an OCX,DLL,TLB) ?
 

Mauricio Cunha
www.mcunha98.cjb.net
mcunha98@terra.com.br

QuestionBug... 1064960 bytes and then it blocks....memberG_T29 May '08 - 6:02 
Hi Pablo,


I have recently been looking into making my own FTP server. So I downloaded from CodeProject your FTP Server written in C++/MFC. It works really well, and it was very useful, however I thought I would point out that I believe that there is a bug in that version. If you push too many files, or even just a single large file it will stop uploading at 1064960 bytes, and (most clients, I use Filezilla... as I am an opensource fan) will ask you if you would like to overnight the file even if you haven't finished uploading it. I have been looking at your code, and I cannot see the reason for thisFrown | :(

I thought I would bring this to your attention. You might have already fixed this error in later versions which I noticed you have created from your website, e.g the Baby FTP Server and the QuickNEasy one. May I know how to fix this bug?

Thank you for your help,

Best regards,
GeneralC++ .NET Sourcememberjmanson2 May '08 - 6:16 
Pablo,
 
Did you ever make the C++ .NET code available for download?
 
Great work BTW!
 
-Jake
QuestionHow can I get c# source code?memberLeSang23 Aug '07 - 15:42 
How can I get c# source code?
 
THT

AnswerRe: How can I get c# source code?memberAghochikyan9 Sep '07 - 2:19 
I can send you a C++ code for .NET. If it will help you.
 
Visit our site: Emergency Soft
GeneralGot errors while compling the FTPSERVER in 2.0 frameworkmembermesh21238829 Jul '07 - 16:15 
i got these errors when i complied the ftp server. someone pls help on how to complie the FTP server successfully in Mircosoft Visula studio Framewrok 2.0. Thanks a lot.
 
Warning 1 Command line warning D9025 : overriding '/D_DEBUG' with '/U_DEBUG' cl
 
Warning 2 warning C4996: '_splitpath' was declared deprecated c:\documents and settings\mohan\my documents\ntu\year 4 semester 1\fyp stuff\fwthesourcecode\ftpserver\stdafx.cpp 104
 

Error 3 error C2664: 'MultiByteToWideChar' : cannot convert parameter 5 from 'WORD [260]' to 'LPWSTR' c:\documents and settings\mohan\my documents\ntu\year 4 semester 1\fyp stuff\fwthesourcecode\ftpserver\stdafx.cpp 276
 

Error 4 error C2664: 'IPersistFile::Load' : cannot convert parameter 1 from 'WORD [260]' to 'LPCOLESTR' c:\documents and settings\mohan\my documents\ntu\year 4 semester 1\fyp stuff\fwthesourcecode\ftpserver\stdafx.cpp 279
 

 

 
Ramesh
Confused | :confused: Confused | :confused:
GeneralRe: Got errors while compling the FTPSERVER in 2.0 frameworkmemberRobert nAppliance31 Aug '11 - 14:39 
Try making the following change (WORD to WCHAR) in the line where the compiler fails:
 
// WORD wsz [MAX_PATH]; // buffer for Unicode string
WCHAR wsz [MAX_PATH]; // buffer for Unicode string
Questioncan not run in true 64 bitmemberMember #160677122 Feb '07 - 5:56 
I have compiled it into a 64bit app, but it cannot run!
QuestionFTP url tracingmemberamitbk81@yahoo.com24 Jan '07 - 20:22 
if user gives URL like ftp:// then FTP server will show the folder structure, i want to capture this link in any method or program, how i do it??
Thxn in Advance
 
asdfasdfasdfasdf

GeneralFTP url tracingmemberamitbk81@yahoo.com24 Jan '07 - 20:21 

 
asdfasdfasdfasdf

General64-bit file sizememberstd.denis7 Jan '07 - 2:15 
neither this FTP server, nor Baby FTP are not supports files greater than 4Gb
i've fixed it by simple using I64 modificator in format string in CControlSocket::GetDirectoryList [ strLength.Format("%I64d", find.GetLength()); ] and using of ULONGLONG as type for CDataSocket::m_nTotal* variables
Questionhow to run with chinese file and folder namememberfnjcr7 Dec '06 - 19:40 
I am in china,when I use this client and the server showed in http://www.codeproject.com/cs/internet/ftplibrary.asp?forumid=15023&select=1794998&df=100&msg=1794998[^]
 
if the name of the file or folder contain chinese word,it can not to upload!
how can i get it?
 
thanks
 
i post the same question on http://www.codeproject.com/cs/internet/ftplibrary.asp?forumid=15023&select=1794998&df=100&msg=1794998[^]
Generalmultithreaded downloadmemberlathi26 May '06 - 1:36 
can anyone give me the approach to download a file from a ftp server using multithreding. (i.e. separate threads for downloading simultaneously USING JAVA)
 
VIVEK
QuestionA Complete FTP Server source usagememberViswanatha Shastry27 Apr '06 - 20:05 
Hi !,
I found this article is interesting and wanted to use the source in my project.
I have to develop a FTP server with minimum functionality (uploading and downloding the files).
Please let me know if I use the source is there any licensing problems ?
An early reply appriciated.
 
Thanks
Viswanatha Shastry M.
GeneralMemory leak problem.memberVCPP631 Oct '04 - 15:20 
When doing a large number of file transfers, the system will crash for memory problem.
 

GeneralMessage Title: Socket Notification Sink: FtpServer.exesussAnonymous2 Nov '04 - 14:48 
Memory (000020) can not be read
GeneralRe: Message Title: Socket Notification Sink: FtpServer.exememberPablo van der Meer2 Nov '04 - 20:18 
Check out for updates/bugfixes:
http://www.pablovandermeer.nl/ftp_server.html

GeneralBug report in DataSocket.cppmemberVCPP69 Sep '04 - 8:42 
Hi, Paolo, I very thank your great job first!
 
I have found serval bugs in your program. One of them is that the program run very well in WINDOWS98(Client)/Windows98(Server), or Window2k|XP(Client)/Windows2k|XP running mode, but there will be a bug in Windows98(client)/Windows2K|XP running mode. The client software is using your FTP client program.
 
I found the receive() got a big problem.
 
If a FTP transfer finished sucessfully, the program will use the Receive() function at least twice. First time. it receive the data of XXX characters, XXX is less or equal to PACKET_SIZE, second it must be 0 character.
 
But in Win98(client)/Win2K(Server) mode, sometime the program only pass the function one time. so it not past the statement:
 
case 0: m_File.Close();
 
It get a big problem.
 
How to fix the bug? Thanks
 
coolzergLaugh | :laugh: Roll eyes | :rolleyes:
 

 

int CDataSocket::Receive()
{
int nRead = 0;

if (m_nStatus == XFERMODE_RECEIVE)
{
if (m_File.m_hFile == NULL)
return 0;
 
byte data[PACKET_SIZE];
nRead = CAsyncSocket::Receive(data, PACKET_SIZE);
 

switch(nRead)
{
case 0:
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pConnectSocket->SendResponse("226 Transfer complete 4");
AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADSUCCEEDED);
break;
}
case SOCKET_ERROR:
{
if (GetLastError() != WSAEWOULDBLOCK)
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pConnectSocket->SendResponse("426 Connection closed; transfer aborted.");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
// upload failed
((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
 
}
break;
}
default:
{
((CConnectThread *)AfxGetThread())->IncReceivedBytes(nRead);
 
TRY
{
m_File.Write(data, nRead);
}
CATCH_ALL(e)
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pConnectSocket->SendResponse("450 can't access file.");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_THREADMSG, 0, 0);
// upload failed
((CConnectThread *)AfxGetThread())->UpdateStatistic(FTPSTAT_UPLOADFAILED);
ProcessFiles();
return 0;
}
END_CATCH_ALL;
}
}
}
return nRead;
}

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 30 May 2005
Article Copyright 2002 by Pablo van der Meer
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid