bluetoothcommsprofiles/btpan/panagt/panagtincoming.cpp
author jontanne
Thu, 14 Oct 2010 11:30:12 +0100
changeset 27 83036355c0f3
parent 0 29b1cd4cb562
permissions -rw-r--r--
Add USB HCTL to bt package

// 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 <bluetooth/logger.h>
#include <bt_sock.h>
#include <comms-infras/eintsock.h>
#include <networking/panuiinterfaces.h>
#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<TUint16> 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;
		}
	}