bluetoothcommsprofiles/btpan/panagt/panagtincoming.cpp
changeset 0 29b1cd4cb562
--- /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 <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;
+		}
+	}