--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hti/PC_Tools/HTIGateway/HtiGateway/src/HtiDispatcher.cpp Wed Oct 13 16:17:58 2010 +0300
@@ -0,0 +1,554 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+* This file contains implementation of HtiDispatcher class.
+*/
+
+#include "stdsoap2.h" //should be first because of WinSock2.h errors
+
+#include "common.h"
+#include "HtiDispatcher.h"
+#include "soapHandler.h"
+
+#include "HtiMessage.h"
+#include "util.h"
+#include <sstream>
+
+#include <crtdbg.h>
+
+const static char* HTI_PLUGIN_FOLDER = "ServicePlugins/";
+//used to redispatch hti framework error messages (like not authorized)
+
+/**
+* namespace table is needed to correclty send fault messages
+* each service plugin should explicitly set its one namespace table before processing
+* request
+*/
+SOAP_NMAC struct Namespace namespaces[] =
+{
+ {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},
+ {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},
+ {NULL, NULL, NULL, NULL}
+};
+
+//**********************************************************************************
+// Class HtiDispatcher
+//
+// This class
+// -forwards Soap requests and Hti messages to correct SOAPHandlers
+// -Is used to initiate SOAPHandlers by reading them from dll's and start them
+//**********************************************************************************
+HtiDispatcher::HtiDispatcher(SafeQueue<Data*>* qIn,
+ SafeQueue<Data*>* qOut)
+ : m_Running(true),
+ m_QueueIn(qIn),
+ m_QueueOut(qOut),
+ m_IncomingHtiMessage(NULL)
+{
+}
+
+HtiDispatcher::~HtiDispatcher()
+{
+ for( htiSoapActionHashMap::const_iterator i = m_SoapHandlers.begin();
+ i != m_SoapHandlers.end();
+ ++i)
+ {
+ delete i->second;
+ }
+}
+
+/**
+ * This method is used to read all the available SoapHandler dll's and initialize an instance of them and store a reference to m_SoapHandlers(by soap action)
+ * and m_HanlersUidMap(by service uid) maps.
+ */
+void HtiDispatcher::InitHandlers()
+{
+ Util::Info( "HtiDispatcher::InitHandlers" );
+ //1. read exe/plugin directory
+ WIN32_FIND_DATA FileData;
+ HANDLE hSearch;
+ bool fFinished = false;
+
+ // Start searching for .dll files
+ string searchMask = HTI_PLUGIN_FOLDER;
+ searchMask.append( "*.dll" );
+ hSearch = FindFirstFile( searchMask.c_str(), &FileData );
+ if (hSearch == INVALID_HANDLE_VALUE)
+ {
+ Util::Info("No DLLs found.");
+ return;
+ }
+
+ while (!fFinished)
+ {
+
+ //2. get list of all DLLs
+ //SoapHandler* t = new SoapHandler("ws_hti.dll");
+ string pluginPath = HTI_PLUGIN_FOLDER;
+ pluginPath.append( FileData.cFileName );
+ Util::Info("Try to load:");
+ Util::Info(pluginPath);
+ SoapHandler* t = new SoapHandler( pluginPath );
+ if( t->LoadPlugin() )
+ {
+ //3. add them to m_SoapHandlers
+ char* soapAction = t->soapAction();
+ m_SoapHandlers[ soapAction ] = t;
+ //add to uid map as well
+ int uid = t->serviceUID();
+ m_HanlersUidMap[ uid ] = t;
+
+ stringstream s;
+ s<<"Loaded plugin: ";
+ s<<soapAction;
+ s<<", service UID: ";
+ s<<uid;
+
+ Util::Info( s.str().c_str() );
+ }
+ else
+ {
+ delete t;
+ //
+ Util::Error("Failed load DLL as a plugin");
+ }
+
+ if (!FindNextFile(hSearch, &FileData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ {
+ fFinished = TRUE;
+ }
+ else
+ {
+ Util::Error("Couldn't find next plugin.");
+ fFinished = TRUE;
+ //return;
+ }
+ }
+ }
+
+ // Close the search handle.
+
+ FindClose(hSearch);
+
+ stringstream s;
+ s<<"Plugins loaded ";
+ s<<m_SoapHandlers.size();
+ Util::Info( s.str().c_str() );
+}
+
+/**
+ * This method is used to start all the SoapHandler instances that are stored in htiSoapActionHashMap
+ */
+void HtiDispatcher::StartHandlers()
+{
+ for( htiSoapActionHashMap::const_iterator i = m_SoapHandlers.begin();
+ i != m_SoapHandlers.end();
+ ++i)
+ {
+ (i->second)->SetDispatcher(this);
+ (i->second)->Start();
+ }
+}
+
+/*
+ * This loop is used to forward incoming Hti messages(arriving from CommChannelPlugin to m_QueueOut side) to correct SoapHandlers
+ */
+void HtiDispatcher::Run()
+{
+ Util::Debug("HtiDispatcher::Run");
+ //m_testHandler.SetDispatcher(this);
+ //m_testHandler.Start();
+ InitHandlers();
+ StartHandlers();
+
+ BYTE* shortData = NULL; //keep data if it's too short to have HtiHeader
+ //or if one Data msg have more than one HtiMessage
+ DWORD msgBufferSize = 8096;
+ BYTE* msgBuffer = (BYTE*)malloc( msgBufferSize );
+ DWORD shortDataLen = 0;
+
+ // By setting this threads priority below others will give soaphandler threads
+ // more runtime to process the received messages.. This is to avoid the situation
+ // where two messages arrive so close to each other that m_hReceiveHtiEvent is
+ // signalled twice before the first message has even been processed by the soap plugin.
+ if(!SetThreadPriority( ThreadHandle(), THREAD_PRIORITY_BELOW_NORMAL ))
+ Util::Info("Warning: Could not set HtiDispatcher priority!");
+
+ while (m_Running)
+ {
+ try
+ {
+ Data* d = m_QueueOut->front(50);
+ BYTE* p = (BYTE *)d->GetData();
+ DWORD l = d->GetLength();
+ //printf("\td = %d\n", m_QueueOut->size());
+
+ if (Util::GetVerboseLevel() == Util::VerboseLevel::debug)
+ {
+ char tmp[64];
+ sprintf(tmp, "[HtiDispatcher] HTI MsgSize = %d", l);
+ string s(tmp);
+ Util::Debug(s);
+ //Util::Hex(p, d->GetLength());
+ }
+
+ //Util::Debug("leftovers");
+ //copy leftovers to the beginning of the buffer
+ if ( shortDataLen > 0 )
+ {
+ memcpy( msgBuffer, shortData, shortDataLen );
+ }
+ shortData = msgBuffer; //set shortData to the beginning
+
+ //copy data to buffer
+ if ( shortDataLen + l > msgBufferSize )
+ {
+ msgBufferSize = shortDataLen + l;
+ msgBuffer = (BYTE*)realloc(msgBuffer, msgBufferSize);
+ shortData = msgBuffer;
+ }
+ //copy data gotten from queue to the end of shortData
+ memcpy(shortData + shortDataLen, p, l );
+ shortDataLen = l + shortDataLen;
+
+ while ( shortDataLen != 0 &&
+ (shortDataLen >= HtiMessage::MinHeaderSize() ||
+ m_IncomingHtiMessage != NULL ) )
+ {
+ //new message
+ if ( m_IncomingHtiMessage == NULL )
+ {
+ if ( shortDataLen >= HtiMessage::MinHeaderSize() )
+ {
+ if ( HtiMessage::CheckValidHtiHeader(shortData) )
+ {
+ m_IncomingHtiMessage = new HtiMessage( shortData, shortDataLen );
+
+ if (Util::GetVerboseLevel() == Util::VerboseLevel::debug)
+ {
+ char tmp[64];
+ sprintf(tmp,"New hti message %d", m_IncomingHtiMessage->HtiDataSize());
+ string s(tmp);
+ Util::Debug(s);
+ //Util::Hex(p, d->GetLength());
+ }
+
+ //_RPT2(_CRT_WARN, "income msg %x <%d>\n", m_IncomingHtiMessage, sizeof(HtiMessage));
+ //check message
+ if ( m_IncomingHtiMessage->IsMessageComplete() )
+ {
+ Util::Debug("HTI message complete");
+ DWORD msgSize = m_IncomingHtiMessage->HtiDataSize();
+ if ( msgSize < shortDataLen )
+ {
+ //remove used part
+ //BYTE* temp = new BYTE[shortDataLen-msgSize];
+ //_RPT2(_CRT_WARN, "temp %x <%d>\n", shortData , shortDataLen-msgSize);
+ //memcpy(temp, shortData + msgSize, shortDataLen-msgSize);
+ //_RPT1(_CRT_WARN, "del shortData %x\n", shortData);
+ //delete[] shortData;
+ //shortData = temp;
+ shortData += msgSize; //just move pointer
+ shortDataLen -= msgSize;
+
+ }
+ else
+ {
+ //_RPT1(_CRT_WARN, "del shortData %x\n", shortData);
+ //delete[] shortData;
+ //shortData = NULL;
+ shortDataLen = 0;
+ }
+ //Dispatch incoming message
+ DispatchToSoapHandlers();
+ }
+ else
+ {
+ //_RPT1(_CRT_WARN, "del shortData %x\n", shortData);
+ //delete[] shortData;
+ //shortData = NULL;
+ shortDataLen = 0;
+ }
+ }
+ else
+ {
+ //invalid header
+ Util::Error("Invalid HTI header, dismiss Data message");
+ Util::Hex(shortData, HtiMessage::MinHeaderSize() );
+ //_RPT1(_CRT_WARN, "del shortData %x\n", shortData);
+ //delete[] shortData;
+ //shortData = NULL;
+ shortDataLen = 0;
+ }
+ }
+ }
+ else //body parts
+ {
+ Util::Debug("add");
+ DWORD added = m_IncomingHtiMessage->AddToBody( shortData,
+ shortDataLen );
+ //printf("reminder %d\n", m_IncomingHtiMessage->Reminder());
+ if ( added < shortDataLen )
+ {
+ //only part of message was added
+ //remove added part
+ //BYTE* temp = new BYTE[shortDataLen-added];
+ //_RPT2(_CRT_WARN, "temp %x <%d>\n", shortData , shortDataLen-added);
+ //memcpy(temp, shortData + added, shortDataLen-added);
+ //_RPT1(_CRT_WARN, "del shortData %x\n", shortData );
+ //delete[] shortData;
+ //shortData = temp;
+ shortData += added;
+ shortDataLen -= added;
+ }
+ else //all data were added
+ {
+ //_RPT1(_CRT_WARN, "del shortData %x\n", shortData );
+ //delete[] shortData;
+ //shortData = NULL;
+ shortDataLen = 0;
+ }
+
+ if ( m_IncomingHtiMessage->IsMessageComplete() )
+ {
+ Util::Debug("HTI message complete");
+ //Dispatch incoming message
+ DispatchToSoapHandlers();
+ }
+ }
+ }
+
+ m_QueueOut->pop();
+ //_RPT1(_CRT_WARN, "del data %x\n", d);
+ delete d;
+ d = NULL;
+ } catch (TimeoutException te)
+ {
+ //Util::Debug("[DataGatewaySocketWriterThread]timeout exception");
+ }
+ }
+ free( msgBuffer );
+}
+
+/**
+ * This method is used to forward the incoming HTI message to correct SoapHandler
+ * The correct SoapHandler is found by service uid
+ */
+void HtiDispatcher::DispatchToSoapHandlers()
+{
+ htiUIDHashMap::const_iterator i;
+ int targetServiceUid;
+ if ( m_IncomingHtiMessage->IsErrorMessage() )
+ {
+ targetServiceUid = m_IncomingHtiMessage->ErrorServiceUid();
+
+ stringstream s;
+ s<<"Received HTI error message\nhtiErrorCode: ";
+ s<<m_IncomingHtiMessage->HtiErrorCode();
+ s<<"\nserviceUid: ";
+ s<<m_IncomingHtiMessage->ErrorServiceUid();
+ s<<"\nserviceErrorCode: ";
+ s<<m_IncomingHtiMessage->ServiceErrorCode();
+ s<<"\nErrorDescription: ";
+ s<<m_IncomingHtiMessage->ErrorDescription();
+ s<<"\ntargetServiceUid: ";
+ s<<targetServiceUid;
+
+ Util::Error(s.str().c_str());
+ }
+ else
+ {
+ targetServiceUid = m_IncomingHtiMessage->GetServiceUID();
+ }
+
+ if ( targetServiceUid == HTI_SYSTEM_SERVICE_UID &&
+ m_IncomingHtiMessage->IsErrorMessage() )
+ {
+ Util::Debug("dispatch error");
+ //if system plugin doesn't wait for a message then find plugin that
+ //is waiting for a message and delivery the incoming msg to it
+ i = m_HanlersUidMap.find( targetServiceUid );
+ if ( i != m_HanlersUidMap.end() )
+ {
+ if ( (i->second)->IsWaitsForHtiMessage() )
+ {
+ Util::Debug("dispatch error to system cause it waits");
+ if ( !(i->second)->ReceiveHtiMessage(m_IncomingHtiMessage) )
+ {
+ Util::Error("Failed to dispatch hti message");
+ Util::Hex(m_IncomingHtiMessage->HtiData(), HtiMessage::MinHeaderSize());
+ //dismiss message
+ delete m_IncomingHtiMessage;
+ }
+ }
+ else
+ {
+ Util::Debug("find handler that waits");
+ //find the handler that waits for hti message
+ for( htiUIDHashMap::const_iterator i = m_HanlersUidMap.begin();
+ i != m_HanlersUidMap.end();
+ ++i)
+ {
+ Util::Debug((i->second)->soapAction());
+ if ( (i->second)->IsWaitsForHtiMessage() )
+ {
+ Util::Debug("found");
+ if ( !(i->second)->ReceiveHtiMessage(m_IncomingHtiMessage) )
+ {
+ Util::Error("Failed to dispatch hti message");
+ Util::Hex(m_IncomingHtiMessage->HtiData(), HtiMessage::MinHeaderSize());
+ //dismiss message
+ delete m_IncomingHtiMessage;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ i = m_HanlersUidMap.find( targetServiceUid );
+ if ( i != m_HanlersUidMap.end() )
+ {
+ if ( !(i->second)->ReceiveHtiMessage(m_IncomingHtiMessage) )
+ {
+ Util::Error("Failed to dispatch hti message");
+ Util::Hex(m_IncomingHtiMessage->HtiData(), HtiMessage::MinHeaderSize());
+ //dismiss message
+ delete m_IncomingHtiMessage;
+ }
+ }
+ else
+ {
+ Util::Error("Failed to dispatch hti message, no plug-in with appropriate uid",m_IncomingHtiMessage->GetServiceUID() );
+ Util::Hex(m_IncomingHtiMessage->HtiData(), HtiMessage::MinHeaderSize());
+ //dismiss message
+ delete m_IncomingHtiMessage;
+ }
+ }
+ m_IncomingHtiMessage = NULL;
+
+ // This will give other threads (soaphandlers) some runtime to process the
+ // received message.
+ Sleep(0);
+}
+
+/*
+ * This method is used to forward soap request to correct SOAPHandler
+ * Correct SOAPHandler is found by soap action
+ */
+bool HtiDispatcher::DispatchSoapServe(struct soap* soapEnv)
+{
+ Util::Debug("HtiDispatcher::DispatchSoapServe()");
+/*
+ _CrtMemState localMem;
+ _CrtMemCheckpoint( &localMem );
+*/
+ soap_begin( soapEnv );
+ if (soap_begin_recv(soapEnv))
+ {
+ soap_set_namespaces( soapEnv, namespaces);
+ soap_send_fault(soapEnv);
+ return false;
+ }
+
+ if ( !(soapEnv->action) )
+ {
+ //Util::Error("soapAction is missing");
+ soap_set_namespaces( soapEnv, namespaces);
+ soapEnv->error = soap_sender_fault(soapEnv, "soapAction is missing", NULL);
+ soap_send_fault(soapEnv);
+ return false;
+ }
+/*
+ //_RPT0(_CRT_WARN, "!!!!!!!!!!!!!!!! Local Objects !!!!!!!!!!!!!!!!\n");
+
+ _CrtMemDumpAllObjectsSince( &localMem );
+ //_RPT1(_CRT_WARN, "action address %x\n", soapEnv->action);
+*/
+ htiSoapActionHashMap::const_iterator it;
+ it = m_SoapHandlers.find( soapEnv->action );
+ if ( it != m_SoapHandlers.end() )
+ {
+ return (it->second)->ServeSoap( soapEnv );
+ }
+ else
+ {
+ //Util::Error("soapAction is unknown:");
+ //Util::Error(soapEnv->action);
+ //soapEnv->error = SOAP_NO_METHOD;
+ soap_set_namespaces( soapEnv, namespaces);
+ soapEnv->error = soap_sender_fault(soapEnv, "No plugin found", "no plugin found for requested service in actionSOAP header field");
+ soap_send_fault(soapEnv);
+ return false;
+ }
+
+ Util::Debug("HtiDispatcher::DispatchSoapServe() OK");
+}
+
+/*
+ * SoapHandler calls this method
+ * The method creates a Data object from the HtiMessage given as parameter
+ * and puts the Data object into incoming queue(going eventually to CommChannelPlugin)
+ */
+void HtiDispatcher::SendHtiMessage(HtiMessage* msg)
+{
+ Util::Debug("HtiDispatcher::SendHtiMessage()");
+ if (msg)
+ {
+ Data* d = new Data(msg->HtiData(), msg->HtiDataSize(), Data::EData);
+ //_RPT2(_CRT_WARN, "d %x <%d>\n", d , sizeof(Data));
+
+ if (Util::GetVerboseLevel() == Util::VerboseLevel::debug)
+ {
+ char tmp[64];
+ sprintf(tmp, "[HtiDispatcher] HTI MsgSize = %d", msg->HtiDataSize());
+ string s(tmp);
+ Util::Debug(s);
+ Util::Hex( (char*)(msg->HtiData()), 16);
+ }
+ m_QueueIn->push(d);
+ //delete msg;
+ }
+ Util::Debug("HtiDispatcher::SendHtiMessage() OK");
+}
+
+void HtiDispatcher::Stop()
+{
+ m_Running = false;
+ HANDLE* handles = new HANDLE[ m_SoapHandlers.size() ];
+ int h = 0;
+ for( htiSoapActionHashMap::const_iterator i = m_SoapHandlers.begin();
+ i != m_SoapHandlers.end();
+ ++i)
+ {
+ (i->second)->Stop();
+ handles[ h++ ] = (i->second)->ThreadHandle();
+ }
+
+ WaitForMultipleObjects(m_SoapHandlers.size(),
+ handles,
+ TRUE,
+ 5000/*g_MaximumShutdownWaitTime*/);
+
+ delete[] handles;
+}
+
+bool HtiDispatcher::IsRunning()
+{
+ return m_Running;
+}