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