diff -r 000000000000 -r 29b1cd4cb562 bluetoothcommsprofiles/btpan/panagt/panagtstates.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothcommsprofiles/btpan/panagt/panagtstates.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,1431 @@ +// Copyright (c) 2004-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: +// + +/** + @file + @note PAN agent role state machine state implementations +*/ + +#include +#include "panagtstates.h" +#include "panagtremdev.h" +#include "panlocalsdphelper.h" +#include "BTSec.h" +using namespace PanAgent; + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT); +#endif + +CPanAgtStateBase* CPanAgtStateUninitialised::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateUninitialised* self = new (ELeave) CPanAgtStateUninitialised(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +void CPanAgtStateUninitialised::OnEntryL() + { + } + +CPanAgtStateUninitialised::CPanAgtStateUninitialised(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgentStateUninitialised) + { + } +// +// CPanAgentStateInitialising +// +CPanAgentStateInitialising::CPanAgentStateInitialising(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgentStateInitialising) +/** + +*/ + { } + +CPanAgtStateBase* CPanAgentStateInitialising::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgentStateInitialising* self = new (ELeave) CPanAgentStateInitialising(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +void CPanAgentStateInitialising::OnEntryL() +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInInitialisingState)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(ENegotiatingDevicesInArrayInInitialisingState)); + + LOG(_L("RoleState: - entering state")); + + // Have a look in commdb to see if we have a defined local role + TUint32 roleTemp; + StateMachine().Database().GetIntL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_LOCAL_ROLE), roleTemp); + __ASSERT_DEBUG(roleTemp!=0xffff, PanicInState(EOldFormatPanRoleBeingUsedInCommdb)); + StateMachine().FixedLocalRole() = static_cast(roleTemp); + LOG1(_L("RoleState: - local device state in commdb is %x"), StateMachine().FixedLocalRole()); + + // same thing for remote role + StateMachine().Database().GetIntL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PEER_ROLE), roleTemp); + __ASSERT_DEBUG(roleTemp!=0xffff, PanicInState(EOldFormatPanRoleBeingUsedInCommdb)); + StateMachine().FixedRemoteRole() = static_cast(roleTemp); + LOG1(_L("RoleState: - remote device state in commdb is %x"), StateMachine().FixedRemoteRole()); + + // Check if PAN NAP is allowed as a local role. + TBool napEnabled = EFalse; + TRAP_IGNORE(StateMachine().Database().GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_NAP_SERVICE_ENABLED), napEnabled)); + StateMachine().SetNapEnabled(napEnabled); + + // Check for incoming connection support and enable if necessary + TBool allowIncoming; + StateMachine().Database().GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_ALLOW_INCOMING), allowIncoming); + StateMachine().SetAllowIncoming(allowIncoming); + + // make sure the fixed roles (if there are any) make sense + User::LeaveIfError(IsRoleRequestValid(StateMachine().FixedLocalRole(), StateMachine().FixedRemoteRole())); + + if(napEnabled) + { + // NAP can only be enabled for a listening IAP. + if(!allowIncoming) + { + LOG(_L("RoleState: - Listening must be enabled when NAP is enabled. Fail initialisation")); + User::Leave(KErrArgument); + } + + if(!(StateMachine().FixedLocalRole() == EPanRoleUnknown || StateMachine().FixedLocalRole() == EPanRoleNap)) + { + LOG1(_L("RoleState: - Invalid Fixed Local Role %x"), StateMachine().FixedLocalRole()); + User::Leave(KErrArgument); + } + } + else + { + if(StateMachine().FixedLocalRole() == EPanRoleNap) + { + LOG(_L("RoleState: - Invalid Fixed Local Role PAN-NAP when NAP not enabled")); + User::Leave(KErrArgument); + } + } + + if(allowIncoming) + { + // Only any point in advertising in SDP if we're allowing incoming connections... + LOG(_L("RoleState: - incoming support is enabled")); + + if(StateMachine().FixedLocalRole() == EPanRoleU) + { + LOG(_L("RoleState: - Invalid PAN-U Fixed Local Role for listening IAP")); + User::Leave(KErrArgument); + } + + if(!(StateMachine().FixedRemoteRole() == EPanRoleUnknown || StateMachine().FixedRemoteRole() == EPanRoleU)) + { + LOG1(_L("RoleState: - Invalid Fixed Remote Role for listening IAP %x"), StateMachine().FixedRemoteRole()); + User::Leave(KErrArgument); + } + + //If other services are active currently, we will not register sdp records and open listen socket + if (StateMachine().IsNewPanConnectionAllowed()) + { + StartListenerL(); + } + } +#ifdef _DEBUG + else // no incoming support, so just start outgoing connections and move to idle state + // if incoming support is enabled, this will be done after all the SDP roles are registered + { + LOG(_L("RoleState: - incoming support is disabled")); + } +#endif + DoStartOutgoingL(); + } + +void CPanAgentStateInitialising::DoStartOutgoingL() +/** +Start setting up outgoing connections, and move to the idle state +*/ + { + if(StateMachine().SuppressOutgoing()) // check that outgoing connections are not suppressed + // (to allow UIs to start the ad-hoc IAP in incoming mode only, + // and to allow reuse of the registering SDP records state to + // perform reregistration of SDP records - when reregistering + // records, we don't want to prompt to start an outgoing connection) + { + LOG(_L("RoleState: - outgoing connections suppressed, resetting suppression flag and moving directly to idle state")); + StateMachine().ResetSuppressOutgoing(); // stop future outgoing connections being suppressed + if(!(StateMachine().IsIncomingConnectionListenerEnabled())) + { + LOG(_L("RoleState: - This is an invalid state while outgoing connection is suppressed without incoming listening enabled.")); + // outstanding async request will be cancelled by state machine when we leave + User::Leave(KErrListenForIncomingConnectionRequestedWithoutListeningSupport); + } + } + else + { + // outstanding async request will be cancelled by state machine when we leave + StateMachine().SetupOutgoingConnectionsL(); + } + + CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +// +// CPanAgtStateIdle +// +CPanAgtStateBase* CPanAgtStateIdle::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateIdle* self = new (ELeave) CPanAgtStateIdle(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateIdle::CPanAgtStateIdle(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateIdle) +/** + +*/ + { } + +void CPanAgtStateIdle::OnEntryL() +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInInitialisingState)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(ENegotiatingDevicesInArrayInInitialisingState)); + + LOG(_L("RoleState: - entering state")); + + StateMachine().SendProgress(EPanAgtIdle, KErrNone); + StartNegotiationWithFirstPendingDevice(); // if there's not already a device negotiating, start one negotiating + } + +void CPanAgtStateIdle::InitiateOutgoingConnectionL(TBluetoothPanRole& aRequestedLocalRole, TBluetoothPanRole& aRequestedRemoteRole, TPanDeviceWorthTryingRolesList& aWorthTryingRemoteRoles) +/** + +*/ + { + LOG(_L("RoleState: - InitiateOutgoingConnectionL")); + LOG3(_L("RoleState: - ...worthTrying roles - U:%x GN:%x NAP:%x..."), aWorthTryingRemoteRoles.IsWorthTryingU(), aWorthTryingRemoteRoles.IsWorthTryingGn(), aWorthTryingRemoteRoles.IsWorthTryingNap()); + + // Determine the roles for this outgoing connection. + aRequestedLocalRole = StateMachine().FixedLocalRole(); + if(aRequestedLocalRole == EPanRoleUnknown) + { + aRequestedLocalRole = EPanRoleU; + } + + // aRequestedLocalRole should be set to the local role we want to be by the time we call the method below + User::LeaveIfError(SelectRemoteRoleBasedOnLocalRole(aRequestedLocalRole, aRequestedRemoteRole, aWorthTryingRemoteRoles)); + + // and now transition to the appropriate state + CPanAgtStateBase* nextState = NULL; + switch(aRequestedLocalRole) + { + case EPanRoleU: + { + // What about a multiple start case where there are several devices started at once, + // you may be asking? + // This is the wrong state to go into then... However, if they all arrive in the + // outgoing connection starter at the same time (which they will), then they'll all + // get dumped into the array sychronously, and since each one has to asyhronously + // connect a socket, by the time they call us for their role request, we'll know + // there's >1 device + nextState = CPanAgtStateNegotiatingURole::NewL(StateMachine()); + break; + } + case EPanRoleGn: + case EPanRoleNap: + { + nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine()); + break; + } + + default: + { + PanicInState(EPanAgentRoleStateMachineInvalidLocalRole); + break; + } + } + + __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet)); + StateMachine().SetState(*nextState); + delete this; + } + +void CPanAgtStateIdle::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** +A remote device has disconnected before it even began role negotiation! Obviously something dodgy about their role request... +*/ + { + DoDeviceDisconnectL(aDevice); + } + +void CPanAgtStateIdle::IncomingConnectionFromPeerL(TBluetoothPanRole aLocalRole) + { + CPanAgtStateBase* nextState = NULL; + switch(aLocalRole) + { + case EPanRoleU: + { + nextState = CPanAgtStateNegotiatingURole::NewL(StateMachine()); + break; + } + + case EPanRoleGn: + case EPanRoleNap: + { + nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine()); + break; + } + + default: + PanicInState(EInvalidRoleForIncomingConnectionFromPeerL); + } + __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet)); + StateMachine().SetState(*nextState); + delete this; + } + +// +// CPanAgtStateNegotiatingURole +// +CPanAgtStateBase* CPanAgtStateNegotiatingURole::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateNegotiatingURole* self = new (ELeave) CPanAgtStateNegotiatingURole(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateNegotiatingURole::CPanAgtStateNegotiatingURole(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateNegotiatingURole) +/** + +*/ + { } + +CPanAgtStateNegotiatingURole::CPanAgtStateNegotiatingURole(MPanAgtStateMachineNotify& aStateMachine, TPanAgtStates aStateNumber) : + CPanAgtStateBase(aStateMachine, aStateNumber) +/** +When implementing a new state that derives from this base class, ensure that +it provides a unique number to identify the state from other possible +states. @see PanAgent::TPanAgtStates. +*/ + { } + +void CPanAgtStateNegotiatingURole::OnEntryL() +/** +Start deregistering unwanted local SDP records +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInNegotiatingPanUState)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - entering state")); + + if(StateMachine().AllowIncoming()) + { + // stop advertising U record + StateMachine().PanLocalSdpRegistrar().UnregisterLocalSdpRecord(EPanRoleU); + } + } + +void CPanAgtStateNegotiatingURole::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/) +/** +Don't accept more role requests when we're negotiating +*/ + { + LOG(_L("RoleState: - InitiateOutgoingConnectionL to another device, returning busy")); + User::Leave(KErrLocked); + } + +void CPanAgtStateNegotiatingURole::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/) + { + LOG(_L("RoleState: - IncomingConnectionFromPeerL , returning busy")); + User::Leave(KErrLocked); + } + +void CPanAgtStateNegotiatingURole::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice) +/** +A device has finished negotiation and is now active +*/ + { + __ASSERT_ALWAYS(FindDeviceInArray(aDevice)>=0, PanicInState(EDeviceAttemptingToNegotiateThatIsNotInArray)); + __ASSERT_DEBUG(aDevice.GetState() == EActive, PanicInState(EDeviceActiveCalledByDeviceNotInActiveState)); + + CPanAgtStateBase* nextState = CPanAgtStateURole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + +void CPanAgtStateNegotiatingURole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** +A device has disconnected +*/ + { + //This function will only be called when device is in EDisconnecting State. + //Remote device state machine will first shutdown itself and then call panagent to + //disconnect this device and remove it from the device array + __ASSERT_DEBUG(aDevice.GetState() == EDisconnecting, PanicInState(EInvalidRemoteDeviceState)); + + // disconnect them and shutdown or return to the idle state + // outstanding async request will be cancelled by state machine when we leave + DoDeviceDisconnectL(aDevice); // will leave and shutdown the connection if necessary + + StartListenerL(); + + CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +// +// CPanAgtStateURole +// +CPanAgtStateBase* CPanAgtStateURole::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateURole* self = new (ELeave) CPanAgtStateURole(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateURole::CPanAgtStateURole(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateURole) +/** + +*/ + { } + +void CPanAgtStateURole::OnEntryL() +/** + +*/ + { + __ASSERT_DEBUG(NegotiatingDeviceCount()==0,PanicInState(EDeviceInNegotiatingModeOnEntryToUState)); + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ETooManyDevicesAttachedInURole)); + + LOG(_L("RoleState: - entering state")); + + StateMachine().SendProgress(EPanAgtURole, KErrNone); + StartNegotiationWithFirstPendingDevice(); + } + +void CPanAgtStateURole::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/) + { + // Need to become GN / NAP. Check that this will be acceptable for the fixed roles + if(StateMachine().FixedLocalRole() == EPanRoleU || + (StateMachine().FixedRemoteRole() == EPanRoleNap || StateMachine().FixedRemoteRole() == EPanRoleGn)) + { + User::Leave(KErrInvalidOrUnacceptableRoleCombination); + } + else + { + CPanAgtStateBase* nextState = CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + User::Leave(KErrLocked); + } + } + +void CPanAgtStateURole::IncomingConnectionFromPeerL(TBluetoothPanRole aLocalRole) + { + if(aLocalRole == EPanRoleU) + { + // An existing connection is established to the PAN-U role. + User::Leave(KErrInvalidOrUnacceptableRoleCombination); + } + + // Start upgrade to GN/NAP + CPanAgtStateBase* nextState = CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + User::Leave(KErrLocked); // hold the new device off until we've renegotiated with the existing one + } + +void CPanAgtStateURole::RoleChangeRequestFromPeerL(TBluetoothPanRole aLocalRole) + { + CPanAgtStateBase* nextState = NULL; + switch(aLocalRole) + { + case EPanRoleU: + nextState = CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::NewL(StateMachine()); + break; + + case EPanRoleGn: + case EPanRoleNap: + nextState = CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::NewL(StateMachine()); + break; + + default: + PanicInState(EInvalidLocalRoleFromRoleChangeRequestFromPeer); + } + + __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet)); + StateMachine().SetState(*nextState); + delete this; + } + +#ifdef _DEBUG +void CPanAgtStateURole::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice) +#else +void CPanAgtStateURole::DeviceActiveL(CPanRemoteDeviceStateMachine& /*aDevice*/) +#endif // _DEBUG +/** +@note This is only allowed if it's the same device as we're already attached to +ie. we're performing a role switch +*/ + { + __ASSERT_DEBUG(aDevice.GetState() == EPerformingNegotiation, PanicInState(EUnexpectedDeviceActiveReceivedByState)); + } + +void CPanAgtStateURole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** +A remote device has completed its shutdown +*/ + { + LOG(_L("RoleState: - device disconnected...")); + DoDeviceDisconnectL(aDevice); // if there are no devices in the array and we're not supporting incoming connection this method will leave + + // This could be the on device connected to the U or it could be a failed upgrade device. + if(StateMachine().Devices().Count() == 0) + { + StartListenerL(); + CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + } + +void CPanAgtStateURole::StateSendRoleNotification() + { + StateMachine().SendProgress(EPanAgtURole, KErrNone); + } + +// +// CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest +// +CPanAgtStateBase* CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest* self = new (ELeave) CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest) +/** + +*/ + { } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::OnEntryL() +/** +@pre Just come from U mode, so only one active device in the array +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ETooManyDevicesAttachedWhenRenegotiatingActiveConnectionForGnOrNapUpgrade)); // not quite enough to ensure we were previously in U role, but as good as we're going to get + + LOG(_L("RoleState: - entering state")); + + StateMachine().SendProgress(EPanAgtReconfiguringPiconet, KErrNone); + + CPanRemoteDeviceStateMachine& currentActiveDevice = FindDeviceInActiveState(); // there will only be one (we're in U role) + currentActiveDevice.ReadyForRoleRequest(); // signal it to redo role negotiation + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::RoleChangeRequestFromPeerL(TBluetoothPanRole /*aLocalRole*/) + { + // Not in a state to handle this unexpected event. + User::Leave(KErrNotReady); + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::PerformLocalRoleChangeRequestL(TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole) + { + aLocalRole = StateMachine().NapEnabled() ? EPanRoleNap : EPanRoleGn; + aRemoteRole = EPanRoleU; + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice) +/** +We've successfully managed to renegotiate roles with the currently connected device +*/ + { + __ASSERT_ALWAYS(FindDeviceInArray(aDevice)>=0, PanicInState(EDeviceAttemptingToNegotiateThatIsNotInArray)); + __ASSERT_DEBUG(aDevice.GetState() == EActive, PanicInState(EDeviceActiveCalledByDeviceNotInActiveState)); + LOG(_L("RoleState: - device active received")); + + CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/) +/** +Role upgrade failed, return to our previous state +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - role change failed...")); + // there should be (at least one) pending device (the one that caused us to attempt the upgrade to GN/NAP) + // disconnect it (them), because the role change failed + // need to do this because the new device may have been added by the user, so we can't rely + // on a timeout from a remote device, because there may not be one connected + RPointerArray& deviceArray = StateMachine().Devices(); + for(TInt i = 0; i < deviceArray.Count(); ++i) + { + if(deviceArray[i]->GetState() != EPerformingNegotiation) // ie. it's not the device we just failed to get to change role + { + LOG(_L("RoleState: - ...disconnecting non-negotiating device...")); + deviceArray[i]->Disconnect(); + } + } + + LOG(_L("RoleState: - ...setting original device active again and going to U role")); + + // since we're negotiating GN/NAP role, then we must previously have been in U role + __ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(ETooManyDevicesAttachedWhenRenegotiatingActiveConnectionForGnOrNapUpgrade)); // not quite enough to ensure we were previously in U role, but as good as we're going to get + __ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray)); + + // Enter negotiating U role state and wait for the device active + // notification from the remote device state machine + CPanAgtStateBase* nextState = CPanAgtStateNegotiatingURole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==0, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray)); + + + //This function will only be called when device is in EDisconnecting State. + //Remote device state machine will first shutdown itself and then call panagent to + //disconnect this device and remove it from the device array + __ASSERT_DEBUG(aDevice.GetState() == EDisconnecting, PanicInState(EInvalidRemoteDeviceState)); + + LOG(_L("RoleState: - whoops, the remote device we're trying to upgrade has disconnected!")); + DoDeviceDisconnectL(aDevice); // will leave if there are no other devices waiting and we're not accepting incoming connections + + // go back to idle state and start negotiating with the idle device that should be in the array + // there should be one there, as it was the reason that we tried to do role upgrade in the first place! + StartListenerL(); + + CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + + } + +CPanRemoteDeviceStateMachine& CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtOurBehest::FindDeviceInActiveState() +/** +Return the device that is in the active state +@pre There is only one device in an active state +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(EMoreThanOneActiveDeviceWhenTryingToRenegotiateUToGnOrNapRoleChange)); + + RPointerArray& deviceArray = StateMachine().Devices(); + for(TInt i=0;iGetState() == EActive) + { + return (*(deviceArray[i])); + } + } + + PanicInState(ENoActiveDeviceInArray); + // next bit will never be reached, but it keeps the compiler quiet... + CPanRemoteDeviceStateMachine* notUsed = NULL; + return(*notUsed); + } + +// +// CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest +// +CPanAgtStateBase* CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest* self = new (ELeave) CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest) +/** + +*/ + { } + +void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::OnEntryL() +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDeviceInArrayInRenegActConnToURoleAtPeersBehest)); // if we're going to U and we've not got an active device, we're in trouble + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + LOG(_L("RoleState: - entering state")); + + StateMachine().SendProgress(EPanAgtReconfiguringPiconet, KErrNone); + + // we've already had the role request from the remote device in the previous state, so just + // wait for device active or role changed failed + } + +void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aRequestedLocalRole*/, TBluetoothPanRole& /*aRequestedRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice) +/** +We've successfully managed to renegotiate roles with the currenly connected device +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - device active, role change successful")); + + if(aDevice.GetState() == EActive) // we've succeeded in changing role + { + CPanAgtStateBase* nextState = CPanAgtStateURole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + else + { + PanicInState(EUnexpectedDeviceActiveReceivedByState); + } + } + +void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/) +/** +Unlikey this can happen - if we get into this state we've decided we can do the role change. +If this gets called, the remote device state machine is probably doing something dodgy +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDeviceInArrayInRenegActConnToURoleAtPeersBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - role changed failed - strange, the peer must have asked us to go to U role, but for some reason we decided we could, then it turned out we couldn't. Sounds like remote device state machine is doing something dodgy")); + + // we couldn't go to U role (unlikely this can happen) so go back to GN/NAP state + CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +void CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDeviceInArrayInRenegActConnToURoleAtPeersBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - whoops, the remote device we're trying to upgrade has disconnected!")); + DoDeviceDisconnectL(aDevice); // will leave if there are no other devices waiting and we're not accepting incoming connections + + // return to idle (possibly after reregistering local SDP record) - there can't be + // any active devices left attached + StartListenerL(); + + CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +// +// CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest +// +CPanAgtStateBase* CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest* self = new (ELeave) CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest) +/** + +*/ + { } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::OnEntryL() +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtPeersBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - entering state")); + + StateMachine().SendProgress(EPanAgtReconfiguringPiconet, KErrNone); + + // we've already had the role request from the remote device in the previous state, so just + // wait for device active or role changed failed + } + + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aLocalRole*/, TBluetoothPanRole& /*aRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::DeviceActiveL(CPanRemoteDeviceStateMachine& /*aDevice*/) +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtPeersBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - device active received from negotitaing device")); + + CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/) +/** +Unlikey this can happen - if we get into this state we've decided we can do the role change. +If this gets called, the remote device state machine is probably doing something dodgy +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(ENoActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtPeersBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - role changed failed - strange, the peer must have asked us to go to U role, but for some reason we decided we could, then it turned out we couldn't. Sounds like remote device state machine is doing something dodgy")); + + // we couldn't go to GN/NAP role (unlikely this can happen) so go back to U role + CPanAgtStateBase* nextState = CPanAgtStateURole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +void CPanAgtStateRenegotiatingActiveConnectionToGnOrNapRoleAtPeersBehest::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()==1, PanicInState(EActiveDevicesInArrayInRenegActConnToGnOrNapRoleAtOurBehest)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EUnexpectedDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - whoops, the remote device we're trying to upgrade has disconnected!")); + DoDeviceDisconnectL(aDevice); // will leave if there are no other devices waiting and we're not accepting incoming connections + + StartListenerL(); + + CPanAgtStateBase* nextState = CPanAgtStateIdle::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + return; + } + +// +// CPanAgtStateNegotiatingGnOrNapRole +// +CPanAgtStateBase* CPanAgtStateNegotiatingGnOrNapRole::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateNegotiatingGnOrNapRole* self = new (ELeave) CPanAgtStateNegotiatingGnOrNapRole(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateNegotiatingGnOrNapRole::CPanAgtStateNegotiatingGnOrNapRole(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateNegotiatingGnOrNapRole) +/** + +*/ + { } + +CPanAgtStateNegotiatingGnOrNapRole::CPanAgtStateNegotiatingGnOrNapRole(MPanAgtStateMachineNotify& aStateMachine, TPanAgtStates aStateNumber) : + CPanAgtStateBase(aStateMachine, aStateNumber) +/** +When implementing a new state that derives from this base class, ensure that +it provides a unique number to identify the state from other possible +states. @see PanAgent::TPanAgtStates. +*/ + { } + +void CPanAgtStateNegotiatingGnOrNapRole::OnEntryL() +/** +@note Remote device object will make us piconet master +*/ + { + LOG(_L("RoleState: - entering state")); + + if(StateMachine().AllowIncoming()) // stop advertising U service record + { + StateMachine().PanLocalSdpRegistrar().UnregisterLocalSdpRecord(EPanRoleU); + } + } + +void CPanAgtStateNegotiatingGnOrNapRole::InitiateOutgoingConnectionL(TBluetoothPanRole& /*aLocalRole*/, TBluetoothPanRole& /*aRemoteRole*/, TPanDeviceWorthTryingRolesList& /*aWorthTryingRemoteRoles*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + +void CPanAgtStateNegotiatingGnOrNapRole::IncomingConnectionFromPeerL(TBluetoothPanRole /*aLocalRole*/) + { + // Negotiation in progress - Wait... + User::Leave(KErrLocked); + } + + +void CPanAgtStateNegotiatingGnOrNapRole::DeviceActiveL(CPanRemoteDeviceStateMachine& aDevice) +/** +We've completed BNEP negotiation with the remote device successfully +*/ + { + __ASSERT_ALWAYS(FindDeviceInArray(aDevice)>=0, PanicInState(EActiveDeviceThatIsNotInArray)); + __ASSERT_DEBUG(aDevice.GetState() == EActive, PanicInState(EDeviceNotActive)); + + LOG(_L("RoleState: - device active received...")); + + CPanAgtStateBase* nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + +void CPanAgtStateNegotiatingGnOrNapRole::DeviceRoleChangeFailedL(CPanRemoteDeviceStateMachine& /*aDevice*/) +/** +Looks like the remote device asked us to act in a role that we couldn't support +@note This can only be called as part of a role change, not during initial negotiation with a device +*/ + { + __ASSERT_DEBUG(NegotiatingDeviceCount()==1, PanicInState(EMoreThanOneDeviceInNegotiatingModeInArray)); + + LOG(_L("RoleState: - role changed failed - this *might* be triggered by an incoming connection from a remote device asking us to be PAN-U, and we can't because we've got other attached devices")); + + CPanAgtStateBase* nextState = NULL; + nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine()); + + __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet)); + StateMachine().SetState(*nextState); + delete this; + } + +void CPanAgtStateNegotiatingGnOrNapRole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** + +*/ + { + + //This function will only be called when device is in EDisconnecting State. + //Remote device state machine will first shutdown itself and then call panagent to + //disconnect this device and remove it from the device array + __ASSERT_DEBUG(aDevice.GetState() == EDisconnecting, PanicInState(EInvalidRemoteDeviceState)); + + LOG(_L("RoleState: - oops, the remote device we're negotiating with has disconnected")); + // outstanding async request will be cancelled by state machine when we leave + DoDeviceDisconnectL(aDevice); // will leave if there are no more devices connected and we're not accepting incoming connections + + CPanAgtStateBase* nextState = NULL; + if(ActiveDeviceCount()>=1) + { + nextState = CPanAgtStateGnOrNapRole::NewL(StateMachine()); + } + else + { + StartListenerL(); + nextState = CPanAgtStateIdle::NewL(StateMachine()); // will trigger negotiation with idle device + } + __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet)); + StateMachine().SetState(*nextState); + delete this; + return; + + } + + +// +// CPanAgtStateGnOrNapRole +// +CPanAgtStateBase* CPanAgtStateGnOrNapRole::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateGnOrNapRole* self = new (ELeave) CPanAgtStateGnOrNapRole(aStateMachine); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateGnOrNapRole::CPanAgtStateGnOrNapRole(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateGnOrNapRole) +/** + +*/ + { } + +void CPanAgtStateGnOrNapRole::OnEntryL() +/** + +*/ + { + __ASSERT_DEBUG(ActiveDeviceCount()>=1, PanicInState(ENoActiveDeviceAfterNegotiationCompleted)); + __ASSERT_DEBUG(NegotiatingDeviceCount()==0, PanicInState(EDeviceInNegotiatingModeOnEntryToGnOrNapState)); + + LOG1(_L("RoleState: - entering state, %d active devices"), ActiveDeviceCount()); + + if(StateMachine().NapEnabled()) + { + StateMachine().SendProgress(EPanAgtNapRole, KErrNone); + } + else + { + StateMachine().SendProgress(EPanAgtGnRole, KErrNone); + } + + LockDeviceAsPiconetMasterL(); // apply piconet master lock each time we enter this state, to ensure all devices have this set + + // scan the array to see if there are any devices awaiting negotiation, if so, trigger negotiation with one of them + StartNegotiationWithFirstPendingDevice(); + } + +void CPanAgtStateGnOrNapRole::IncomingConnectionFromPeerL(TBluetoothPanRole aLocalRole) + { + if(StateMachine().NapEnabled()) + { + if(aLocalRole != EPanRoleNap) + { + User::Leave(KErrInvalidOrUnacceptableRoleCombination); + } + } + else + { + if(aLocalRole != EPanRoleGn) + { + User::Leave(KErrInvalidOrUnacceptableRoleCombination); + } + } + } + +void CPanAgtStateGnOrNapRole::RoleChangeRequestFromPeerL(TBluetoothPanRole aLocalRole) + { + if(aLocalRole == EPanRoleU) + { + // Check if we can change role. There must be at least one connection. Any more than + // one and we can't change to U role. + if(ActiveDeviceCount() == 1) + { + LOG(_L("RoleState: - ...remote device wants us to be U, accepting")); + + CPanAgtStateBase* nextState = CPanAgtStateRenegotiatingActiveConnectionToURoleAtPeersBehest::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + else + { + // Can't change local role. + User::Leave(KErrInvalidOrUnacceptableRoleCombination); + } + } + else + { + // The local role must be the same as our local role. + // Nothing to do. Accept request and wait for DeviceActive call. + CPanAgtStateBase* nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + } + +void CPanAgtStateGnOrNapRole::InitiateOutgoingConnectionL(TBluetoothPanRole& aLocalRole, TBluetoothPanRole& aRemoteRole, TPanDeviceWorthTryingRolesList& aWorthTryingRemoteRoles) + { + LOG(_L("RoleState: - InitiateOutgoingConnectionL")); + + // There must already be an existing connection (in GN/NAP role). Set the local role to GN/NAP and the + // remote to U + aLocalRole = StateMachine().NapEnabled() ? EPanRoleNap : EPanRoleGn; + + // Check the a connection U role is worth trying + if(aWorthTryingRemoteRoles.IsWorthTryingU()) + { + aRemoteRole = EPanRoleU; + } + else + { + User::Leave(KErrInvalidOrUnacceptableRoleCombination); + } + + CPanAgtStateBase* nextState = CPanAgtStateNegotiatingGnOrNapRole::NewL(StateMachine()); + StateMachine().SetState(*nextState); + delete this; + } + +void CPanAgtStateGnOrNapRole::DeviceActiveL(CPanRemoteDeviceStateMachine& /*aDevice*/) +/** + +*/ + { + // A new device has been added to the bridge. + } + +void CPanAgtStateGnOrNapRole::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** + +*/ + { + LOG(_L("RoleState: - device disconnected...")); + + DoDeviceDisconnectL(aDevice); // if there are no devices in the array and we're not supporting incoming connection this method will leave + + if(StateMachine().Devices().Count()) + { + LOG1(_L("RoleState: - ...%d device(s) remaining - staying in GN role"), StateMachine().Devices().Count()); + // do nothing - need to remain in GN/NAP role + } + else // no devices left - decide what to do next... + { + LOG(_L("RoleState: - ...no devices remaining - choosing next role...")); + CPanAgtStateBase* nextState = NULL; + StartListenerL(); + + LOG(_L("RoleState: - ...incoming connections not being accepted, going to idle state")); + nextState = CPanAgtStateIdle::NewL(StateMachine()); + + __ASSERT_ALWAYS(nextState, PanicInState(ENoNextStateSet)); + StateMachine().SetState(*nextState); + delete this; + return; + } + } + +void CPanAgtStateGnOrNapRole::StateSendRoleNotification() + { + if(StateMachine().NapEnabled()) + { + StateMachine().SendProgress(EPanAgtNapRole, KErrNone); + } + else + { + StateMachine().SendProgress(EPanAgtGnRole, KErrNone); + } + } + +// +// CPanAgtStateShutdown +// +CPanAgtStateBase* CPanAgtStateShutdown::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateShutdown* self = new (ELeave) CPanAgtStateShutdown(aStateMachine); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateShutdown::CPanAgtStateShutdown(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateShutdown) +/** + +*/ + { } + +CPanAgtStateShutdown::~CPanAgtStateShutdown() + { + iShutdownCallback->Cancel(); + delete iShutdownCallback; + } +void CPanAgtStateShutdown::ConstructL() + { + BaseConstructL(); + iShutdownCallback = new (ELeave) CAsyncCallBack(KPanAgtAoPriority); + TCallBack callbackFunc(ShutdownCallback, this); + iShutdownCallback->Set(callbackFunc); + } + +TInt CPanAgtStateShutdown::ShutdownCallback(TAny* aThisPtr) +/** +Callback function to do a full shutdown of the Pan Agent +*/ + { + LOG(_L("RoleState: - shutting down")); + + CPanAgtStateShutdown* self = (CPanAgtStateShutdown*)aThisPtr; + self->StateMachine().FullShutdownComplete(); + return KErrNone; + } + +void CPanAgtStateShutdown::OnEntryL() +/** +Shut all the connections down +*/ + { + LOG(_L("RoleState: - entering state")); + + // Start closing things down, and notify apps that we're shutting down + StateMachine().CloseIncomingConnectionListener(); + StateMachine().SendProgress(EPanAgtDisconnecting, KErrNone); + + // Start disconnecting any attached devices... + RPointerArray& deviceArray = StateMachine().Devices(); + if(deviceArray.Count()==0) // ...no devices attached, shutdown straight away + { + LOG(_L("RoleState: - no devices connected, use callback to shutdown")); + + // Use a Callback function here to allow the connection to process any progress + // before the shutdown is completed. + // This is important if a connection is being created from an IAP entry and + // the connection fails, without allowing the connection to process the progress + // RConnection::Start will never return. + iShutdownCallback->CallBack(); + return; + } + else // ...tell all the attached devices to shut down + { + for(TInt i=0; i < deviceArray.Count(); ++i) + { + deviceArray[i]->Disconnect(); + } + } + } + +void CPanAgtStateShutdown::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** +Remote device has disconnected +@note *** Must not leave from here *** +*/ + { + TRAPD(err, DoDeviceDisconnectL(aDevice)); + if(err==KErrAllDevicesDisconnected) // all devices have disconnected, so we can shutdown now + { + LOG(_L("RoleState: - all devices disconnected, shutting down")); + StateMachine().FullShutdownComplete(); + } + else if(err) + { + LOG1(_L("RoleState: - unknown error %d, shutting down"), err); + StateMachine().FullShutdownComplete(); + } + else if(StateMachine().Devices().Count()==0) + { + LOG(_L("RoleState: - all devices disconnected but incoming connection listener active, stopping it and shutting down")); + StateMachine().FullShutdownComplete(); + } + } + +// +// CPanAgtStateReconnect +// +CPanAgtStateBase* CPanAgtStateReconnect::NewL(MPanAgtStateMachineNotify& aStateMachine) + { + CPanAgtStateReconnect* self = new (ELeave) CPanAgtStateReconnect(aStateMachine); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStateReconnect::CPanAgtStateReconnect(MPanAgtStateMachineNotify& aStateMachine) : + CPanAgtStateBase(aStateMachine, EPanAgtStateReconnect) +/** + +*/ + { } + +CPanAgtStateReconnect::~CPanAgtStateReconnect() + { + iReconnectCompleteCallback->Cancel(); + delete iReconnectCompleteCallback; + } + +void CPanAgtStateReconnect::ConstructL() + { + BaseConstructL(); + iReconnectCompleteCallback = new (ELeave) CAsyncCallBack(KPanAgtAoPriority); + TCallBack reconnectCompleteCallback(ReconnectCompleteCb, this); + iReconnectCompleteCallback->Set(reconnectCompleteCallback); + TCallBack serviceStartedCallback(ServiceStartedCb, this); + iServiceStartedCallback->Set(serviceStartedCallback); + } + +void CPanAgtStateReconnect::OnEntryL() + { + LOG(_L("RoleState: - entering state")); + + StateMachine().CloseIncomingConnectionListener(); + + // Start disconnecting any attached devices... + RPointerArray& deviceArray = StateMachine().Devices(); + if(deviceArray.Count()!=0) // ...no devices attached, shutdown straight away + { + for(TInt i=0; i < deviceArray.Count(); ++i) + { + deviceArray[i]->Disconnect(); + } + } + iReconnectCompleteCallback->CallBack(); + } + +void CPanAgtStateReconnect::Connect() + { + iServiceStartedCallback->CallBack(); + } + +void CPanAgtStateReconnect::CancelReconnect() + { + iReconnectCompleteCallback->Cancel(); + } + +void CPanAgtStateReconnect::DeviceDisconnectedL(CPanRemoteDeviceStateMachine& aDevice) +/** +Remote device has disconnected +*/ + { + DoDeviceDisconnectL(aDevice); + } + +void CPanAgtStateReconnect::ServiceStarted() +/** +@note Don't notify Nifman with ServiceStarted() because that will try to load the packet driver +again which will cause a panic. +*/ + { + LOG(_L("CPanAgtStateBase: Service started")); + + StateMachine().SendProgress(EPanAgtInitialising, KErrNone); + iConnectCompleteCallback->CallBack(); + } + +TInt CPanAgtStateReconnect::ServiceStartedCb(TAny* aThisPtr) +/** +Connection callback function +*/ + { + __ASSERT_DEBUG(aThisPtr, PanAgentPanic(ENullTAnyPointer)); + + CPanAgtStateReconnect* self = static_cast(aThisPtr); + self->ServiceStarted(); + return KErrNone; + } + +TInt CPanAgtStateReconnect::ReconnectCompleteCb(TAny* aThisPtr) +/** +Reconnect callback function +*/ + { + __ASSERT_DEBUG(aThisPtr, PanAgentPanic(ENullTAnyPointer)); + + CPanAgtStateReconnect* self = static_cast(aThisPtr); + self->StateMachine().ReconnectComplete(KErrNone); + return KErrNone; + } + + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY +CPanAgtStatePaused* CPanAgtStatePaused::NewL(MPanAgtStateMachineNotify& aStateMachine, CPanAgtStateBase& aNextState) + { + CPanAgtStatePaused* self = new(ELeave) CPanAgtStatePaused(aStateMachine, aNextState); + CleanupStack::PushL(self); + self->BaseConstructL(); + CleanupStack::Pop(); + return self; + } + +CPanAgtStatePaused::CPanAgtStatePaused(MPanAgtStateMachineNotify& aStateMachine, CPanAgtStateBase& aNextState) + : CPanAgtStateBase(aStateMachine, EPanAgtStatePaused), iNextState(&aNextState) + { + } + +CPanAgtStatePaused::~CPanAgtStatePaused() + { + delete iNextState; + } + +void CPanAgtStatePaused::OnEntryL() + { + // Does nothing + } + +void CPanAgtStatePaused::TransitionToNextState() + { + StateMachine().SetState(*iNextState); + + // We no longer own the next state + iNextState = NULL; + delete this; + } + +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY