diff -r a2efdd544abf -r b47902b73a93 networkprotocolmodules/suplprotocolmodule/SuplProtocol/src/suplstatehandlerbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkprotocolmodules/suplprotocolmodule/SuplProtocol/src/suplstatehandlerbase.cpp Fri Jun 04 10:34:15 2010 +0100 @@ -0,0 +1,580 @@ +// Copyright (c) 2008-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 provides the implementation of the base class for +// protocol states used in the SUPL Protocol Module. +// +// + +/** + @file + @internalTechnology + @deprecated +*/ + +#include "suplstatehandlerbase.h" +#include "supldevloggermacros.h" +#include "suplend.h" +#include "suplgatewayinterface.h" + +/** Standard constructor. +@param aMachine A reference to the parent state machine. +*/ +CSuplStateHandlerBase::CSuplStateHandlerBase(CSuplFsmSessionBase& aMachine) +: iMachine(aMachine) + { + SUPLLOG(ELogP1, "CSuplStateHandlerBase::CSuplStateHandlerBase() Begin\n"); + SUPLLOG(ELogP1, "CSuplStateHandlerBase::CSuplStateHandlerBase() End\n"); + } + + +/** Standard destructor. +*/ +CSuplStateHandlerBase::~CSuplStateHandlerBase() + { + SUPLLOG(ELogP1, "CSuplStateHandlerBase::~CSuplStateHandlerBase() Begin\n"); + SUPLLOG(ELogP1, "CSuplStateHandlerBase::~CSuplStateHandlerBase() End\n"); + } + + +/** +Utility method to retrieve the location Id in from the store +@param Pointer to the location Id. Caller owns the heap object created. +*/ +TBool CSuplStateHandlerBase::BuildLocationIdL(CSuplLocationId*& aLocationId) +{ + SUPLLOG(ELogP1, "CSuplStateHandlerBase::BuildLocationIdL() Begin\n"); + TBool ret = EFalse; + CSuplLocationId* ptr = NULL; + + // Location ID is constructed with network information + // stored by the state machine. + + RMobilePhone::TMobilePhoneNetworkInfoV1 networkInfo; + RMobilePhone::TMobilePhoneLocationAreaV1 locationArea; + + if(iMachine.IsNetworkInfoAvailable()) + { + iMachine.RetrieveStoredNetworkInfo(networkInfo, locationArea); + + switch(networkInfo.iMode) + { + case RMobilePhone::ENetworkModeGsm: + { + RMobilePhone::TMobilePhoneCellInfoV9 cellInfo; + ptr = CSuplLocationId::NewL(ESuplLocationTypeGsm); + aLocationId = ptr; + TLex(networkInfo.iCountryCode).Val(aLocationId->iGsmCellInfo->iRefMCC); + TLex(networkInfo.iNetworkId).Val(aLocationId->iGsmCellInfo->iRefMNC); + aLocationId->iGsmCellInfo->iRefLAC = locationArea.iAreaKnown?locationArea.iLocationAreaCode:0; + aLocationId->iGsmCellInfo->iRefCI = locationArea.iCellId; + if(iMachine.RetrieveStoredCellInfo(cellInfo)) + { + aLocationId->iGsmCellInfo->iTA = cellInfo.iTimingAdvance; + } + ret = ETrue; + } + break; + + case RMobilePhone::ENetworkModeWcdma: + ptr = CSuplLocationId::NewL(ESuplLocationTypeWcdma); + aLocationId = ptr; + TLex(networkInfo.iCountryCode).Val(aLocationId->iWcdmaCellInfo->iRefMCC); + TLex(networkInfo.iNetworkId).Val(aLocationId->iWcdmaCellInfo->iRefMNC); + aLocationId->iWcdmaCellInfo->iRefUC = locationArea.iCellId; + ret = ETrue; + break; + + default: // only GSM and WCDMA networks are supported + ret = EFalse; + break; + } + + } + + if(ptr != NULL) + { + RMobilePhone::TMobilePhoneCellInfoV9 cellInfo; + if(iMachine.RetrieveStoredCellInfo(cellInfo)) + { + switch(cellInfo.iStatus) + { + case RMobilePhone::ECellInfoStatusNotCurrent: + ptr->iStatus = ESuplLocStatusStale; + break; + case RMobilePhone::ECellInfoStatusCurrent: + ptr->iStatus = ESuplLocStatusCurrent; + break; + default: + case RMobilePhone::ECellInfoStatusUnknown: + ptr->iStatus = ESuplLocStatusUnknown; + break; + } + } + else + { + ptr->iStatus = ESuplLocStatusCurrent; + } + } + + SUPLLOG(ELogP1, "CSuplStateHandlerBase::BuildLocationIdL() End\n"); + return ret; +} + +/** Actions on entering state EStatePositioningInProgress +Events conductive to (re)entering this state are a SUPL POS +message received from the SLP or a request from the positioning +state machine for sending a SUPL POS with a positining protocol +payload. +*/ +TBool CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() + { + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() Begin\n"); + TBool actionsTaken = EFalse; + + // Check first if a positioning payload is available in the event + // store for sending out + const CSuplPosPayload* constPosPayload = iMachine.RetrievePosPayload(); + CSuplPosPayload* posPayload = const_cast (constPosPayload); + if (posPayload) + { + ASSERT(iMachine.IsSessionConnected()); + + // Set payload in a SUPL POS + CSuplPos* suplPos = CSuplPos::NewLC(ETrue); + suplPos->SetPosPayload(posPayload); + + CSuplSessionId* msgId = iMachine.MessageSessionId(); + + suplPos->SetSessionId(*msgId); + + CleanupStack::Pop(suplPos); + // Ask the Connection Manager to send the SUPL POS message + iMachine.Observer().ConnectionManager().SendMessage(suplPos, iMachine.SessionId().SessionNum()); + + // If this was the last of the SUPL POS messages (positioning state machine + // has terminated), start the SUPL END timer. + if (iMachine.RetrievePositioningSessionEnded()) + { + iMachine.StartSuplEndTimer(); + } + + actionsTaken = ETrue; + } + else + { + // There must be a SUPL POS in the event store + CSuplMessageBase* suplMessage = const_cast (iMachine.RetrieveSuplMessage()); + ASSERT(suplMessage != NULL); + ASSERT(CSuplMessageBase::ESuplPos == suplMessage->MessageType()); + + if ((suplMessage != NULL) && (CSuplMessageBase::ESuplPos == suplMessage->MessageType())) + { + CSuplPos* suplPosMessage = static_cast (suplMessage); + + // make sure the session id matches the one received in earlier messages + CSuplSessionId *sessId = CSuplSessionId::NewLC(); + suplPosMessage->GetSessionId(*sessId); + if (! ((*(iMachine.MessageSessionId())) == (*sessId))) + { + iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId); + // Store received session Id for sending later in SUPL END as per SUPL specification + CleanupStack::Pop(sessId); + iMachine.SetMessageSessionId(sessId); // ownership transferred + delete suplPosMessage; + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() End\n"); + return actionsTaken; + } + else + { + CleanupStack::PopAndDestroy(sessId); + } + // Extract the payload + posPayload = suplPosMessage->PosPayload(); + ASSERT(posPayload != NULL); + if (posPayload) + { + // send the payload to the positioning fsm + iMachine.PositioningFsm()->ProcessPositioningMessage(posPayload); + } + + // Delete the SUPL POS message + delete suplPosMessage; + actionsTaken = ETrue; + } + } + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() End\n"); + return actionsTaken; + } + +/** Actions on entering state EStatePositionReceived +This method extracts a position from a SUPL END message and +sends it to LBS. +*/ +TBool CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() + { + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() Begin\n"); + TBool actionsTaken = EFalse; + + // Extract the position from the SUPL END in the event store and send to + // LBS in a ProcessLocationUpdate method + TPosition position; + + // There must be a SUPL END in the store + CSuplMessageBase* suplMessage = const_cast (iMachine.RetrieveSuplMessage()); + + ASSERT(suplMessage != NULL); + ASSERT(CSuplMessageBase::ESuplEnd == suplMessage->MessageType()); + + if ((suplMessage != NULL) && (CSuplMessageBase::ESuplEnd == suplMessage->MessageType())) + { + + CSuplEnd* suplEndPtr = static_cast (suplMessage); + + // make sure the session id matches the one received in earlier messages + CSuplSessionId *sessId = CSuplSessionId::NewLC(); + suplEndPtr->GetSessionId(*sessId); + + // Compare only the SET session ID as this may be the first message we get from + // the SLP and the SLP session ID is not yet known. + CSuplSetSessionId* receivedSetSessId = (*(iMachine.MessageSessionId())).iSetSessionId; + CSuplSetSessionId* storedSetSessId = (*sessId).iSetSessionId; + if (! ((*receivedSetSessId)== (*storedSetSessId))) + { + iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId); + // Store received session Id for sending later in SUPL END as per SUPL specification + CleanupStack::Pop(sessId); + iMachine.SetMessageSessionId(sessId); // ownership transferred + delete suplEndPtr; + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() End\n"); + return actionsTaken; + } + else + { + CleanupStack::PopAndDestroy(sessId); + } + + // There must be a position in the SUPL END + ASSERT(suplEndPtr->PositionPresent()); + if (suplEndPtr->PositionPresent()) + { + suplEndPtr->GetPosition(position); + + // Use position to build a TPositionInfo object + // and send it to LBS + TPositionInfo pos; + pos.SetPosition(position); + const TPositionModuleId id = {KSuplv1UidValue}; + pos.SetModuleId(id); + pos.SetUpdateType(EPositionUpdateGeneral); + pos.SetPositionModeReason(EPositionModeReasonNone); + + // If the position has been received and no positioning session + // has taken place, then the position is the reference location + // calculated based on cell-id. + if (!iMachine.PosSessionConducted()) + { + pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork); + } + else + { + // Position calculated in Terminal Assisted mode unless the + // SUPL END has an error code, in which case the position is + // the reference location. + if(suplEndPtr->StatusCodePresent()) + { + pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork); + } + else + { + pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted); + } + } + + iMachine.Observer().Gateway().NetworkLocationInd(iMachine.LbsSessionId(), pos); + + actionsTaken = ETrue; + } + + // SUPL POS message no longer needed + delete suplEndPtr; + } + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() End\n"); + return actionsTaken; + } + + +/** Actions on entering state EStateSuplSessionEnded + +Send a SUPL END message to the SUPL server. This state is reached +after the state machine was cancelled for some reason. +*/ +TBool CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() + { + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() Begin\n"); + TBool verRequired = EFalse; + TBool statusCodeRequired = ETrue; + // Send a SUPL END to the SLP. Most likely reason to be here is + // that the machine is cancelling due to explicit client cancel, a + // client privacy rejection, an error or a timeout. If so, the + // cancel source and reason can be taken from the event store. + // + // The only other use case where we end up in here is for MTLRs + // where the SUPL INIT has specified "no Position". + + + // Take cancel source and reason from the event store + CSuplFsmSessionBase::TCancelSource source; + CSuplFsmSessionBase::TCancelReason reason; + iMachine.RetrieveCancelInfo(source,reason); + + // work out the reason code to set in a SUPL END + TSuplStatusCode statusCode = ESuplStatusUnspecified; + switch (source) + { + case CSuplFsmSessionBase::ECancelNone: + // Not here after a cancel...assuming + // there has been a SUPL INIT with "no position" + // and we are here to send a SUPL END with privacy + // acceptance. + + verRequired = ETrue; + statusCodeRequired = ETrue; + statusCode = ESuplStatusConsentGrantedByUser; + + break; + case CSuplFsmSessionBase::ECancelNetwork: + + switch (reason) + { + case CSuplFsmSessionBase::EReasonInsuficcientSecurity: + // no matching supl status code + statusCode = ESuplStatusUnspecified; + break; + // Since the connection manager performs the decoding + // of received SUPL messages, all of the errors in decoding + // show as having ECancelNetwork source, hence: + case CSuplFsmSessionBase::EReasonParsingError: + statusCode = ESuplStatusProtocolError; + break; + case CSuplFsmSessionBase::EReasonDataMissing: + statusCode = ESuplStatusDataMissing; + break; + case CSuplFsmSessionBase::EReasonUnexpectedDataValue: + statusCode = ESuplStatusUnexpectedDataValue; + break; + default: + statusCode = ESuplStatusUnspecified; + break; + } + break; + + case CSuplFsmSessionBase::ECancelPosProt: + statusCode = ESuplStatusPosMethodFailure; + break; + + case CSuplFsmSessionBase::ECancelSuplProt: + switch (reason) + { + case CSuplFsmSessionBase::EReasonMethodMismatch: + statusCode = ESuplStatusPosMethodMismatch; + break; + case CSuplFsmSessionBase::EReasonInvalidSessId: + statusCode = ESuplStatusInvalidSessionId; + break; + case CSuplFsmSessionBase::EReasonUnexpectedMessage: + statusCode = ESuplStatusUnexpectedMessage; + break; + default: + statusCode = ESuplStatusUnspecified; + break; + } + break; + + case CSuplFsmSessionBase::ECancelClient: + // no matching status code in SUPL + if (CSuplFsmSessionBase:: EReasonPrivacyRejected == reason) + { + statusCode = ESuplStatusConsentDeniedByUser; + verRequired = ETrue; + } + else if (CSuplFsmSessionBase::EReasonFutilePosCalc == reason) + { + statusCode = ESuplStatusPosMethodFailure; + } + else + { + statusCode = ESuplStatusUnspecified; + } + break; + + case CSuplFsmSessionBase::ECancelClosing: + default: + //No other source of cancel should result in this method being called + ASSERT(EFalse); + break; + } + + // Build and send a SUPL END + CSuplEnd* suplEndPtr = CSuplEnd::NewLC(ETrue); + + if (statusCodeRequired) + { + suplEndPtr->SetStatusCode(statusCode); + } + + if (verRequired) + { + // Set the Ver field in SUPL END + TBuf8<8> ver; + iMachine.RetrieveVer(ver); + User::LeaveIfError(suplEndPtr->SetVer(ver)); + } + + // Set the session Id + CSuplSessionId* msgId = iMachine.MessageSessionId(); + suplEndPtr->SetSessionId(*msgId); + + CleanupStack::Pop(suplEndPtr); + iMachine.Observer().ConnectionManager().SendMessage(suplEndPtr, iMachine.SessionId().SessionNum()); + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() End\n"); + return ETrue; + } + + +/** Actions on entering state EStateLbsSessionEnded + +This method informs LBS that the session has ended. +*/ +TBool CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() + { + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() Begin\n"); + TBool actionsTaken = EFalse; + + TInt sessionCompletionReason = KErrNone; // reason sent to LBS + + // Check the event store to see in the completion reason + // has to be different from KErrNone + // Take cancel source and reason from the event store. + // + CSuplFsmSessionBase::TCancelSource cancelSource; + CSuplFsmSessionBase::TCancelReason cancelReason; + iMachine.RetrieveCancelInfo(cancelSource,cancelReason); + + if (cancelSource != CSuplFsmSessionBase::ECancelNone) + { + // Session was cancelled. Error code is KErrCancel + // except if network connection is down (KErrDisconnected). + if ((cancelSource == CSuplFsmSessionBase::ECancelNetwork) + && (cancelReason == CSuplFsmSessionBase::EReasonDisconnected)) + { + sessionCompletionReason = KErrDisconnected; + } + else + { + sessionCompletionReason = KErrCancel; + } + actionsTaken = ETrue; + } + + // Check if the session was terminated after an unexpected + // SUPL END or a SUPL END with reason code indicating an error + else if (iMachine.IsUnexpectedSuplEndStored()) + { + // Complete with KErrPositionProtocolErr + sessionCompletionReason = KErrPositionProtocolErr; + actionsTaken = ETrue; + } + else + { + // If the session has not been cancelled, there could be a + // SUPL END message in the store (there won't be one if the + // SUPL END carried position information as it is dealt with + // in a previous state). + const CSuplMessageBase* suplEnd = iMachine.RetrieveSuplMessage(); + + if ((suplEnd != NULL) && (CSuplMessageBase::ESuplEnd == (const_cast (suplEnd))->MessageType())) + { + delete suplEnd; + } + + sessionCompletionReason = KErrNone; + actionsTaken = ETrue; + } + + if (actionsTaken) + { + iMachine.Observer().Gateway().SessionCompleteInd(iMachine.LbsSessionId(), sessionCompletionReason); + } + iMachine.SetSessionInProgress(EFalse); + SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() End\n"); + return actionsTaken; + } + + +/** Utility method to convert a numeric string to Binary Coded Decimal string + +Taken from section 8.3 of the OMA SUPL document UserPlane Location Protocol OMA-TS-ULP-V1-0-20070615-A +The BCD string is stored in an 8 octet buffer with 2 digits per octet. +Each digit is encoded 0000 to 1001 ( 0 to 9). +Bits 8765 of octet n encoding digit 2n +Bits 4321 of octet n encoding digit 2(n-1)+1 +Unused digits in the string are filled with 0xFF + +*/ +void CSuplStateHandlerBase::ConvertToBcd(TDes8& aBcdString) + { + + const TUint8 KMaxBcdStringLength = 8; + const TUint8 fillBuffer[KMaxBcdStringLength] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + TBool LeastSignificantNibble(ETrue); + TInt OctetCount = 0; + TChar nextChar; + TUint8 nextOctet = 0; + TLex lexString(*iMachine.Msisdn()); + + aBcdString.Zero(); + while (!lexString.Eos()) + { + nextChar = lexString.Get(); + if (nextChar.IsDigit()) // ignore any non-numeric characters + { + if (LeastSignificantNibble) + { + nextOctet = nextChar.GetNumericValue(); //store digit in L.S. nibble + LeastSignificantNibble = EFalse; + } + else + { + nextOctet |= (nextChar.GetNumericValue()<<4); //store digit in M.S. nibble + aBcdString.Append(nextOctet); + OctetCount++; + LeastSignificantNibble = ETrue; + } + } + } + + // All of the decimal string has been converted - deal with an half filled octet + if (!LeastSignificantNibble) + { + nextOctet |= 0xF0; + aBcdString.Append(nextOctet); + OctetCount++; + } + + // Fill remainder of string with 0xFF values + aBcdString.Append(fillBuffer, (KMaxBcdStringLength-OctetCount)); + + } +