Exemplo n.º 1
0
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;
}