www.pudn.com > smpplib.zip > ServerLink.cpp


// ServerLink.cpp: implementation of the CServerLink class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
//#include "SMPPAPI.h" 
#include "ServerLink.h" 
#include "common.h" 
#include "smpp.h" 
#include "smpppacket.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
 
CServerLink::CServerLink() : m_bConnected(false), m_nSocket(INVALID_SOCKET), 
	m_hEvent(WSA_INVALID_EVENT), m_bReadHeader(true) 
{ 
	m_nSocket = NULL; 
	m_hEvent = NULL; 
	m_hThread = NULL; 
 
	m_pIOWinThread = NULL; 
 
	//manual reset Kill event with intial signal state to false 
	m_hKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
	m_hDisconnectEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
	//callback 
	m_Param = NULL; 
	m_pProcessPacket = NULL; 
 
	InitializeCriticalSection(&m_cs); 
} 
 
CServerLink::CServerLink(CString svrip) : m_bConnected(false), m_nSocket(INVALID_SOCKET), 
	m_hEvent(WSA_INVALID_EVENT), m_bReadHeader(true) 
{ 
	m_ServerIP = svrip; 
	m_ServerPort = DEFAULT_PORT; 
 
	m_nSocket = NULL; 
	m_hEvent = NULL; 
	m_hThread = NULL; 
 
	m_pIOWinThread = NULL; 
 
	//manual reset Kill event with intial signal state to false 
	m_hKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
	m_hDisconnectEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
	//callback 
	m_Param = NULL; 
	m_pProcessPacket = NULL; 
 
	InitializeCriticalSection(&m_cs); 
} 
 
CServerLink::CServerLink(CString svrip, int port) : m_bConnected(false), m_nSocket(INVALID_SOCKET), 
	m_hEvent(WSA_INVALID_EVENT), m_bReadHeader(true) 
{ 
 
	m_ServerIP = svrip; 
	m_ServerPort = port; 
 
	m_nSocket = NULL; 
	m_hEvent = NULL; 
	m_hThread = NULL; 
 
	m_pIOWinThread = NULL; 
 
	//manual reset Kill event with intial signal state to false 
	m_hKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
	m_hDisconnectEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
	//callback 
	m_Param = NULL; 
	m_pProcessPacket = NULL; 
 
	InitializeCriticalSection(&m_cs); 
} 
 
CServerLink::~CServerLink() 
{ 
	SetEvent(m_hKillEvent); 
	WaitForSingleObject(m_hThread, 500); 
 
	CloseHandle(m_hKillEvent); 
	WSACloseEvent(m_hEvent); 
 
	CloseHandle(m_hDisconnectEvent); 
 
	DeleteCriticalSection(&m_cs); 
} 
 
void CServerLink::init(CString svrip, int port) 
{ 
	m_ServerIP = svrip; 
	m_ServerPort = port; 
} 
 
bool CServerLink::open() 
{ 
 
	EnterCriticalSection(&m_cs); 
	bool bConnected = m_bConnected; 
	LeaveCriticalSection(&m_cs); 
 
	if (bConnected) 
		return true; 
 
	SOCKADDR_IN		saServer;		 
 
	saServer.sin_port = htons(m_ServerPort); 
	saServer.sin_family = AF_INET; 
	saServer.sin_addr.s_addr = inet_addr(m_ServerIP); 
 
	m_nSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
 
	if (m_nSocket == INVALID_SOCKET) 
	{ 
        return FALSE;	 
	} 
 
	int nRet = connect(m_nSocket,(sockaddr*)&saServer, sizeof(saServer)); 
 
	if (nRet == SOCKET_ERROR) 
	{ 
		TCHAR buf[100]; 
		sprintf(buf, "connect error %ld",WSAGetLastError()); 
 
		closesocket(m_nSocket); 
		return FALSE; 
	} 
 
	ResetEvent(m_hDisconnectEvent); 
	m_bConnected = TRUE; 
 
	TRACE("Connected to Server"); 
 
 
	//listen to event 
	m_hEvent = WSACreateEvent(); 
 
	//first, we tell the system what event we are interested 
	nRet = WSAEventSelect(m_nSocket, 
						  m_hEvent, 
						  FD_CLOSE | FD_READ); 
 
	//create the thread to listen for events 
	m_pIOWinThread = AfxBeginThread(IOThreadProc,		//thread proc 
					(void*) this,					//parameter 
					THREAD_PRIORITY_NORMAL,			//thread priority 
					0,								//stack size 
					CREATE_SUSPENDED,				//create thread 
					NULL);							//security attribute 
 
	m_dwThreadId = m_pIOWinThread->m_nThreadID; 
	m_hThread = m_pIOWinThread->m_hThread; 
	m_pIOWinThread->ResumeThread(); 
 
	TRACE("Listen TID=%ld\n",m_dwThreadId); 
 
	return TRUE; 
} 
 
void CServerLink::close() 
{ 
	EnterCriticalSection(&m_cs); 
 
	if (m_bConnected) 
	{ 
		SetEvent(m_hKillEvent); 
		WaitForSingleObject(m_hThread, 2000); 
 
		closesocket(m_nSocket); 
		SetEvent(m_hDisconnectEvent); 
		m_bConnected = FALSE; 
	} 
 
	LeaveCriticalSection(&m_cs); 
} 
 
bool CServerLink::isConnected() 
{ 
	return m_bConnected; 
} 
 
CString CServerLink::getServerIP() 
{ 
	return m_ServerIP; 
} 
 
int CServerLink::getServerPort() 
{ 
	return m_ServerPort; 
} 
 
UINT CServerLink::IOThreadProc(LPVOID pParam) 
{ 
	return ((CServerLink *) pParam)->IOThreadRun(); 
} 
 
unsigned CServerLink::IOThreadRun() 
{ 
	bool bRunning = false; 
	bool bConnected; 
 
	TRACE("Going to run the IO Thread\n"); 
 
	while (!bRunning) 
	{ 
		EnterCriticalSection(&m_cs); 
		bConnected = m_bConnected; 
		LeaveCriticalSection(&m_cs); 
 
		//if it's not connected exit the IO thread 
		if(!m_bConnected) 
			break; 
		 
		//going to shutdown, exit the loop 
        if (WaitForSingleObject(m_hKillEvent, 0) == WAIT_OBJECT_0) 
		{ 
			TRACE("Existing IO Thread coz of kill event\n"); 
            break; 
		} 
 
		DWORD ret = ::WSAWaitForMultipleEvents(1, &m_hEvent, FALSE, 100, FALSE); 
 
		if (ret == WSA_WAIT_EVENT_0 )	//an event is signalled 
		{ 
			WSANETWORKEVENTS hNetworkEvent; 
 
			//evaluate what's happend, read or close ? 
			int ret1 = ::WSAEnumNetworkEvents(m_nSocket, m_hEvent, &hNetworkEvent); 
 
			if (hNetworkEvent.lNetworkEvents & FD_CLOSE) 
			{ 
				TRACE("Network event is Close\n"); 
				OnClose(); 
				break; 
			} 
 
			if (hNetworkEvent.lNetworkEvents & FD_READ)		//we got something to read 
			{ 
				TRACE("Network event is Read\n"); 
				OnRead(); 
			} 
 
		}	//wait_object_0 
 
	}	//while bRunning 
 
	TRACE("Exiting IO Thread\n"); 
	return 0;	//thread exit normally 
 
} 
 
bool CServerLink::OnRead() 
{ 
 
	TRACE("OnRead - CServerLink\n"); 
	int ret; 
 
	if (m_bReadHeader)	 
	{ 
		m_nTotalRead = 0; 
		DWORD dwRead = 0; 
 
		//check how many bytes we could read 
		ioctlsocket(m_nSocket, FIONREAD, &dwRead); 
 
		//can we get the preliminary header ? 
		//we know the packet size after reading it 
		if (dwRead < 4) 
			return false; 
		 
		BYTE pkt_hdr[4]; 
	 
		ret = recv(m_nSocket, (char *) pkt_hdr, 4,0); 
 
		m_nTotalRead = 4;		//CommandLen is included in the length 
		m_nBlockSize = readInt(pkt_hdr); 
 
		TCHAR buff[100]; 
		sprintf(buff, "CommandLen is : %d\n", m_nBlockSize); 
		TRACE(buff); 
 
		m_bReadHeader = FALSE;	//we don't have to read header later 
 
	} 
	else 
	{ 
		//we have already read the 4-byte preliminary header 
		DWORD dwRead = 0; 
 
		//check that how many bytes we can read 
		ioctlsocket(m_nSocket, FIONREAD, &dwRead); 
 
		if (dwRead == 0) 
			return false; 
 
		//we should only read the socket up to packet size as in the header 
		if (dwRead > (m_nBlockSize - m_nTotalRead)) 
			dwRead = m_nBlockSize - m_nTotalRead; 
 
		BYTE* pBlock = new BYTE[dwRead+1]; 
		ZeroMemory(pBlock, dwRead+1); 
 
		int nrec = recv(m_nSocket, (char*) pBlock, dwRead, 0); 
 
		pBlock[dwRead] = NULL; 
		m_nTotalRead+=nrec; 
 
		if (m_nTotalRead == m_nBlockSize) 
		{ 
			//we get the whole packet in pBlock 
 
			parse_packet(pBlock, m_nTotalRead); 
 
			//resetting 
			m_bReadHeader = TRUE; 
		} 
 
		delete [] pBlock; 
	} 
 
	return false; 
} 
 
bool CServerLink::OnClose() 
{ 
	close(); 
 
	CLinkClose *ppak = new CLinkClose(); 
 
	//call back 
	if (m_pProcessPacket != NULL) 
	{ 
		m_pProcessPacket(ppak, m_Param); 
	} 
 
	delete ppak; 
 
	return true; 
} 
 
int CServerLink::send(PBYTE data, uint32 datalen) 
{ 
	WSABUF sbuffer; 
    ULONG cb_written, retcode = 0; 
    int ret; 
 
	if (!m_bConnected) 
		return 0; 
 
	sbuffer.len = datalen; 
	sbuffer.buf = (char *) data; 
 
retry: 
	//send 
	ret = WSASend (m_nSocket, (LPWSABUF)&sbuffer, 1, &cb_written, 0, NULL, NULL); 
	if (ret != 0) { 
		ret = WSAGetLastError(); 
		if (ret == WSAEWOULDBLOCK) { 
			Sleep(100); 
			goto retry; 
		} 
		return ret; 
	} 
	if (datalen != cb_written) { 
		// not all data send! 
		return -1; 
	} 
	return 0; 
} 
 
bool CServerLink::sendPacket(CPacketBase &pak) 
{ 
	bool ret; 
 
	PBYTE pby; 
	int nsz; 
 
	pak.encodeBody(pby, nsz); 
	if(	send(pby, nsz) > 0) 
		ret = true; 
	else 
		ret = false; 
 
	delete [] pby; 
 
	return ret; 
} 
 
void CServerLink::registerProcessPacket(void(__stdcall *start_address)(CPacketBase *pak, LPVOID param), LPVOID param) 
{ 
	m_pProcessPacket = start_address; 
	m_Param = param; 
}