diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPStates.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpiputils/dhcp/src/DHCPStates.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,612 @@ +// 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: +// Implements the DHCPv4 States representing each interface +// +// + +/** + @file DHCPStates.cpp + @internalTechnology +*/ + +#include "DHCPStates.h" +#ifdef _DEBUG +#include "DHCPServer.h" +#endif +#ifdef SYMBIAN_ESOCK_V3 +#include +#include +#endif +#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS +#include "DHCPAuthentication.h" //DHCPv4::KReqMaxRetry is defined in this file +#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS +#include "DHCPStatesDebug.h" + +CDHCPState::~CDHCPState() +/** + * Destructor for this state base class + * + * @internalTechnology + */ + { + delete iNext; + } + +CDHCPState* CDHCPState::ProcessAckNakL(TRequestStatus* aStatus) +/** + * Handle acknowledgement and negative acknowlegements + * + * @internalTechnology + */ + { + CDHCPStateMachine& rDHCP = Dhcp(); + return rDHCP.HandleReplyL( aStatus ); + } + +void CDHCPState::Cancel() +/** + * Cancel any pending outstanding request + * + * @internalTechnology + */ + { + } + + + +#ifdef SYMBIAN_ESOCK_V3 +SFactoryChannel::~SFactoryChannel() + { + if ( iC32Root.Handle() ) + { + iC32Root.Close(); + } + } + +void SFactoryChannel::SendMessageL( NetMessages::CMessage& aQuery ) + { + //connect to root server and find an instance + if ( !iC32Root.Handle() ) + { + User::LeaveIfError(iC32Root.Connect()); + } + //send a message to find a channel instance + TInt nLen = aQuery.Length(); + iBuf.Close(); + iBuf.CreateL( nLen ); + TPtr8 ptr( const_cast(iBuf.Ptr()), iBuf.MaxLength() ); + User::LeaveIfError( aQuery.Store( ptr ) ); + iBuf.SetLength( ptr.Length() ); + //this should be very quick so we can afford to hold different interfaces up for a while + //we should really have a solution for servers running each session in a different thread + User::LeaveIfError( iC32Root.SendMessage( iModule, CommsFW::EFactoryMsg, ptr ) ); + TPtrC8 ptrC( ptr ); + User::LeaveIfError( aQuery.GetTypeId().Check( ptrC ) ); + User::LeaveIfError( aQuery.Load( ptrC ) ); + } + +SDhcpSignal::~SDhcpSignal() + { + delete iQuery; + delete iNetSubscribe; + } + +void SDhcpSignal::SubscribeL(const TName& aInterfaceName, TInt aEventId, NetSubscribe::TEvent& aEvent ) + { + iModule.Copy( _L( "ESock_DIP" ) ); + if ( !iQuery ) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("SDhcpSignal::SubscribeL NetMessages::CTypeIdQuery::NewL"))); + iQuery = NetMessages::CTypeIdQuery::NewL(); + iQuery->iUid = IPEvent::KFactoryImplementationUid; + iQuery->iTypeId = IPEvent::KProtocolId; + iQuery->iHandle = NULL; + iQuery->iOid.Copy( aInterfaceName.Left( iQuery->iOid.MaxLength() ) ); + } + if ( !iQuery->iHandle ) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("SDhcpSignal::SubscribeL handle = 0"))); + SFactoryChannel::SendMessageL( *iQuery ); + + STypeId typeId = STypeId::CreateSTypeId( NetSubscribe::KTransportUid, NetSubscribe::EPublishSubscribe ); + ASSERT( !iNetSubscribe ); + iNetSubscribe = NetSubscribe::CNetSubscribe::NewL( typeId ); + + NetSubscribe::SSignalId signalId( IPEvent::KEventImplementationUid, aEventId, iQuery->iHandle ); + aEvent.SubscribeL(*iNetSubscribe, signalId); + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("SDhcpSignal::SubscribeL registered for signal handle = %d"), iQuery->iHandle)); + //and wait for the signal + } + else + {//deregister & release the handle + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("SDhcpSignal::SubscribeL deregister & release the handle"))); + aEvent.Cancel(*iNetSubscribe); + SFactoryChannel::SendMessageL( *iQuery ); + } + } +#endif + +CAsynchEvent* CDHCPAddressAcquisition::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIPAddressAcquisition); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.InitialiseSocketL(); + + rDHCP.CreateDiscoverMsgL(); + + // one second retransmit passed to CloseNsendMsgL + rDHCP.CloseNSendMsgL(KOneSecond,rDHCP.iMaxRetryCount,CDHCPStateMachine::EAllAvailableServers); + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); //move to the next state + return iNext; + } + +CAsynchEvent* CDHCPSelect::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPSelect); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.iReceiving = EFalse; + rDHCP.HandleOfferL(); + rDHCP.CreateOfferAcceptanceRequestMsgL(); + // one second initial retransmit passed to CloseNsendMsgL + rDHCP.CloseNSendMsgL(KOneSecond, rDHCP.iMaxRetryCount, CDHCPStateMachine::EAllAvailableServers); + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); //move to the next state + + return iNext; + } + +CAsynchEvent* CDHCPInformationConfig::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPInformationConfig); + CDHCPStateMachine& rDHCP = Dhcp(); +#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + if (rDHCP.iDhcpInformAckPending) + { + rDHCP.BindSocketForUnicastL(); + } + else + { +#endif// SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + rDHCP.InitialiseSocketL(); +#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + } +#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + rDHCP.CreateInformMsgL(); +#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + if (rDHCP.iDhcpInformAckPending) //new condition added for dynamic dhcp inform message-For IPv4 only + { + rDHCP.CloseNSendMsgL(KOneSecond, DHCPv4::KReqMaxRetry,CDHCPStateMachine::EUnicast); + } + else + { +#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + // one second initial retransmit passed to CloseNsendMsgL + rDHCP.CloseNSendMsgL(KOneSecond, rDHCP.iMaxRetryCount,CDHCPStateMachine::EAllAvailableServers); +#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + } +#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); //move to the next state + return iNext; + } + +CAsynchEvent* CDHCPRebootConfirm::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPRebootConfirm); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.InitialiseSocketL(); + rDHCP.CreateRebootRequestMsgL(); + // one second retransmit passed to CloseNsendMsgL + rDHCP.CloseNSendMsgL(KOneSecond, rDHCP.iMaxRetryCount,CDHCPStateMachine::EAllAvailableServers); + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); //move to the next state + return iNext; + } + +CAsynchEvent* CDHCPRequest::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPRequest); + CDHCPStateMachine& rDHCP = Dhcp(); + if (!rDHCP.iReceiving) + { + return rDHCP.ReceiveL(&aStatus); + } + return ProcessAckNakL(&aStatus); + } + +CAsynchEvent* CDHCPRebind::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPRebind::ProcessL"))); + + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPRebind); + CDHCPStateMachine& rDHCP = Dhcp(); + if (!rDHCP.iReceiving) + { + rDHCP.CreateRebindRequestMsgL(); + // the socket will be closed so as to free up resources... + // therefore we will have to set it up again... + rDHCP.InitialiseSocketL(); + // 10 second initial retransmit passed to CloseNsendMsgL + rDHCP.CloseNSendMsgL(KOneSecond * 10/*10 secs*/,rDHCP.iMaxRetryCount, CDHCPStateMachine::EAllAvailableServers); +// rDHCPIPv4.StartDeltaTimer(iTimeToWait, *this); + return rDHCP.ReceiveL(&aStatus); + } + return ProcessAckNakL(&aStatus); + } + +void CDHCPWaitForDADBind::Cancel() + { + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.CancelTimer(); + + TRequestStatus* p = &iStateMachine->iStatus; + User::RequestComplete(p, KErrCancel); + rDHCP.SetAsyncCancelHandler(NULL); + } + +CAsynchEvent* CDHCPWaitForDADBind::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPWaitForDADBind); + CDHCPStateMachine& rDHCP = Dhcp(); + aStatus = KRequestPending; + rDHCP.SetAsyncCancelHandler(this); + rDHCP.CancelMessageSender(); + iBoundAt.HomeTime(); + rDHCP.StartTimer(TTimeIntervalMicroSeconds32(KHalfSecondInMicroSeconds), *this); // 0.5 sec to wait for TCP/IP6 stack to complete DAD + rDHCP.UpdateHistory(EBinding); + iErr = KErrNone; + return NULL; //no matter what that's the end + } + +void CDHCPWaitForDADBind::TimerExpired() +/** + * Interface function, called by timer when timer has popped + * in this case we try to bind a socket to the source address + * to check that DAD has been resolved by the TCP/IP6 stack. + * If it hasn't then we have to wait for another 2 seconds, + * up to a maximum of 30 seconds... + * There is an improvement to this, by checking the status + * of the route for the interface...no time to implement this + * improvement, but it would be more robust to have it as + * this would enable differentiation between when DAD has not been + * resolved and when it has found a duplicate address...which the + * current method does not allow, as the bind will only return KErrNotFound + * if the source address is not recognised...would still have to poll though... + * + * @internalTechnology + */ + { + CDHCPStateMachine& rDHCP = Dhcp(); + + +#ifdef _DEBUG + if (CDHCPServer::DebugFlags() & KDHCP_Dad) + { + iErr = KErrNotFound; // simulate a duplicate address + // but we only want to do this once... + // so reset the debug flag + CDHCPServer::DebugFlags() &= ~KDHCP_Dad; + } + else +#endif + { + iErr = rDHCP.BindToSource(); + if (iErr!=KErrNone) + { + TTime now; + now.HomeTime(); + TTimeIntervalSeconds thirtySeconds(30); + if ((now-thirtySeconds) something's gone wrong => no response from IP notifier + TRequestStatus* p = &iStateMachine->iStatus; + User::RequestComplete(p, KErrTimedOut); + } +#endif + +CAsynchEvent* CDHCPRenew::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPRenew); + CDHCPStateMachine& rDHCP = Dhcp(); + if (!rDHCP.iReceiving) + { + rDHCP.CreateRenewRequestMsgL(); + // the socket will be closed so as to free up resources... + // therefore we will have to set it up again... + rDHCP.BindSocketForUnicastL(); + // 10 second initial retransmit passed to CloseNsendMsgL + rDHCP.CloseNSendMsgL(KOneSecond * 10/*10 secs*/, rDHCP.iMaxRetryCount, CDHCPStateMachine::EUnicast); + return rDHCP.ReceiveL(&aStatus); + } + return ProcessAckNakL(&aStatus); + } + +CAsynchEvent* CDHCPRelease::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPRelease); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.CreateReleaseMsgL(); + rDHCP.InitialiseSocketL(); + // the socket will be closed so as to free up resources... + // therefore we will have to set it up again... + rDHCP.BindSocketForUnicastL(); + rDHCP.CloseNSendMsgL( aStatus, CDHCPStateMachine::EUnicast); + return iNext; + } + + + +CAsynchEvent* CDHCPDecline::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPDecline); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.CreateDeclineMsgL(); + // need to open a new socket to broadcast a decline + // as the old socket has been closed and then used to + // try to bind to source address... + rDHCP.InitialiseSocketL(); + rDHCP.CloseNSendMsgL(aStatus, CDHCPStateMachine::EAllAvailableServers); + return iNext; + } + +#ifdef SYMBIAN_NETWORKING_DHCPSERVER +CAsynchEvent* CDHCPWaitForClientMsgs::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPWaitForClientMsgs::ProcessL"))); + + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPWaitForClientMsgs); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.iReceiving = EFalse; + rDHCP.InitialiseServerSocketL(); + rDHCP.ReceiveOnPort67L(&aStatus); + + return iNext; + } + + +CAsynchEvent* CDHCPHandleClientMsgs::ProcessL(TRequestStatus&/* aStatus*/) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + return iNext; + } + + +CAsynchEvent* CDHCPProvideOffer::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPProvideOffer); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.CreateOfferMsgL(); + rDHCP.CloseNSendServerMsgL(aStatus, CDHCPStateMachine::EAllAvailableServers); + return iNext; + } + +CAsynchEvent* CDHCPSendRequestResponse::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPSendAckNak); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.HandleRequestMsgL(); + rDHCP.InitialiseServerSocketL(); + + if(rDHCP.IsClientIdentified()) + { + rDHCP.CloseNSendServerMsgL(aStatus, CDHCPStateMachine::EUnicast); + rDHCP.iSvrSpecificState = ESvrRenewInProgress; + } + else + { + rDHCP.CloseNSendServerMsgL(aStatus, CDHCPStateMachine::EAllAvailableServers); + rDHCP.iSvrSpecificState = ESvrDiscoverInProgress; + } + + rDHCP.SetClientIdentified(ETrue); + return iNext; + } + +CAsynchEvent* CDHCPSendInformResponse::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPSendAckNak); + CDHCPStateMachine& rDHCP = Dhcp(); + + rDHCP.HandleInformMsgL(); + rDHCP.InitialiseServerSocketL(); + + //Sends DHCPAck only the Client NetworkId is same as the Server's NetworkId + if(rDHCP.CheckNetworkId()) + { + rDHCP.CloseNSendServerMsgL(aStatus, CDHCPStateMachine::EUnicast); + rDHCP.SetClientIdentified(ETrue); + rDHCP.iSvrSpecificState = ESvrInformInProgress; + } + else + { + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); + } + return iNext; + } + +CAsynchEvent* CDHCPHandleRelease::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ProcessReleaseL"))); + CDHCPStateMachine& rDHCP = Dhcp(); + + rDHCP.SetClientIdentified(EFalse); + rDHCP.iSvrSpecificState = ESvrReleaseInProgress; + + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); + return iNext; + } + +CAsynchEvent* CDHCPHandleDecline::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ProcessReleaseL"))); + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.SetClientIdentified(EFalse); + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); + return iNext; + } + +void CDHCPBindServer::Cancel() + { + CDHCPStateMachine& rDHCP = Dhcp(); + rDHCP.CancelTimer(); + + TRequestStatus* p = &iStateMachine->iStatus; + User::RequestComplete(p, KErrCancel); + rDHCP.SetAsyncCancelHandler(NULL); + } + +CAsynchEvent* CDHCPBindServer::ProcessL(TRequestStatus& aStatus) +/** + * Interface function, execute state machine + * + * @internalTechnology + */ + { + CDHCPStateMachine& rDHCP = Dhcp(); + aStatus = KRequestPending; + rDHCP.SetAsyncCancelHandler(this); + rDHCP.CancelMessageSender(); + + TInt err = rDHCP.BindServerInterface(); + if(KErrNone == err) + { + TRequestStatus* p = &aStatus; + User::RequestComplete(p, KErrNone); + rDHCP.SetAsyncCancelHandler(NULL); + } + else + rDHCP.StartTimer(TTimeIntervalMicroSeconds32(KHalfSecondInMicroSeconds), *this); // 0.5 sec to wait for TCP/IP6 stack to complete Bind + + iErr = KErrNone; + return NULL; //no matter what that's the end + } + +void CDHCPBindServer::TimerExpired() +/** + * Interface function, called by timer when timer has popped + * in this case we try to bind the server socket to the static IP address from comms database. + * If the bind fails then we have to wait for another 2 seconds, + * up to a maximu of 30 seconds... + * + * @internalTechnology + */ + { + CDHCPStateMachine& rDHCP = Dhcp(); + iErr = rDHCP.BindServerInterface(); + + if(iErr != KErrNone) + { + rDHCP.StartTimer(TTimeIntervalMicroSeconds32(KHalfSecondInMicroSeconds), *this); // 0.5 sec to wait for TCP/IP6 stack to complete Bind + } + } + +#endif // SYMBIAN_NETWORKING_DHCPSERVER