diff -r bbd31066657e -r 8bb370ba6d1d testexecfw/stf/stfext/testmodules/teftestmod/testexecmdw/filelogger/src/server.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testexecfw/stf/stfext/testmodules/teftestmod/testexecmdw/filelogger/src/server.cpp Fri Apr 09 10:46:28 2010 +0800 @@ -0,0 +1,552 @@ +/* +* Copyright (c) 2005-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: +* Main log server engine. +* Process log requests from multiple clients simultaneously. +* +*/ + + + +/** + @file server.cpp +*/ +#include "server.h" + +CLogServer* CLogServer::NewL() +/** + * @return - Instance of the log server + */ + { + CLogServer * server = new (ELeave) CLogServer(); + CleanupStack::PushL(server); + server->ConstructL(); + // CServer base class call + server->StartL(KFileLogrerServerName); + CleanupStack::Pop(server); + return server; + } + +void CLogServer::ConstructL() +/** + * Second phase construction + */ + { + User::LeaveIfError(Fs().Connect()); + } + + +CLogServer::CLogServer() : CServer2(EPriorityStandard,ESharableSessions) +/** + * Constructor + */ + { + } + +CLogServer::~CLogServer() +/** + * Destructor + */ + { + // Close the array of control structures + LogControl().Close(); + Fs().Close(); + } + + +CSession2* CLogServer::NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const +/** + * @param RMessage - RMessage for the session open + */ + { + // Just create the session + CLogSession* session = new (ELeave) CLogSession(); + return session; + } + +void CLogServer::ControlComplete(CLogFileControl& aControl) +/** + * @param aControl - Logfile control class reference + * + * Checks to see if this control session can be removed + */ + { + // Check session count and the data buffers on the queue + if(aControl.SessionCount() || !aControl.QueueEmpty()) + return; + + // There are no subsessions mapped to the logfile control class and + // no data buffers on its write queue + // Loop through the server's control array and remove it then delete it + TInt i; + for(i=0;iRemoveSession(); + CLogServer* p=(CLogServer*) Server(); + // Shuts Down the server if this is the last open session + p->ControlComplete(*iControl); + } + +void CLogSession::ServiceL(const RMessage2& aMessage) +/** + * @param aMessage - Function and data for the session + */ + { + switch(aMessage.Function()) + { + // API CreateLog() call + case RFileFlogger::ECreateLog : + { + // Sanity check to make sure it's not been called multiple times + if(iControl) + { + aMessage.Complete(KErrInUse); + break; + } + // Get the filepath + // size policed on the client side + TBuf logFilePath; + // Read it + aMessage.ReadL(0,logFilePath); + // Get the log mode in the second argument + RFileFlogger::TLogMode logMode; + logMode = (RFileFlogger::TLogMode)aMessage.Int1(); + // Get a pointer to the parent server + CLogServer* server=(CLogServer*) Server(); + // For compare's convert the whole path to lower case + logFilePath.LowerCase(); + // Get rid of leading and trailing spaces. + logFilePath.Trim(); + + // Loop the through the server's logfile control class list + // to see if there's a match. + TInt i; + for(i=0;iLogControl().Count();i++) + { + if(server->LogControl()[i]->LogFile() == logFilePath) + // This file's already in open so we don't have to open it + break; + } + TInt err = KErrNone; + // Check the count + if(i < server->LogControl().Count()) + // Map this session to an existing logfile control class in the list + iControl = server->LogControl()[i]; + else + { + // Create a new logfile control class + // creates/opens the logfile + TRAP(err,iControl = CLogFileControl::NewL(*server,logFilePath,logMode)); + if(!err) + { // nancy + // find out the type of output format and assign to this new created control + TInt error = logFilePath.Find(_L(".xml")); + if(error==KErrNotFound) iControl->SetLogType(CLogFileControl::ETxt); + else iControl->SetLogType(CLogFileControl::EXml); + // end nancy + // Append it to the logfile control class list + server->LogControl().Append(iControl); + } + } + if(!err) + // Increment its session count + iControl->AddSession(); + aMessage.Complete(err); + } + break; + // One of the API write calls + case RFileFlogger::EWriteLog : + { + // Sanity check + if(!iControl) + { + aMessage.Complete(KErrNotFound); + break; + } + // Data can be any size + // Get the length from second argument + TInt bufferLength = aMessage.Int1(); + // Get a heap buffer of the right size + HBufC8* buffer = HBufC8::NewLC(bufferLength); + TPtr8 ptr(buffer->Des()); + // read the data + aMessage.ReadL(0,ptr); + // Get a buffer control class contructed with the heap data + // takes ownership + CLogBuffer* logBuffer = new (ELeave) CLogBuffer(*buffer); + CleanupStack::Pop(buffer); + // Add it to the logfile control class buffer queue + iControl->AddLogBuffer(*logBuffer); + if(!iControl->IsActive()) + // AO is idle, kick into life + iControl->Kick(); + aMessage.Complete(KErrNone); + } + break; + + default: + break; + } + } + +/////// + +CLogFileControl* CLogFileControl::NewL(CLogServer& aParent, const TDesC& aLogFilePath,RFileFlogger::TLogMode aMode) +/** + * @param aParent - Server reference for callback + * @param aLogFilePath - Full path and filename of the logfile + * @param aMode - Overwrite or Append + * + * First phase construction for logfile control class + */ + { + CLogFileControl* self = new (ELeave) CLogFileControl(aParent,aLogFilePath); + CleanupStack::PushL(self); + self->ConstructL(aMode); + CleanupStack::Pop(); + return self; + } + +CLogFileControl::CLogFileControl(CLogServer& aParent,const TDesC& aLogFilePath) : + iParent(aParent), + iLogFileName(aLogFilePath), + iTransmitted(EFalse) +/** + * @param aParent - Server reference for callback + * @param aLogFilePath - Full path and filename of the logfile + * + * Constructor - Safe initialisation + */ + { + iQueue.SetOffset(CLogBuffer::LinkOffset()); + } + +void CLogFileControl::ConstructL(RFileFlogger::TLogMode aMode) +/** + * @param aMode - Overwrite or Append + * + * Second phase construction - Create or open the logfile + */ + { + if(aMode == RFileFlogger::ELogModeOverWrite) + // In overwrite mode replace + User::LeaveIfError(iLogFile.Replace(iParent.Fs(),iLogFileName,EFileWrite)); + else + { + // For append try open then replace + TInt err = iLogFile.Open(iParent.Fs(),iLogFileName,EFileWrite); + if(err != KErrNone) + // Bomb out if replace fails + User::LeaveIfError(iLogFile.Replace(iParent.Fs(),iLogFileName,EFileWrite)); + else + { + // Open worked. Position at EOF + TInt pos; + iLogFile.Size(pos); + User::LeaveIfError(iLogFile.Seek(ESeekEnd,pos)); + } + } + } + +CLogFileControl::~CLogFileControl() +/** + * Destructor + * The server maintains a list of these classes and will not destruct one if there + * is data on its queue + * Destructor just closes the file handle. + */ + { + iLogFile.Close(); + } + +void CLogFileControl::RunL() +/** + * Main File writing pump + * Called on write completion or Kick() by the session that accepts the data + */ + { +#if (defined _DEBUG) + _LIT(KPanic,"LogEng RunL()"); +#endif + __ASSERT_DEBUG(iStatus.Int() == KErrNone,User::Panic(KPanic,iStatus.Int())); + // Check to see if this is the result of write completion + if(iTransmitted) + { + // Write completed + // Remove the buffer at the head of the queue and free it + CLogBuffer* buffer = iQueue.First(); + iQueue.Remove(*buffer); + delete buffer; + } + // Check to see if there's more on the queue + if(!iQueue.IsEmpty()) + { + // There is so write the head of the queue + CLogBuffer* buffer = iQueue.First(); + SetActive(); + // Set the flag to say we've transmitted + iTransmitted = ETrue; + +// ------------------------------------ + if(iLogFormat==ETxt) WriteTxt(buffer->Buf()); + else WriteXml(buffer->Buf()); + } + else + { + // Nothing on the queue + iTransmitted = EFalse; + // Call into the server to check if this resource can be freed + iParent.ControlComplete(*this); + } + } + +void CLogFileControl::WriteXml(const TDesC8 &aDes) +/** + * @param aDes - send a aDes string in xml format to a log file + */ + { +/*--------- Maintaince Warning: ----------------------------------- +******* the fomat of below is sensible from client original format. +******* Any change should match actual string formated from client. +******* Double check the code on client side + +* The current assumtion of format: +* First string values are seperated by sign " - " and extra pair of fields are +* seperated from main log message by long unusual string "LogFieldsRequiredBeingAddedToAboveLogMessage" +* The \t used to seperate field name and field value and \r\n used to seperate +* each other from those pairs of field +* \t\t\t\t\t\t is used to end of whole string +--------------------------------------------------------------------------------*/ + _LIT8(KxmlHeader,"\r\n"); + //The order of variables: + // time - aTime + // Severity - aSeverity + // Thread - aThread + // Filename - aFilename + // Linenumber - aLinenumber + // Text - aText + + // Start of string retrive/deformating + HBufC8* pBuf1 = HBufC8::NewL(KMaxLoggerLineLength*2); //(aDes.Length()+200); + if(!pBuf1) + { + return; // no memory + } + TPtr8 aPtr(pBuf1->Des()); // used for searching + TPtr8 alogbuf(pBuf1->Des()); //used for final log + aPtr.Append(aDes); + TPtrC8 SearchBuf; + TInt aCount[8]; + aCount[0]=0; + TInt posI(0); + +// retrive log message: + // Retrive common part of log message: + for(TInt i = 1; i<6; i++) + { + SearchBuf.Set(aPtr.Mid(posI)); + aCount[i]=SearchBuf.Find(KSeperation8)+posI; + posI=aCount[i]+3; + if(aCount[i]0 + { + TInt currentLength = alogField[5].iLogValue8.Length() ; + //this sentence will append the log info without buffer limit. + TInt newAppendLength = aDes.Length()-aCount[5]-5; + //The max length for log buff in this + TInt bufferLeft = alogField[5].iLogValue8.MaxLength() - currentLength; + // get the smaller one between the two + TInt enabledLength = bufferLeft > newAppendLength ? newAppendLength : bufferLeft ; + alogField[5].iLogValue8.Copy(aPtr.Mid(aCount[5]+3,enabledLength)); + //alogField[5].iLogValue8.Copy(aPtr.Mid(aCount[5]+3,aDes.Length()-aCount[5]-5)); + } + else + { + alogField[5].iLogValue8.Copy(aPtr.Mid(aCount[5]+3,aCount[6]-aCount[5]-5)); + posI=aCount[6]+45; //45 is from the length of long string and a tab + SearchBuf.Set(aPtr.Mid(posI)); + aCount[7]=SearchBuf.Find(_L8("\r\n"))+posI; + TLex8 lex(aPtr.Mid(posI,aCount[7]-posI)); // get the length + TInt err=lex.Val(alength); + if (err) alength=0; // ignor the extra log fields. Let the log go + + // Retrive the extra log fields + extralogField = new TLogField8[alength]; + if(!extralogField) return; // no memory + for(TInt i=0; i" + //It shoud happened once at the beginning of the file + // such as overwrite mode + { + afileSize=12; // used for lock position + alogbuf.Copy(KxmlHeader); + } + alogbuf.Append(_L8("\r\n\r\n")); + for(TInt i=0; i<6; i++) + { + alogbuf.Append(_L8(" <")); + alogbuf.Append(alogField[i].iLogTag8); + alogbuf.Append(_L8(">")); + alogbuf.Append(alogField[i].iLogValue8); + alogbuf.Append(_L8("\r\n")); + } + for(TInt i=0; i")); + alogbuf.Append(extralogField[i].iLogValue8); + alogbuf.Append(_L8("\r\n")); + } + + alogbuf.Append(_L8("")); + alogbuf.Append(_L8("\r\n")); + + iLogFile.Write(afileSize-12,alogbuf,iStatus); + iLogFile.Flush(); + + if(!r) + { + mutex.Signal(); + mutex.Close(); + } + + if(extralogField) delete[] extralogField; + delete[] alogField; + delete pBuf1; + + } + +void CLogFileControl::WriteTxt(const TDesC8 &aDes) +/** + * @param aDes - send a aDes string in xml format to a log file + */ + { +/*--------- Maintaince Warning for aLogBuffer ----------------------------------- +******* the fomat of below is sensible from client original format. +******* Any change should match actual string formated from client. +******* Double check the code on client side + +* The current assumtion of format: +* First string values are seperated by sign " - " and extra pair of fields are +* seperated from main log message by long unusual string "LogFieldsRequiredBeingAddedToAboveLogMessage" +* The \t used to seperate field name and field value and \r\n used to seperate +* each other from those pairs of field +--------------------------------------------------------------------------------*/ + iLogFile.Write(aDes,iStatus); + } +/////// +CLogBuffer::CLogBuffer(HBufC8& aLogBuffer) : iLogBuffer(aLogBuffer) +/** + * @param aLogBuffer - Heap descriptor. This class takes ownership + * Constructor + */ + { + } + +CLogBuffer::~CLogBuffer() +/** + * Destructor + * This class owns a heap buffer so just free it + */ + { + delete &iLogBuffer; + }