void CSocketManager::OnDataReceived(const LPBYTE lpBuffer, DWORD dwCount) { LPBYTE lpData = lpBuffer; SockAddrIn origAddr; stMessageProxy msgProxy; if (IsSmartAddressing()) { dwCount = __min(sizeof(msgProxy), dwCount); memcpy(&msgProxy, lpBuffer, dwCount); origAddr = msgProxy.address; if (IsServer()) { // broadcast message to all msgProxy.address.sin_addr.s_addr = htonl(INADDR_BROADCAST); WriteComm((const LPBYTE)&msgProxy, dwCount, 0L); } dwCount -= sizeof(msgProxy.address); lpData = msgProxy.byData; } // Display data to message list DisplayData( lpData, dwCount, origAddr ); }
/////////////////////////////////////////////////////////////////////////////// // Run /////////////////////////////////////////////////////////////////////////////// // DESCRIPTION: // This function runs the main thread loop // this implementation can be overloaded. // This function calls CSocketComm::OnDataReceived() (Virtual Function) // PARAMETERS: // NOTES: // You should not wait on the thread to end in this function or overloads /////////////////////////////////////////////////////////////////////////////// void CSocketComm::Run() { stMessageProxy stMsgProxy; DWORD dwBytes = 0L; DWORD dwTimeout = INFINITE; LPBYTE lpData = (LPBYTE)&stMsgProxy; DWORD dwSize = sizeof(stMsgProxy); bool bSmartAddressing = IsSmartAddressing(); if ( !bSmartAddressing ) { lpData = stMsgProxy.byData; dwSize = sizeof(stMsgProxy.byData); } // Should we run as server mode if (IsServer() && !bSmartAddressing) { if (!IsBroadcast()) { SOCKET sock = (SOCKET) m_hComm; sock = WaitForConnection( sock ); // Get new connection socket if (sock != INVALID_SOCKET) { ShutdownConnection( (SOCKET) m_hComm); m_hComm = (HANDLE) sock; OnEvent( EVT_CONSUCCESS, NULL ); // connect } else { // Do not send event if we are closing if (IsOpen()) OnEvent( EVT_CONFAILURE, NULL ); // wait fail return; } } } else { GetPeerName( stMsgProxy.address ); } while( IsOpen() ) { // Blocking mode: Wait for event dwBytes = ReadComm(lpData, dwSize, dwTimeout); // Error? - need to signal error if (dwBytes == (DWORD)-1L) { // Do not send event if we are closing if (IsOpen()) { if ( bSmartAddressing ) { RemoveFromList( stMsgProxy.address ); } OnEvent( EVT_CONDROP, &stMsgProxy.address ); // lost connection } // special case for UDP, alert about the event but do not stop if ( bSmartAddressing ) continue; else break; } // Chars received? if ( bSmartAddressing && dwBytes == sizeof(SOCKADDR_IN)) { OnEvent( EVT_ZEROLENGTH, NULL ); } else if (dwBytes > 0L) { OnDataReceived( lpData, dwBytes); } //Sleep(0); } }
/////////////////////////////////////////////////////////////////////////////// // WriteComm /////////////////////////////////////////////////////////////////////////////// // DESCRIPTION: // Writes data to the Socket Communication // PARAMETERS: // const LPBYTE lpBuffer: data to write // DWORD dwCount: maximum characters to write // DWORD dwTimeout: timeout to use in millisecond /////////////////////////////////////////////////////////////////////////////// DWORD CSocketComm::WriteComm(const LPBYTE lpBuffer, DWORD dwCount, DWORD dwTimeout) { _ASSERTE( IsOpen() ); _ASSERTE( NULL != lpBuffer ); // Accept 0 bytes message if (!IsOpen() || NULL == lpBuffer) return 0L; fd_set fdWrite = { 0 }; TIMEVAL stTime; TIMEVAL *pstTime = NULL; if ( INFINITE != dwTimeout ) { stTime.tv_sec = dwTimeout/1000; stTime.tv_usec = (dwTimeout%1000)*1000; pstTime = &stTime; } SOCKET s = (SOCKET) m_hComm; // Set Descriptor if ( !FD_ISSET( s, &fdWrite ) ) FD_SET( s, &fdWrite ); // Select function set write timeout DWORD dwBytesWritten = 0L; int res = select( s+1, NULL, &fdWrite, NULL, pstTime ); if ( res > 0) { // Send message to peer or broadcast it bool bSmartAddressing = IsSmartAddressing(); if (IsBroadcast() || bSmartAddressing ) { // use offset for Smart addressing int nOffset = bSmartAddressing ? sizeof(SOCKADDR_IN) : 0; if (bSmartAddressing) { if ( dwCount < sizeof(SOCKADDR_IN)) // error - buffer to small { SetLastError( ERROR_INVALID_USER_BUFFER ); return -1L; } // read socket address from buffer SockAddrIn sockAddr; sockAddr.SetAddr((PSOCKADDR_IN) lpBuffer); // Get Address and send data if (sockAddr.sin_addr.s_addr != htonl(INADDR_BROADCAST)) { LPSTR lpszData = (LPSTR)(lpBuffer + nOffset); res = sendto( s, lpszData, dwCount-nOffset, 0, sockAddr, sockAddr.Size()); dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1)); return dwBytesWritten; } else { // NOTE: broadcast will broadcast only to our peers // Broadcast send to all connected-peers LockList(); // Lock this object addresses-list CSockAddrList::iterator iter = m_AddrList.begin(); for( ; iter != m_AddrList.end(); ) { // Fix v1.3 - nOffset was missing sockAddr = (*iter); res = sendto( s, (LPCSTR)&lpBuffer[nOffset], dwCount-nOffset, 0, sockAddr, iter->Size()); if (res < 0) { CSockAddrList::iterator deladdr = iter; ++iter; // get next m_AddrList.erase( deladdr ); } else ++iter; // get next } UnlockList(); // unlock this object addresses-list } } // always return success - UDP res = (int) dwCount - nOffset; } else // Send to peer-connection res = send( s, (LPCSTR)lpBuffer, dwCount, 0); } dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1L)); return dwBytesWritten; }
/////////////////////////////////////////////////////////////////////////////// // ReadComm /////////////////////////////////////////////////////////////////////////////// // DESCRIPTION: // Reads the Socket Communication // PARAMETERS: // LPBYTE lpBuffer: buffer to place new data // DWORD dwSize: maximum size of buffer // DWORD dwTimeout: timeout to use in millisecond /////////////////////////////////////////////////////////////////////////////// DWORD CSocketComm::ReadComm(LPBYTE lpBuffer, DWORD dwSize, DWORD dwTimeout) { _ASSERTE( IsOpen() ); _ASSERTE( lpBuffer != NULL ); if (lpBuffer == NULL || dwSize < 1L) return 0L; fd_set fdRead = { 0 }; TIMEVAL stTime; TIMEVAL *pstTime = NULL; if ( INFINITE != dwTimeout ) { stTime.tv_sec = dwTimeout/1000; stTime.tv_usec = (dwTimeout%1000)*1000; pstTime = &stTime; } SOCKET s = (SOCKET) m_hComm; // Set Descriptor if ( !FD_ISSET( s, &fdRead ) ) FD_SET( s, &fdRead ); // Select function set read timeout DWORD dwBytesRead = 0L; int res = select( s+1, &fdRead, NULL, NULL, pstTime ); if ( res > 0) { if (IsBroadcast() || IsSmartAddressing()) { SockAddrIn sockAddr; sockAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); int nLen = sockAddr.Size(); int nOffset = IsSmartAddressing() ? nLen : 0; // use offset for Smart addressing if ( dwSize < (DWORD) nOffset) // error - buffer to small { SetLastError( ERROR_INVALID_USER_BUFFER ); return -1L; } LPSTR lpszData = (LPSTR)(lpBuffer + nOffset); res = recvfrom( s, lpszData, dwSize-nOffset, 0, sockAddr, &nLen); // clear 'sin_zero', we will ignore them with 'SockAddrIn' anyway! memset(&sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); // Lock the list... LockList(); m_AddrList.remove( sockAddr ); if ( res >= 0) { // insert unique address m_AddrList.insert(m_AddrList.end(), sockAddr); if (IsSmartAddressing()) { memcpy(lpBuffer, &sockAddr, sockAddr.Size()); res += sockAddr.Size(); } } else if (WSAGetLastError() == WSAECONNRESET && m_AddrList.size() == 1) { // recvfrom doesn't always return the connection address for last connection m_AddrList.clear(); } UnlockList(); // unlock this object addresses-list } else { res = recv( s, (LPSTR)lpBuffer, dwSize, 0); } } dwBytesRead = (DWORD)((res > 0)?(res) : (-1L)); return dwBytesRead; }