// ThreadedSocket.cpp: implementation of the CThreadedSocket class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "ThreadedSocket.h" // Class CThreadedSocketException //IMPLEMENT_DYNAMIC(CThreadedSocketException, CException) CThreadedSocketException::CThreadedSocketException(char* pchMessage) { m_strMessage = pchMessage; m_nError = WSAGetLastError(); } bool CThreadedSocketException::GetErrorMessage(string & lpstrError, UINT nMaxError, PUINT pnHelpContext /*= NULL*/) { lpstrError = m_strMessage; lpstrError += "error"; if(m_nError != 0) { lpstrError += " #"; lpstrError += m_nError; } return true; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CThreadedSocket::CThreadedSocket() { m_hSocket = INVALID_SOCKET; h_thread = NULL; // Create events to wait on // for receivier part m_hEvent[0] = WSACreateEvent(); if ( m_hEvent[0] == WSA_INVALID_EVENT ) { TRACE( "CThreadedSocketException(WSACreateEvent )\n"); throw( new CThreadedSocketException( "WSACreateEvent" )); } // for transmitter part m_hEvent[1] = WSACreateEvent(); if ( m_hEvent[1] == WSA_INVALID_EVENT ) { TRACE( "CThreadedSocketException(WSACreateEvent )\n"); throw( new CThreadedSocketException( "WSACreateEvent" )); } } CThreadedSocket::~CThreadedSocket() { if (m_hSocket != INVALID_SOCKET) Close(); //if ( thread ) // On fait de l'auto delete mais dans le cas de terminaison anormale l'object reste ????!!! // delete thread; WSACloseEvent( m_hEvent[0] ); WSACloseEvent( m_hEvent[1] ); } void CThreadedSocket::Create(UINT nSocketPort, int nSocketType, long lEvent, const char * lpszSocketAddress) { Socket(nSocketType, lEvent); Bind(nSocketPort,lpszSocketAddress); } ///////////////////////////////////////////////////////////////////////////// // CThreadedSocket Attributes void CThreadedSocket::GetPeerName(string & rPeerAddress, UINT& rPeerPort) { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); rPeerPort = ntohs(sockAddr.sin_port); rPeerAddress = inet_ntoa(sockAddr.sin_addr); } void CThreadedSocket::GetSockName(string & rSocketAddress, UINT& rSocketPort) { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen); rSocketPort = ntohs(sockAddr.sin_port); rSocketAddress = inet_ntoa(sockAddr.sin_addr); } ///////////////////////////////////////////////////////////////////////////// // CAscynSocket Operations void CThreadedSocket::Accept(CThreadedSocket& rConnectedSocket, SOCKADDR* lpSockAddr, int* lpSockAddrLen) { assert(rConnectedSocket.m_hSocket == INVALID_SOCKET); SOCKET hTemp = accept(m_hSocket, lpSockAddr, lpSockAddrLen); if (hTemp == INVALID_SOCKET) { rConnectedSocket.m_hSocket = INVALID_SOCKET; throw( new CThreadedSocketException( "accept" ) ); } else { rConnectedSocket.m_hSocket = hTemp; rConnectedSocket.StartListener(m_EventMask); } } void CThreadedSocket::Bind(UINT nSocketPort, const char * lpszSocketAddress) { SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); sockAddr.sin_family = AF_INET; if (lpszSocketAddress == NULL) sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); else { DWORD lResult = inet_addr(lpszSocketAddress); if (lResult == INADDR_NONE) { WSASetLastError(WSAEINVAL); throw( new CThreadedSocketException( "bind" ) ); } sockAddr.sin_addr.s_addr = lResult; } sockAddr.sin_port = htons((u_short)nSocketPort); Bind((SOCKADDR*)&sockAddr, sizeof(sockAddr)); } void CThreadedSocket::Close() { if (m_hSocket != INVALID_SOCKET) { AsyncSelect(0); assert(SOCKET_ERROR != closesocket(m_hSocket)); m_hSocket = INVALID_SOCKET; //WSASetEvent( m_hEventObject ); } } bool CThreadedSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen) { if ( !connect(m_hSocket, lpSockAddr, nSockAddrLen) ) { DWORD err = WSAGetLastError(); if ( err == 0 ) return TRUE; TRACE( "***************************************Error connect %d\n", err); if ( err != WSAEWOULDBLOCK ) return FALSE; // Wait for connection to complete TRACE( "***************************************Waiting for connection to complete\n"); err = WSAWaitForMultipleEvents( 1, m_hEvent, FALSE, WSA_INFINITE, TRUE); //TRACE( "Thread socket %d wait return %d\n", m_hSocket, err ); if ( err == WSA_WAIT_FAILED ) { return FALSE; } return TRUE; } return TRUE; } bool CThreadedSocket::Connect(const char * lpszHostAddress, UINT nHostPort) { assert(lpszHostAddress != NULL); SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr(lpszHostAddress); if (sockAddr.sin_addr.s_addr == INADDR_NONE) { LPHOSTENT lphost; lphost = gethostbyname(lpszHostAddress); if (lphost != NULL) sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; else { WSASetLastError(WSAEINVAL); return FALSE; } } sockAddr.sin_port = htons((u_short)nHostPort); return Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr)); } int CThreadedSocket::Receive(void* lpBuf, int nBufLen, int nFlags) { int lg = recv(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags); if ( lg == SOCKET_ERROR ) throw( new CThreadedSocketException( "recv" ) ); return lg; } int CThreadedSocket::ReceiveFrom(void* lpBuf, int nBufLen, string & rSocketAddress, UINT& rSocketPort, int nFlags) { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); int nResult = ReceiveFrom(lpBuf, nBufLen, (SOCKADDR*)&sockAddr, &nSockAddrLen, nFlags); rSocketPort = ntohs(sockAddr.sin_port); rSocketAddress = inet_ntoa(sockAddr.sin_addr); return nResult; } void CThreadedSocket::Send(const void* lpBuf, int nBufLen, int nFlags) { if ( send(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags) != nBufLen ) throw( new CThreadedSocketException( "send" ) ); } void CThreadedSocket::SendTo(const void* lpBuf, int nBufLen, UINT nHostPort, const char * lpszHostAddress, int nFlags) { SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); sockAddr.sin_family = AF_INET; if (lpszHostAddress == NULL) sockAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); else { sockAddr.sin_addr.s_addr = inet_addr(lpszHostAddress); if (sockAddr.sin_addr.s_addr == INADDR_NONE) { LPHOSTENT lphost; lphost = gethostbyname(lpszHostAddress); if (lphost != NULL) sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; else { WSASetLastError(WSAEINVAL); throw( new CThreadedSocketException( "SendTo" )); return; } } } sockAddr.sin_port = htons((u_short)nHostPort); SendTo(lpBuf, nBufLen, (SOCKADDR*)&sockAddr, sizeof(sockAddr), nFlags); } void CThreadedSocket::AddMember( const char * lpszHostAddress ) { int multicast_ttl = 64; // region struct ip_mreq imr; TRACE("CThreadedSocket::AddMember adding %s\n", lpszHostAddress ); imr.imr_multiaddr.s_addr = INADDR_ANY; imr.imr_interface.s_addr = INADDR_ANY; if (lpszHostAddress ) { imr.imr_multiaddr.s_addr = inet_addr(lpszHostAddress); if (imr.imr_multiaddr.s_addr == INADDR_NONE) { LPHOSTENT lphost; lphost = gethostbyname(lpszHostAddress); if (lphost != NULL) imr.imr_multiaddr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; else { WSASetLastError(WSAEINVAL); throw( new CThreadedSocketException( "AddMenber" )); return; } } } if ( IN_CLASSD( htonl(imr.imr_multiaddr.s_addr) ) ) { SetSockOpt( IP_MULTICAST_TTL, &multicast_ttl, sizeof( multicast_ttl ), IPPROTO_IP ); SetSockOpt( IP_ADD_MEMBERSHIP, &imr, sizeof( imr ), IPPROTO_IP ); } } void CThreadedSocket::AsyncSelect(long lEvent) { assert(m_hSocket != INVALID_SOCKET); if ( WSAEventSelect(m_hSocket, m_hEvent[0], lEvent) ) throw( new CThreadedSocketException( "WSAEventSelect" )); } ///////////////////////////////////////////////////////////////////////////// // CThreadedSocket Overridable callbacks void CThreadedSocket::OnWakeup() { } void CThreadedSocket::OnReceive(int /*nErrorCode*/) { } void CThreadedSocket::OnSend(int /*nErrorCode*/) { } void CThreadedSocket::OnOutOfBandData(int /*nErrorCode*/) { } void CThreadedSocket::OnAccept(int /*nErrorCode*/) { } void CThreadedSocket::OnConnect(int /*nErrorCode*/) { } void CThreadedSocket::OnClose(int /*nErrorCode*/) { } ///////////////////////////////////////////////////////////////////////////// // CThreadedSocket Implementation void CThreadedSocket::Socket(int nSocketType, long lEvent, int nProtocolType, int nAddressFormat) { assert(m_hSocket == INVALID_SOCKET); m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType); // m_hSocket = WSASocket ( nAddressFormat, nSocketType,nProtocolType, NULL, 0, 0 ); if (m_hSocket == INVALID_SOCKET) { throw( new CThreadedSocketException( "socket" )); } StartListener(lEvent); } void CThreadedSocket::StartListener(long lEvent) { m_EventMask = lEvent; h_thread = CreateThread(NULL,0,SocketThreadProc, this, 0, &thread_id); if ( ! h_thread ) throw( new CThreadedSocketException( "socket listener" )); } // Implementation DWORD WINAPI CThreadedSocket::SocketThreadProc( LPVOID pParam ) { CThreadedSocket* pObject = (CThreadedSocket*)pParam; if (pObject == NULL ) { throw( new CThreadedSocketException( "bad socket proc" )); return -1; // if pObject is not valid } return pObject->SocketThread(); } UINT CThreadedSocket::SocketThread( ) { DWORD err; WSANETWORKEVENTS NetworkEvents; AsyncSelect(m_EventMask) ; while ( m_hSocket != INVALID_SOCKET ) { err = WSAWaitForMultipleEvents( 2, m_hEvent, FALSE, WSA_INFINITE, TRUE); switch ( err ) { case WSA_WAIT_FAILED: TRACE( "CThreadedSocketException(WSAWaitForMultipleEvents )\n"); throw( new CThreadedSocketException( "WSAWaitForMultipleEvents" )); return err; break; case WSA_WAIT_EVENT_0: NetworkEvents.lNetworkEvents=0; if ( WSAEnumNetworkEvents ( m_hSocket, m_hEvent[0], &NetworkEvents )) { TRACE( "CThreadedSocketException(WSAEnumNetworkEvents )\n"); throw( new CThreadedSocketException( "WSAEnumNetworkEvents" )); return -1; } if ( NetworkEvents.lNetworkEvents & FD_READ ) OnReceive(NetworkEvents.iErrorCode[ FD_READ_BIT ]); if ( NetworkEvents.lNetworkEvents & FD_WRITE ) OnSend( NetworkEvents.iErrorCode[ FD_WRITE_BIT ] ); if ( NetworkEvents.lNetworkEvents & FD_ACCEPT ) OnAccept( NetworkEvents.iErrorCode[ FD_ACCEPT_BIT ] ); if ( NetworkEvents.lNetworkEvents & FD_CONNECT ) OnConnect( NetworkEvents.iErrorCode[ FD_CONNECT_BIT ] ); if ( NetworkEvents.lNetworkEvents & FD_OOB ) OnOutOfBandData( NetworkEvents.iErrorCode[ FD_OOB_BIT ] ); if ( NetworkEvents.lNetworkEvents & FD_CLOSE ) { OnClose( NetworkEvents.iErrorCode[ FD_CLOSE_BIT ] ); } break; case WSA_WAIT_EVENT_0 +1 : if ( m_hSocket != INVALID_SOCKET ) { OnWakeup(); } // else Close by other Thread do silent terminaison WSAResetEvent( m_hEvent[1] ); break; default: TRACE( "CThreadedSocket::SocketThread Unhandled Events !\n"); break; } } Close(); h_thread = NULL; return 0; }