www.pudn.com > zfxcengine-0.1.0.zip > ceNetworkSocket.cpp


/* $Id: ceNetworkSocket.cpp,v 1.3 2005/06/06 09:14:38 jubu Exp $ */ 
///////////////////////////////////////////////////////////////// 
// 
// 	Module:		Network 
//	File:		ceNetworkSocket.cpp 
//	Author:		Johannes Schickel 
//  (c):		2003 by Johannes Schickel ( 14.12.2003 ) 
// 
//!	\brief		Die Sourcedatei für die ceSocket Klasse 
// 
//  Last Change:    Mo Jun  6 08:39:53 CEST 2005 jubu 
// 
//	TODO:		Nichts 
//	BUGS:		Keine Bekannten 
// 
///////////////////////////////////////////////////////////////// 
 
// Includes 
#include  
#include  
#include  
#include  
 
#ifdef WIN32 
#include "winsock2.h" 
//#include "Wspiapi.h" 
#include "Ws2tcpip.h" 
#endif 
 
#include "Core/ceDebug.h" 
#include "Core/ceExceptions.h" 
#include "Network/ceNetwork.h" 
#include "Network/ceNetworkSocket.h" 
#include "Core/ceMemManager.h" 
 
namespace ZFXCE { 
namespace Network { 
	//////////////////////////////////////////////////////////////////////////////// 
	ceSocket::ceSocket(void) : m_soSocket(INVALID_SOCKET), m_iMode(SM_NONE), m_iPort(0), m_xType(NT_UNSPEC) 
	{ 
		PUSH_FUNCTION 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	ceSocket::~ceSocket(void) 
	{ 
		PUSH_FUNCTION 
 
		m_soSocket = INVALID_SOCKET; 
		m_iPort = 0; 
		m_iMode = SM_NONE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	// creating a socket 
	int ceSocket::iCreate(ceNetworkType p_xType) 
	{ 
		PUSH_FUNCTION 
#ifdef WIN32 
		static BOOL bInit=FALSE; 
		if(bInit==FALSE) 
		{ 
			WSADATA wsaData; 
			int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); 
			if ( iResult != NO_ERROR ) 
				printf("Error at WSAStartup()\n"); 
			bInit = TRUE; 
		} 
#endif 
 
		switch(p_xType) { 
		case NT_TCP : 
			// creating TCP-Socket 
			m_soSocket = socket(PF_DEFAULT, SOCK_STREAM, 0); 
			break; 
		case NT_UDP : 
			// creating UDP-Socket 
			m_soSocket = socket(PF_DEFAULT, SOCK_DGRAM, 0); 
			break; 
		default: 
			return false; 
		} 
		m_xType = p_xType; 
 
		if (m_soSocket == INVALID_SOCKET) 
		{ 
			cout << "Invalider Socket!" << endl; 
			return FALSE; 
		} 
 
		// remember the Socket is correct initialized 
		m_iMode |= SM_INIT; 
 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	// Bind Socket to an interface and port 
	// use p_lpcDeviceIP= "0.0.0.0" to bind on all available interfaces 
	// TODO: it should be possible to use a service name instead 
	// of the portnumber 
	int ceSocket::iBind(INT p_iPort, const CHAR* p_lpcDeviceIP) 
	{ 
		PUSH_FUNCTION 
 
		// check if Socket is correct initialized 
		if (!(m_iMode & SM_INIT)) 
			return FALSE; 
 
		addrinfo hints; 
		memset(&hints, 0, sizeof(hints)); 
 
		hints.ai_family = PF_DEFAULT; 
 
		switch (m_xType) { 
			case NT_TCP: 
				hints.ai_socktype = SOCK_STREAM; 
				break; 
			case NT_UDP: 
				hints.ai_socktype = SOCK_DGRAM; 
				break; 
			default: 
				CE_EXCEPTION("Unsupported socket type.", CELS_LOWERROR); 
		} 
 
		if((p_iPort <= 0) || (p_iPort > 0xFFFF)) 
		{ 
				CE_EXCEPTION("Bad Portnumber", CELS_LOWERROR); 
		} 
		char szBuf[10]; 
		snprintf(szBuf, 10, "%5d", p_iPort); 
 
		addrinfo *res = NULL; 
 
		int error = 0; 
		if ((error = getaddrinfo(p_lpcDeviceIP, szBuf, &hints, &res)) != 0) 
		{ 
			return FALSE; 
		} 
 
		// try any address which corresponds to p_lpcDeviceIP 
		// We stop if we find one usable 
		// XXX Is this realy correct? 
 
		addrinfo *p = res; 
		while (p != NULL && ((error = bind(m_soSocket, p->ai_addr, p->ai_addrlen)) == SOCKET_ERROR)) 
		{ 
			p = p->ai_next; 
		} 
 
		freeaddrinfo(res); 
 
		if (error != SOCKET_ERROR) 
		{ 
			// remember socket is bound 
			m_iMode |= SM_BIND; 
 
			// remember the portnumber 
			m_iPort = p_iPort; 
 
			return TRUE; 
		} else { 
			return FALSE; 
		} 
	}// ceSocket::iBind 
	//////////////////////////////////////////////////////////////////////////////// 
	INT ceSocket::iDelete(void) 
	{ 
		PUSH_FUNCTION 
 
		// check if socket is valid 
		if (m_iMode & SM_INIT) { 
			// in case of linux/unix closesocket defined as close 
			closesocket(m_soSocket); 
 
			m_iMode = SM_NONE; 
 
			// remember socket in invalid 
			m_soSocket = INVALID_SOCKET; 
		} 
		return TRUE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
    // send some data. To avoid blocking, the filedescripter m_soSocket 
	// should be checked with select or poll if it's possible 
	// to send data. It is not assured that all data will be sent. 
	// The number of Bytes which are sent will be the return value. 
 
	INT ceSocket::iSend(const char* p_lpvData, INT p_iSize) 
	{ 
		PUSH_FUNCTION 
		return send(m_soSocket, (const char*) p_lpvData, p_iSize, 0); 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	// read some data. To avoid blocking, the filedescripter m_soSocket 
	// should be checked with select or poll if it's possible 
	// to read data. 
	// The number of Bytes which are read will be the return value. 
	INT ceSocket::iReceive(char* p_lpvBuffer, INT p_iBuffersize) 
	{ 
		PUSH_FUNCTION 
		return recv(m_soSocket, (CHAR*) p_lpvBuffer, p_iBuffersize, 0); 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	// connectet 
	INT ceSocket::iConnect(const CHAR *p_lpcServer, INT p_iPort) 
	{ 
		PUSH_FUNCTION 
 
		cout << "iConnect m_iMode=" < 0xFFFF)) 
		{ 
				cout << p_iPort << endl; 
				CE_EXCEPTION("Bad Portnumber", CELS_LOWERROR); 
		} 
		char szBuf[10]; 
		snprintf(szBuf, 10, "%5d", p_iPort); 
 
		addrinfo *res = NULL; 
 
		int error = 0; 
		if ((error = getaddrinfo(p_lpcServer, szBuf, &hints, &res)) != 0) 
		{ 
			return FALSE; 
		} 
 
		// Jetzt wird connectet 
		addrinfo *p = res; 
		while (p != NULL && (error = connect(m_soSocket, p->ai_addr, p->ai_addrlen)) == SOCKET_ERROR) 
		{ 
			p = p->ai_next; 
		} 
 
		freeaddrinfo(res); 
 
		if (error != SOCKET_ERROR) 
		{ 
			// remember the socket is connected 
			m_iMode |= SM_CONNECTED; 
 
			m_iPort = p_iPort; 
			return TRUE; 
		} else { 
			return FALSE; 
		} 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	// listen starts listening for incomming conections 
	// maxSocketsWaitingToBeAccepted is the maximal number of 
	// completely established sockets waiting to  be  accepted. 
	// The semantic changed in linux kernel 2.2 
	void ceSocket::iListen(int maxSocketsWaitingToBeAccepted) 
	{ 
		PUSH_FUNCTION 
 
		int retcode = listen( m_soSocket , maxSocketsWaitingToBeAccepted ); 
		if(retcode){ 
			CE_EXCEPTION("Listen failed", CELS_ERROR); 
		} 
		if(maxSocketsWaitingToBeAccepted){ 
			m_iMode |= SM_LISTEN; 
		} else { 
			m_iMode &= ~SM_LISTEN; 
		} 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	// accept extracts the first connection request on the queue of pending connections. 
	// To avoid blocking, the filedescripter m_soSocket 
	// should be checked with select or poll if it's possible 
	// to read data. 
	// The new sockect ist returned in p_lpxSocket 
	// The remote address ist stored in p_lpcIP 
 
	INT ceSocket::iAccept(ceSocket* p_lpxSocket, CHAR *p_lpcIP, size_t& n_lpcIP) 
	{ 
		PUSH_FUNCTION 
 
		if ((m_iMode & SM_CONNECTED) || !(m_iMode & SM_LISTEN)) 
			return FALSE; 
 
		if (p_lpxSocket->m_iMode & SM_INIT) 
			return FALSE; 
 
#ifdef IPV6 
		sockaddr_in6 saiAddress; 
#else 
		sockaddr_in saiAddress; 
#endif 
 
#ifdef WIN32 
		INT iSize = sizeof(saiAddress); 
#else 
		socklen_t iSize = sizeof(saiAddress); 
#endif 
 
		memset(&saiAddress, 0, iSize); 
 
		p_lpxSocket->m_soSocket = accept(m_soSocket, (sockaddr*) &saiAddress, &iSize); 
 
		if (p_lpxSocket->m_soSocket == INVALID_SOCKET) 
			return FALSE; 
 
#ifdef WIN32 
		WSAAddressToString( (LPSOCKADDR) &saiAddress, iSize, NULL, p_lpcIP, (LPDWORD)&n_lpcIP); 
#else 
		strcpy( p_lpcIP, inet_ntop(reinterpret_cast(&saiAddress)->sa_family, 
#ifdef IPV6 
			&saiAddress.sin6_addr, 
#else 
			&saiAddress.sin_addr, 
#endif 
			p_lpcIP, n_lpcIP)); 
#endif 
 
		return TRUE; 
	} 
	INT ceSocket::iGetSocketFd(){ 
		return(m_soSocket); 
	} 
 
} // Namespace Network 
} // Namespace ZFXCE