Click here to Skip to main content
11,631,525 members (70,658 online)
Click here to Skip to main content
Add your own
alternative version

A Complete FTP Server

, 30 May 2005 379.7K 23.5K 161
This article presents a fully functional implementation of a FTP server.
/****************************************************************/
/*																*/
/*  ConnectThread.cpp											*/
/*																*/
/*  Implementation of the Connect Thread.						*/
/*	Created when a client logs on to the server and processes	*/
/*  'Send' commando's.											*/
/*	This class is a part of Quick 'n Easy FTP Server.			*/
/*																*/
/*  Copyright Pablo Software Solutions 2005						*/
/*	http://www.pablosoftwaresolutions.com						*/
/*																*/
/*  Last updated: May 28, 2005									*/
/*																*/
/****************************************************************/


#include "stdafx.h"
#include "FTPServerApp.h"
#include "FTPServer.h"
#include "ApplicationDlg.h"
#include "ConnectThread.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


IMPLEMENT_DYNCREATE(CConnectThread, CWinThread)


/********************************************************************/
/*																	*/
/* Function name : CConnectThread::CConnectThread					*/
/* Description   : Constructor										*/
/*																	*/
/********************************************************************/
CConnectThread::CConnectThread()
{
	m_nReceivedBytes = 0;
	m_nSentBytes = 0;
	m_nTimerID = 0;
	m_LastDataTransferTime = CTime::GetCurrentTime();
}


/********************************************************************/
/*																	*/
/* Function name : CConnectThread::~CConnectThread					*/
/* Description   : Destructor										*/
/*																	*/
/********************************************************************/
CConnectThread::~CConnectThread()
{
}


/********************************************************************/
/*																	*/
/* Function name : InitInstance										*/		
/* Description   : Perform tasks that must be completed when the	*/
/*				   thread is first created.							*/
/*																	*/
/********************************************************************/
BOOL CConnectThread::InitInstance()
{
	 // This solve statical link problem 
#ifndef _AFXDLL 
	VERIFY(AfxSocketInit()); 
#endif 

	try
	{
		// Attach the socket handle to a CSocket object.
		// This makes sure that the socket notifications are sent to this thread.
		m_ControlSocket.Attach(m_hSocket);
		m_ControlSocket.m_pThread = this;

		CString strIPAddress;
		UINT nPort;
		m_ControlSocket.GetPeerName(strIPAddress, nPort);

		// notify server that there's a new connection
		m_pWndServer->SendMessage(WM_THREADSTART, (WPARAM)this, 0);
		
		if (((CFTPServer *)m_pWndServer)->CheckMaxUsers())
		{
			m_ControlSocket.SendResponse("421 Too many users are connected, please try again later.");
			PostThreadMessage(WM_QUIT,0,0);
		}
		else
		{
			// send welcome message to client
			m_ControlSocket.SendResponse("220 %s", ((CFTPServer *)m_pWndServer)->GetWelcomeMessage());
			m_nTimerID = ::SetTimer(NULL, 0, 1000, TimerProc); 
		}
	}
	catch(CException *e) 
	{
		e->Delete();
	}
	return TRUE;
}


/********************************************************************/
/*																	*/
/* Function name : ExitInstance										*/		
/* Description   : Perform clean-up when the thread terminates.		*/
/*																	*/
/********************************************************************/
int CConnectThread::ExitInstance()
{
	CFTPServer *pWnd = (CFTPServer *)m_pWndServer;

	try
	{
		pWnd->m_CriticalSection.Lock();
		
		// delete this thread from the linked list
		POSITION pos = pWnd->m_ThreadList.Find(this);
		if(pos != NULL)
		{
			pWnd->m_ThreadList.RemoveAt(pos);
		}
		pWnd->m_CriticalSection.Unlock();    		

		// notify service main loop
		pWnd->SendMessage(WM_THREADCLOSE, (WPARAM)this, 0);
	
	}
	catch(CException *e) 
	{
		pWnd->m_CriticalSection.Unlock();
		e->Delete();
	}
	return CWinThread::ExitInstance();
}


BEGIN_MESSAGE_MAP(CConnectThread, CWinThread)
	//{{AFX_MSG_MAP(CConnectThread)
	//}}AFX_MSG_MAP
	ON_THREAD_MESSAGE(WM_DESTROYDATACONNECTION, OnDestroyDataConnection)
END_MESSAGE_MAP()



/********************************************************************/
/*																	*/
/* Function name : IncSentBytes										*/		
/* Description   : Increment number of bytes sent by the server.	*/
/*																	*/
/********************************************************************/
void CConnectThread::IncSentBytes(int nBytes)
{
	m_LastDataTransferTime = CTime::GetCurrentTime();
	m_nSentBytes += nBytes;
	// notify server class
	m_pWndServer->PostMessage(WM_THREADMSG, (WPARAM)0, (LPARAM)nBytes);
}


/********************************************************************/
/*																	*/
/* Function name : IncReceivedBytes									*/		
/* Description   : Increment number of bytes received by the server.*/
/*																	*/
/********************************************************************/
void CConnectThread::IncReceivedBytes(int nBytes)
{
	m_LastDataTransferTime = CTime::GetCurrentTime();
	m_nReceivedBytes += nBytes;
	// notify server class
	m_pWndServer->PostMessage(WM_THREADMSG, (WPARAM)1, (LPARAM)nBytes);
}


/********************************************************************/
/*																	*/
/* Function name : UpdateStatistic									*/	
/* Description   : Specific statistics has been changed.			*/
/*																	*/
/********************************************************************/
void CConnectThread::UpdateStatistic(int nType)
{
	// notify server class
	m_pWndServer->PostMessage(WM_THREADMSG, (WPARAM)2, (LPARAM)nType);
}


/********************************************************************/
/*																	*/
/* Function name : OnDestroyDataConnection							*/		
/* Description   : Thread message received.							*/
/*																	*/
/********************************************************************/
void CConnectThread::OnDestroyDataConnection(WPARAM wParam, LPARAM lParam)
{
	// destroy data socket
	m_ControlSocket.DestroyDataConnection();
}


/********************************************************************/
/*																	*/
/* Function name : TimerProc										*/	
/* Description   : Callback function for timer.						*/
/*																	*/
/********************************************************************/
VOID CALLBACK CConnectThread::TimerProc(HWND hwnd, UINT uMsg, UINT uIDEvent, DWORD dwTime)
{
	CConnectThread *pThread = (CConnectThread *)AfxGetThread();

	if (uIDEvent == pThread->m_nTimerID)
	{
		int nConnectionTimeout = ((CFTPServer *)pThread->m_pWndServer)->GetTimeout();
		// check for connection timeout
		CTime time = pThread->m_LastDataTransferTime;
		time += CTimeSpan(0, 0, nConnectionTimeout, 0);
		if (time < CTime::GetCurrentTime())
		{
			pThread->m_ControlSocket.SendResponse("426 Connection timed out, aborting transfer");
			pThread->PostThreadMessage(WM_QUIT,0,0);
		}
	}
} 

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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

Share

About the Author

Pablo van der Meer
Web Developer
Netherlands Netherlands
No Biography provided

You may also be interested in...

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