diff -r 7fdc9a71d314 -r 8ad140f3dd41 hti/PC_Tools/HTIGateway/HtiGateway/src/HtiDispatcher.cpp --- /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 + +#include + +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* qIn, + SafeQueue* 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<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<HtiErrorCode(); + s<<"\nserviceUid: "; + s<ErrorServiceUid(); + s<<"\nserviceErrorCode: "; + s<ServiceErrorCode(); + s<<"\nErrorDescription: "; + s<ErrorDescription(); + s<<"\ntargetServiceUid: "; + s<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; +}