/****************************************************************/
/*																*/
/*  CONNECTTHREAD.CPP											*/
/*																*/
/*  Implementation of the Connect Thread.						*/
/*	Created when a client logs on to the server and processes	*/
/*  'Send' commando's.											*/
/*																*/
/*  Programmed by LYFZ van der Meer							    */
/*	http://www.LYFZvandermeer.nl								*/
/*																*/
/*  Last updated: 15 july 2002									*/
/*																*/
/****************************************************************/
//��ConnectThread.cpp�ļ���ʵ�������̵߳Ĵ���������߳�����������ͻ��˵����ӡ�
//��һ���ͻ���¼�����������߳̽���������������"Send"���

#include "stdafx.h"
#include "DBServer.h"
#include "theDBServer.h"
#include "DBServerDlg.h"
#include "ConnectThread.h"
#include "MyLock.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
extern CtheDBServer *g_pWndServer;
CStringArray g_connuserarray;
CStringArray g_logintimearray;
extern CConnectThread *g_pThreadPt[200];
extern int g_conncount;
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.							*/
/*																	*/
/********************************************************************/
//��ʼ���߳�

int FindArray3(CStringArray *pArray, CString Str)
{
	int count=0;
	for(int i=0; i<pArray->GetSize (); i++)
	{
		if(pArray->ElementAt (i)==Str)
			count++;
	}
	return count;
}

extern CString g_localip;
extern void GetOneConn(CDatabase **m_pdb, CArray<CDatabase*,CDatabase*>*m_dbarray, CConnectThread *pThread);
extern int FindArray(CStringArray *pArray, CString Str);
void GetConnCount(CStringArray *pArray)
{
	g_pWndServer->m_CriticalSection.Lock();
	CConnectThread *pThread;
	POSITION   pos;
	pos=g_pWndServer->m_ThreadList.GetHeadPosition();
	while(pos)
	{
		pThread=g_pWndServer->m_ThreadList.GetNext(pos);
		if(g_localip==pThread->m_strRemoteHost)continue;
		if(::FindArray(pArray, pThread->m_strRemoteHost)==-1)
			pArray->Add(pThread->m_strRemoteHost);
	}
	g_pWndServer->m_CriticalSection.Unlock();
}

BOOL CConnectThread::InitInstance()
{
	try
	{
		g_pWndServer->m_CriticalSection.Lock();
		g_pWndServer->m_ThreadList.AddTail(this);
		g_pWndServer->m_CriticalSection.Unlock();
		m_ConnectSocket.Attach(m_hSocket);
		m_ConnectSocket.Init();
		m_ConnectSocket.m_pThread = this;
		CString strIPAddress;
		UINT nPort;
		m_ConnectSocket.GetPeerName(strIPAddress, nPort);
		m_strRemoteHost=strIPAddress;
		m_strRemoteHost.TrimLeft ();

#ifdef CONNCOUNT_VERSION
		if(g_localip!=strIPAddress)
		{ 		
			CStringArray iparray;
			BOOL bmax=0;
			if(1)
			{
				//	GetConnCount(&iparray);
				if(FindArray3(&g_connuserarray, strIPAddress)==0 && g_connuserarray.GetSize ()>g_conncount)
					//		if( iparray.GetSize ()>g_conncount)
				{
					bmax=1;
				}
			}
			
			if(bmax)
			{	
				CString ss;
			//	ss.Format("��ϯ�����ӳ�����ip:%s���ܾ���%d/%d", strIPAddress, iparray.GetSize (), g_conncount);
				ss.Format("��ϯ�����ӳ�����ip:%s���ܾ���%d/%d", strIPAddress, g_connuserarray.GetSize (), g_conncount);
				WriteLogin(ss);
				PostThreadMessage(WM_QUIT,0,0);		
				return 0;
			}
			else if(FindArray3(&g_connuserarray, strIPAddress)==0)
			{
				MyLock lock("g_connuserarray");
				g_connuserarray.Add (strIPAddress);
				g_logintimearray.Add (CTime::GetCurrentTime ().Format("%H:%M:%S"));
			}
		}
#endif
		// ֪ͨ������һ���µ����ӵ���
		g_pWndServer->SendMessage(WM_THREADSTART, (WPARAM)this, 0);
	/*	if(AddConn(&m_conndb, "db")==0)
		{
			WriteLogin("�������ݿ�����ʧ��");
			PostThreadMessage(WM_QUIT,0,0);
			return 0;
		}
	    m_conndb.SetQueryTimeout(60*2);
		m_ConnectSocket.m_pConndb=&m_conndb;*/

		m_ConnectSocket.m_pdb=NULL;
		GetOneConn(&m_ConnectSocket.m_pdb, &m_ConnectSocket.m_dbarray, this);
	/*	if (g_pWndServer->CheckMaxUsers())
		{
		//	m_ConnectSocket.SendResponse("421 Too many users are connected, please try again later.");
			
			WriteLogin("���ӳ����������");PostThreadMessage(WM_QUIT,0,0);
		}
		else
		if (!g_pWndServer->IsIPAddressAllowed(strIPAddress))
		{
		//	m_ConnectSocket.SendResponse("421 Access denied, IP address was rejected by the server.");
		
			WriteLogin("�Ƿ�IP��ַ");	PostThreadMessage(WM_QUIT,0,0);
		}
		else*/
		{
		//	AfxMessageBox(strIPAddress);
			// ���ͻ�ӭ��Ϣ���ͻ���
		//	m_ConnectSocket.SendResponse("220 %s", g_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.		*/
/*																	*/
/********************************************************************/
//�߳���ֹ
extern int FindArray(CStringArray *pArray, CString Str);
int CConnectThread::ExitInstance()
{
	try
	{
		g_pWndServer->m_CriticalSection.Lock();
		
		// ��������ɾ����ǰ�߳�
		POSITION pos = g_pWndServer->m_ThreadList.Find(this);
		if(pos != NULL)
		{
			g_pWndServer->m_ThreadList.RemoveAt(pos);
		}
		g_pWndServer->m_CriticalSection.Unlock();    		

		//֪ͨ������ѭ��
		g_pWndServer->SendMessage(WM_THREADCLOSE, (WPARAM)this, 0);


/*
#ifdef CONNCOUNT_VERSION
		MyLock lock("g_connuserarray");
		int pos2=::FindArray (&g_connuserarray, m_strRemoteHost);
		if(pos2!=-1)
		    g_connuserarray.RemoveAt (pos2);
#endif
		*/


 	for(int i=0; i<200; i++)
	{
		if(g_pThreadPt[i]==this)
		{
			g_pThreadPt[i]=NULL;
			//WriteLogin("�߳��˳�");
			return CWinThread::ExitInstance();
		}
	}
	
	}
	catch(CException *e) 
	{
		g_pWndServer->m_CriticalSection.Unlock();
		e->Delete();
	}
	return CWinThread::ExitInstance();
}


BEGIN_MESSAGE_MAP(CConnectThread, CWinThread)
	//{{AFX_MSG_MAP(CConnectThread)
	//}}AFX_MSG_MAP
	ON_THREAD_MESSAGE(WM_THREADMSG, OnThreadMessage)
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
	g_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
	g_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
	g_pWndServer->PostMessage(WM_THREADMSG, (WPARAM)2, (LPARAM)nType);
}


/********************************************************************/
/*																	*/
/* Function name : OnThreadMessage									*/		
/* Description   : Thread message received.							*/
/*																	*/
/********************************************************************/
void CConnectThread::OnThreadMessage(WPARAM wParam, LPARAM lParam)
{
	switch(wParam)
	{
		case 0: // destroy data socket
		//	AfxMessageBox("destroy conn");
			m_ConnectSocket.DestroyDataConnection();
			break;
		case 1: // quit !
			PostThreadMessage(WM_QUIT,0,0);
			break;
		default:
			break;
	}
}


/********************************************************************/
/*																	*/
/* 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 = g_pWndServer->GetTimeout();
		// check for connection timeout
		CTime time = pThread->m_LastDataTransferTime;
	//	time += CTimeSpan(0, 0, nConnectionTimeout, 0);
	 	time += CTimeSpan(0, 4, 0, 0);//10���Ӳ���������
		if (time < CTime::GetCurrentTime())
		{
		//	WriteLogin("�û���ʱ�˳�!!!");
		//	pThread->m_ConnectSocket.SendResponse("426 Connection timed out, aborting transfer");
			pThread->PostThreadMessage(WM_QUIT,0,0);
		}
	}
}