diff -r 000000000000 -r 29b1cd4cb562 bluetoothcommsprofiles/btpan/panagt/panagtincoming.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothcommsprofiles/btpan/panagt/panagtincoming.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,342 @@ +// 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: +// panincoming.cpp +// +// + +/** + @file + @note PAN agent incoming connection listener implementation +*/ + +#include +#include +#include +#include +#include "panagtincoming.h" +#include "panagtpolicy.h" +#include "panagtutils.h" + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT); +#endif + +using namespace PanAgent; + +CPanIncomingConnectionListener* CPanIncomingConnectionListener::NewL(MIncomingConnectionAcceptor& aAcceptor) +/** +Create a new instance of the class +@param aAcceptor The class to notify when a new connection is received +@return A pointer to the new CPanIncomingConnectionListener, or NULL if it could not be created +*/ + { + CPanIncomingConnectionListener* self = new(ELeave) CPanIncomingConnectionListener(aAcceptor); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return(self); + } + +CPanIncomingConnectionListener::CPanIncomingConnectionListener(MIncomingConnectionAcceptor& aAcceptor) : + CActive(KPriorityIncomingListenerAo), iAcceptor(aAcceptor) +/** +Not much to do here +*/ + { } + +CPanIncomingConnectionListener::~CPanIncomingConnectionListener() +/** +Close all the sockets +*/ + { + Cancel(); + + iAcceptingSocket.Close(); + iListeningSocket.Close(); + iListeningSocketIsOpen = EFalse; + + delete iDelayedOpenHelper; + } + +void CPanIncomingConnectionListener::ConstructL() +/** + +*/ + { + CActiveScheduler::Add(this); + + iDelayedOpenHelper = CPanIncomingSocketDelayedOpenHelper::NewL(*this); + + OpenListeningSocketL(); + User::LeaveIfError(iAcceptingSocket.Open()); + iListeningSocket.Accept(iAcceptingSocket, iStatus); + + LOG(_L("IncomingConnectionListener: Incoming socket started and ready to accept connections")); + + SetActive(); + } + +TBool CPanIncomingConnectionListener::IsAcceptingSocketOpen() const +/** +Is there an accepting socket open? +*/ + { + return(IsActive()); // if we're active, then we must have an outstanding Accept() + } + + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY +/** +Notify the main class of the incoming connection +*/ +void CPanIncomingConnectionListener::RunL() + { + if(iStatus == KErrNone) + { + LOG(_L("IncomingConnectionListener: ...connection completed successfully, handing connected device off to agent core.")); + + TRAPD(err, iAcceptor.CreateNewConnectionFromIncomingL(iAcceptingSocket)); // if successful, the socket is transferred away from us here, so a "null" socket is all we have left... + if (err != KErrNone) + { + // Something has failed before the message could be sent + // so we execute the remainder of the RunL logic synchronously + RestartIncomingConnectionListener(err); + } + // else { + // The rest of the RunL logic is executed asynchonously in + // RestartIncomingConnectionListener() once BNEP has responded + // to the TCreateChannelController message + // } + } + else // check what went wrong + { + LOG1(_L("IncomingConnectionListener: ...connection completed with error %d"), iStatus.Int()); + iDelayedOpenHelper->SocketOpenFailed(); + } + } + +void CPanIncomingConnectionListener::RestartIncomingConnectionListener(TInt aError) + { + // ...otherwise we still have a "live" socket + if(aError) // for some reason the connection could not be completed, so we'll just have to close the socket + { // it's possible that the device is already connected + LOG(_L("IncomingConnectionListener: ...error - could not hand off socket to agent core, closing socket instead.")); + iAcceptingSocket.Close(); + } + + // create a new accepting socket... + TInt err = iAcceptingSocket.Open(); + if(err) // esp. likely if we've just got KErrNoMemory as the last error + { + LOG(_L("IncomingConnectionListener: ...could not open new accepting socket. Will try again later.")); + iDelayedOpenHelper->SocketOpenFailed(); + } + else + { + LOG(_L("IncomingConnectionListener: ...requeing listening socket...")); + + // ...and repeat the cycle + iListeningSocket.Accept(iAcceptingSocket, iStatus); + SetActive(); + } + } + +#else +// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + +void CPanIncomingConnectionListener::RunL() +/** +Notify the main class of the incoming connection +*/ + { + if(iStatus==KErrNone) + { + LOG(_L("IncomingConnectionListener: ...connection completed successfully, handing connected device off to agent core.")); + + TRAPD(err, iAcceptor.CreateNewConnectionFromIncomingL(iAcceptingSocket)); // if successful, the socket is transferred away from us here, so a "null" socket is all we have left... + + // ...otherwise we still have a "live" socket + if(err) // for some reason the connection could not be completed, so we'll just have to close the socket + { // it's possible that the device is already connected + LOG(_L("IncomingConnectionListener: ...error - could not hand off socket to agent core, closing socket instead.")); + iAcceptingSocket.Close(); + } + + // create a new accepting socket... + err = iAcceptingSocket.Open(); + if(err) // esp. likely if we've just got KErrNoMemory as the last error + { + LOG(_L("IncomingConnectionListener: ...could not open new accepting socket. Will try again later.")); + iDelayedOpenHelper->SocketOpenFailed(); + } + else + { + LOG(_L("IncomingConnectionListener: ...requeing listening socket...")); + + // ...and repeat the cycle + iListeningSocket.Accept(iAcceptingSocket, iStatus); + SetActive(); + } + } + else // check what went wrong + { + LOG1(_L("IncomingConnectionListener: ...connection completed with error %d"), iStatus.Int()); + iDelayedOpenHelper->SocketOpenFailed(); + } + } +#endif +// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + +void CPanIncomingConnectionListener::DoCancel() +/** +Cancel the outstanding accept +*/ + { + iListeningSocket.CancelAccept(); + } + +void CPanIncomingConnectionListener::OpenListeningSocketL() +/** +Create and initialise the listening socket +*/ + { +#if defined(_DEBUG) && defined(SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY) + TInt err = iListeningSocket.Open(KBTAddrFamily, KSockSeqPacket, KL2CAP); + __ASSERT_DEBUG(err != KErrBadName, PanAgentPanic(EPanAgtMissingBinding)); + User::LeaveIfError(err); +#else + User::LeaveIfError(iListeningSocket.Open(KBTAddrFamily, KSockSeqPacket, KL2CAP)); +#endif + + // listen on the assigned l2cap port for BNEP + TBTSockAddr incomingConnectionSettings; + incomingConnectionSettings.SetPort(KBnepPsm); + + // read the required security settings from commdb, and use them to set up the listening socket + TBTServiceSecurity incomingSecuritySettings; + incomingSecuritySettings.SetAuthentication(KPanIncomingAuthenticationRequired); + incomingSecuritySettings.SetAuthorisation(KPanIncomingAuthorisationRequired); + incomingSecuritySettings.SetEncryption(KPanIncomingEncryptionRequired); + incomingSecuritySettings.SetUid(KBTPanAuthorisationUid); + incomingConnectionSettings.SetSecurity(incomingSecuritySettings); + + User::LeaveIfError(iListeningSocket.Bind(incomingConnectionSettings)); + + // Set the MTU to the required minimum for BNEP + TUint16 bnepMtu = KBnepMtu; + TPckg mtuBuf(bnepMtu); + User::LeaveIfError(iListeningSocket.SetOpt(KL2CAPInboundMTU, KSolBtL2CAP, mtuBuf)); + User::LeaveIfError(iListeningSocket.SetOpt(KL2CAPNegotiatedOutboundMTU, KSolBtL2CAP, mtuBuf)); + // Register the CoD service - Networking bit (especially relevant for WinXP) + User::LeaveIfError(iListeningSocket.SetOpt(KBTRegisterCodService, KSolBtSAPBase, EMajorServiceNetworking)); + + User::LeaveIfError(iListeningSocket.Listen(KIncomingSockQueueSize)); + iListeningSocketIsOpen = ETrue; + } + +CPanIncomingSocketDelayedOpenHelper* CPanIncomingSocketDelayedOpenHelper::NewL(CPanIncomingConnectionListener& aIncomingConnectionListener) +/** + +*/ + { + CPanIncomingSocketDelayedOpenHelper* self = new(ELeave) CPanIncomingSocketDelayedOpenHelper(aIncomingConnectionListener); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CPanIncomingSocketDelayedOpenHelper::CPanIncomingSocketDelayedOpenHelper(CPanIncomingConnectionListener& aIncomingConnectionListener) : + CTimer(KPriorityIncomingListenerAo), iCurrentTimerPeriod(KMinSocketReopenAttemptInterval), iIncomingConnectionListener(aIncomingConnectionListener) +/** + +*/ + { + CActiveScheduler::Add(this); + } + +void CPanIncomingSocketDelayedOpenHelper::ConstructL() +/** + +*/ + { + CTimer::ConstructL(); + } + +CPanIncomingSocketDelayedOpenHelper::~CPanIncomingSocketDelayedOpenHelper() +/** +Nothing to do +*/ + { + + } + +void CPanIncomingSocketDelayedOpenHelper::SocketOpenFailed() +/** +A socket open has failed, so it's now up to us to keep retrying +*/ + { + After(iCurrentTimerPeriod); + } + +void CPanIncomingSocketDelayedOpenHelper::RunL() +/** +Attempt to open the listening socket (if necessary) and the accepting socket +*/ + { + // check that the accepting (and therefore by inference the listening) sockets aren't open already + __ASSERT_DEBUG(!(iIncomingConnectionListener.IsAcceptingSocketOpen()), PanAgentPanic(EDelayedOpenHelperActiveWhenBothListeningAndAcceptingSocketsAreOpen)); + + TInt err; + if(!(iIncomingConnectionListener.IsListeningSocketOpen())) + { + TRAP(err, iIncomingConnectionListener.OpenListeningSocketL()); + if(err) // failed to open listening socket, back off and try again later + { + SetNewTimerPeriod(); + After(iCurrentTimerPeriod); // will set us active + return; + } + } + + if(!(iIncomingConnectionListener.IsAcceptingSocketOpen())) + { + err = iIncomingConnectionListener.iAcceptingSocket.Open(); + if(err) // failed to open accepting socket, back off and try again later + { + SetNewTimerPeriod(); + After(iCurrentTimerPeriod); // will set us active + return; + } + else + { + iIncomingConnectionListener.iListeningSocket.Accept(iIncomingConnectionListener.iAcceptingSocket, iIncomingConnectionListener.iStatus); + iIncomingConnectionListener.SetActive(); + return; + } + } + } + +void CPanIncomingSocketDelayedOpenHelper::SetNewTimerPeriod() +/** +Set the timer period to a new value - doubles each time up to the limit +*/ + { + iCurrentTimerPeriod = iCurrentTimerPeriod.Int() * 2; + + if(iCurrentTimerPeriod > TTimeIntervalMicroSeconds32(KMaxSocketReopenAttemptInterval)) // this happens rarely enough (once per many secs to minutes) to take the hit of constructing a new object each time + { + iCurrentTimerPeriod = KMaxSocketReopenAttemptInterval; + } + }