--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/localconnectivityservice/dun/utils/src/DunChanMan.cpp Tue Aug 31 16:03:15 2010 +0300
@@ -0,0 +1,577 @@
+/*
+* Copyright (c) 2006-2008 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: RComm channel management related functionality (waiter)
+*
+*/
+
+
+#include "DunSignalWaiter.h"
+#include "DunDataWaiter.h"
+#include "DunUpstream.h"
+#include "DunDownstream.h"
+#include "DunSignalCopy.h"
+#include "DunChanMan.h"
+#include "DunUtils.h"
+#include "DunDebug.h"
+#include "DunPlugin.h"
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CDunChanMan* CDunChanMan::NewL( CDunTransporter& aParent,
+ MDunTransporterUtility* aUtility,
+ MDunTransporterUtilityAux* aUtilityAux,
+ MDunPluginManager* aPluginManager )
+ {
+ CDunChanMan* self = new (ELeave) CDunChanMan( aParent,
+ aUtility,
+ aUtilityAux,
+ aPluginManager );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CDunChanMan::~CDunChanMan()
+ {
+ FTRACE(FPrint( _L("CDunChanMan::~CDunChanMan()") ));
+ ResetData();
+ FTRACE(FPrint( _L("CDunChanMan::~CDunChanMan() complete") ));
+ }
+
+// ---------------------------------------------------------------------------
+// Resets data to initial values
+// ---------------------------------------------------------------------------
+//
+void CDunChanMan::ResetData()
+ {
+ FTRACE(FPrint( _L("CDunChanMan::ResetData()") ));
+ // APIs affecting this:
+ // AddConnWaiterL()
+ // IssueConnWaiterRequest()
+ TInt i;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ DeleteWaiters( i );
+ }
+ iWaiterData.Close();
+ FTRACE(FPrint( _L("CDunChanMan::ResetData() complete") ));
+ }
+
+// ---------------------------------------------------------------------------
+// Number of waiters
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::NumberOfWaiters()
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NumberOfWaiters()" )));
+ TInt waiters = iWaiterData.Count();
+ FTRACE(FPrint( _L("CDunChanMan::NumberOfWaiters() complete" )));
+ return waiters;
+ }
+
+// ---------------------------------------------------------------------------
+// Gets number of waiters by owner UID
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::GetNumberOfWaitersByUid( TUid aOwnerUid )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::GetNumberOfWaitersByUid()" )));
+ TInt i;
+ TInt waiters = 0;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ TDunWaiterData& waiterData = iWaiterData[i];
+ if ( waiterData.iOwnerUid == aOwnerUid )
+ {
+ waiters++;
+ }
+ }
+ FTRACE(FPrint( _L("CDunChanMan::GetNumberOfWaitersByUid() complete" )));
+ return waiters;
+ }
+
+// ---------------------------------------------------------------------------
+// Adds new connection waiter to connection waiter array
+// ---------------------------------------------------------------------------
+//
+void CDunChanMan::AddConnWaiterL( RComm* aComm,
+ TUid aOwnerUid,
+ const TDesC8& aName,
+ TBool aEnqueuedFail,
+ MDunBufferCorrection* aCorrection )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::AddConnWaiterL()" )));
+ if ( !aComm )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::AddConnWaiterL() (aComm not initialized!) complete" )));
+ User::Leave( KErrGeneral );
+ }
+ CDunSignalWaiter* signalWaiter = CDunSignalWaiter::NewL( this );
+ CleanupStack::PushL( signalWaiter );
+ TInt retTemp = signalWaiter->SetMedia( aComm );
+ if ( retTemp != KErrNone )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::AddConnWaiterL() (ERROR) complete" )));
+ User::Leave( retTemp );
+ }
+ CDunDataWaiter* dataWaiter = CDunDataWaiter::NewL( this );
+ CleanupStack::PushL( dataWaiter );
+ retTemp = dataWaiter->SetMedia( aComm );
+ if ( retTemp != KErrNone )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::AddConnWaiterL() (ERROR) complete" )));
+ User::Leave( retTemp );
+ }
+ TDunWaiterData waiterData;
+ waiterData.iComm = aComm;
+ waiterData.iChannelName = HBufC8::NewMaxL( aName.Length() );
+ TPtr8 chanNamePtr = waiterData.iChannelName->Des();
+ chanNamePtr.Copy( aName );
+ waiterData.iSignalWaiter = signalWaiter;
+ waiterData.iDataWaiter = dataWaiter;
+ waiterData.iCorrection = aCorrection;
+ waiterData.iEnqueuedFail = aEnqueuedFail;
+ waiterData.iOwnerUid = aOwnerUid;
+ iWaiterData.AppendL( waiterData );
+ CleanupStack::Pop( dataWaiter );
+ CleanupStack::Pop( signalWaiter );
+ FTRACE(FPrint( _L("CDunChanMan::AddConnWaiterL() complete" )));
+ }
+
+// ---------------------------------------------------------------------------
+// Removes existing waiter from connection waiter array
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::RemoveConnWaiter( RComm* aComm )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::RemoveConnWaiter()" )));
+ TInt i;
+ for ( i=iWaiterData.Count()-1; i>=0; i-- )
+ {
+ TDunWaiterData& waiterData = iWaiterData[i];
+ if ( waiterData.iComm == aComm )
+ {
+ DeleteWaiters( i );
+ iWaiterData.Remove( i );
+ FTRACE(FPrint( _L("CDunChanMan::RemoveConnWaiter() complete" )));
+ return KErrNone;
+ }
+ }
+ FTRACE(FPrint( _L("CDunChanMan::RemoveConnWaiter() (not found) complete" )));
+ return KErrNotFound;
+ }
+
+// ---------------------------------------------------------------------------
+// Makes CDunConnWaiter ready to detect new data
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::IssueConnWaiterRequest( RComm* aComm )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::IssueConnWaiterRequest()" )));
+ TInt i;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ TDunWaiterData& waiterData = iWaiterData[i];
+ if ( waiterData.iComm == aComm )
+ {
+ waiterData.iSignalWaiter->IssueRequest();
+ waiterData.iDataWaiter->IssueRequest();
+ FTRACE(FPrint( _L("CDunChanMan::IssueConnWaiterRequest() complete" )));
+ return KErrNone;
+ }
+ }
+ FTRACE(FPrint( _L("CDunChanMan::IssueConnWaiterRequest() (not found) complete" )));
+ return KErrNotFound;
+ }
+
+// ---------------------------------------------------------------------------
+// Stops CDunConnWaiter to detect new data
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::StopConnWaiter( RComm* aComm )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::StopConnWaiter()" )));
+ TInt i;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ TDunWaiterData& waiterData = iWaiterData[i];
+ if ( waiterData.iComm == aComm )
+ {
+ waiterData.iSignalWaiter->Stop();
+ waiterData.iDataWaiter->Stop();
+ FTRACE(FPrint( _L("CDunChanMan::StopConnWaiter() complete" )));
+ return KErrNone;
+ }
+ }
+ FTRACE(FPrint( _L("CDunChanMan::StopConnWaiter() (not found) complete" )));
+ return KErrNotFound;
+ }
+
+// ---------------------------------------------------------------------------
+// Saves waiter's connection monitor callback data
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::SaveWaiterConnMonCallbackL( RComm* aComm,
+ MDunConnMon* aCallback,
+ TDunDirection aDirection )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterConnMonCallbackL()" )));
+ TInt i;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ TDunWaiterData& waiterData = iWaiterData[i];
+ if ( waiterData.iComm != aComm )
+ {
+ continue;
+ }
+ TDunConnMonCallback connMon;
+ connMon.iCallback = aCallback;
+ connMon.iDirection = aDirection;
+ if ( aDirection==EDunReaderUpstream ||
+ aDirection==EDunWriterDownstream )
+ {
+ // Local media -> add to object
+ // Add signal waiter's callback (for RunL error monitoring)
+ if ( !waiterData.iSignalWaiter )
+ {
+ FTRACE(FPrint( _L("CDunTransUtils::SaveWaiterConnMonCallbackL() (ERROR) complete" )));
+ return KErrGeneral;
+ }
+ waiterData.iSignalWaiter->AddCallback( aCallback );
+ // Add data waiter's callback (for RunL error monitoring)
+ if ( !waiterData.iDataWaiter )
+ {
+ FTRACE(FPrint( _L("CDunTransUtils::SaveWaiterConnMonCallbackL() (ERROR) complete" )));
+ return KErrGeneral;
+ }
+ waiterData.iDataWaiter->AddCallback( aCallback );
+ // Now just store information for R/W case
+ waiterData.iConnMons.AppendL( connMon );
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterConnMonCallbackL() complete" )));
+ return KErrNone;
+ }
+ else if ( aDirection==EDunWriterUpstream ||
+ aDirection==EDunReaderDownstream )
+ {
+ // Network -> just store information for R/W case
+ waiterData.iConnMons.AppendL( connMon );
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterConnMonCallbackL() complete" )));
+ return KErrNone;
+ }
+ else
+ {
+ FTRACE(FPrint( _L("CDunTransUtils::SaveWaiterConnMonCallbackL() (ERROR) complete" )));
+ return KErrGeneral;
+ }
+ }
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterConnMonCallbackL() (not found) complete" )));
+ return KErrNotFound;
+ }
+
+// ---------------------------------------------------------------------------
+// Saves waiter's skipped error data
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::SaveWaiterSkippedErrorL( TInt aError,
+ RComm* aComm,
+ TDunDirection aDirection )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterSkippedErrorL()" )));
+ TInt i;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ TDunWaiterData& waiterData = iWaiterData[i];
+ if ( waiterData.iComm == aComm )
+ {
+ TDunSkippedError skippedError;
+ skippedError.iError = aError;
+ skippedError.iDirection = aDirection;
+ waiterData.iOkErrors.AppendL( skippedError );
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterSkippedErrorL() complete" )));
+ return KErrNone;
+ }
+ }
+ FTRACE(FPrint( _L("CDunChanMan::SaveWaiterSkippedErrorL() (not found) complete" )));
+ return KErrNotFound;
+ }
+
+// ---------------------------------------------------------------------------
+// CDunChanMan::CDunChanMan
+// ---------------------------------------------------------------------------
+//
+CDunChanMan::CDunChanMan( CDunTransporter& aParent,
+ MDunTransporterUtility* aUtility,
+ MDunTransporterUtilityAux* aUtilityAux,
+ MDunPluginManager* aPluginManager ) :
+ iParent( aParent ),
+ iUtility( aUtility ),
+ iUtilityAux( aUtilityAux ),
+ iPluginManager( aPluginManager )
+ {
+ Initialize();
+ }
+
+// ---------------------------------------------------------------------------
+// CDunChanMan::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CDunChanMan::ConstructL()
+ {
+ FTRACE(FPrint( _L("CDunChanMan::ConstructL()" ) ));
+ if ( !iUtility || !iUtilityAux || !iPluginManager )
+ {
+ User::Leave( KErrGeneral );
+ }
+ FTRACE(FPrint( _L("CDunChanMan::ConstructL() complete" ) ));
+ }
+
+// ---------------------------------------------------------------------------
+// Initializes this class
+// ---------------------------------------------------------------------------
+//
+void CDunChanMan::Initialize()
+ {
+ FTRACE(FPrint( _L("CDunChanMan::Initialize()" ) ));
+ // Don't initialize iParent here (it is set through NewL)
+ // Don't initialize iUtility here (it is set through NewL)
+ // Don't initialize iUtilityAux here (it is set through NewL)
+ // Don't initialize iPluginManager here (it is set through NewL)
+ FTRACE(FPrint( _L("CDunChanMan::Initialize() complete" ) ));
+ }
+
+// ---------------------------------------------------------------------------
+// From class MDunChannelAllocator.
+// Notifies when new channel is wanted
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::NotifyNewChannelRequest( RComm* aComm )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest()" )));
+ if ( !aComm->SubSessionHandle() )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (RComm) (bad handle) complete" ) ));
+ return KErrBadHandle;
+ }
+ // Get plugin UID for connection ID
+ TInt i;
+ TUid foundUid = TUid::Null();
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ if ( iWaiterData[i].iComm == aComm )
+ {
+ foundUid = iWaiterData[i].iOwnerUid;
+ break;
+ }
+ }
+ if ( i >= count )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (RComm) (not found) complete" )));
+ return KErrNotFound;
+ }
+ TDunWaiterData& waiterData = iWaiterData[i];
+ // Try to stop if either one of the waiters are still runnig
+ waiterData.iSignalWaiter->Stop();
+ waiterData.iDataWaiter->Stop();
+ // enqueued will be omitted (not needed to set to RComm)
+ TInt firstFree = iUtility->InitializeFirstFreeChannel( aComm );
+ if ( firstFree < 0 )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (RComm) (firstfree failed!) complete" ) ));
+ return firstFree;
+ }
+ if ( firstFree >= iParent.iChannelData.Count() )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (RComm) (firstfree failed!) complete" )));
+ return KErrGeneral;
+ }
+ TInt bufferLength = KErrNotFound;
+ MDunBufferCorrection* correction = waiterData.iCorrection;
+ TRAPD( retTrap,
+ iUtility->DoAllocateChannelL(aComm, bufferLength, firstFree, correction) );
+ if ( retTrap != KErrNone )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() trapped!" ) ));
+ iParent.UnInitializeOnDemand(); // remove unused initialized channel
+ if ( retTrap == KErrTooBig )
+ {
+ if ( waiterData.iEnqueuedFail )
+ {
+ // Inform plugin enqueue request
+ iPluginManager->NotifyPluginEnqueueRequest( foundUid );
+ }
+ FTRACE(FPrint( _L("CDunTransporter::AllocateChannel() (RSocket) complete" )));
+ return KErrTooBig;
+ }
+ iPluginManager->NotifyPluginCloseRequest( foundUid, EFalse );
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (ERROR) complete" )));
+ return retTrap;
+ }
+ TInt retTemp = CDunUtils::SetRCommBufferLength( *aComm, bufferLength );
+ if ( retTemp != KErrNone )
+ {
+ iParent.UnInitializeOnDemand(); // remove unused initialized channel
+ iPluginManager->NotifyPluginCloseRequest( foundUid, EFalse );
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (ERROR) complete" )));
+ }
+ // Next find aComm from iWaiterData and copy its contents to channel data
+ retTemp = FillNewWaiterChannelData( aComm, firstFree );
+ if ( retTemp != KErrNone )
+ {
+ iParent.UnInitializeOnDemand(); // remove unused initialized channel
+ iPluginManager->NotifyPluginCloseRequest( foundUid, EFalse );
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (RComm) (not found) complete" )));
+ }
+ FTRACE(FPrint( _L("CDunChanMan::NotifyNewChannelRequest() (RComm) complete" )));
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Fills data for channel created by waiter
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::FillNewWaiterChannelData( RComm* aComm,
+ TInt aFirstFree )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::FillNewWaiterChannelData()" )));
+ TInt i;
+ TInt count = iWaiterData.Count();
+ for ( i=0; i<count; i++ )
+ {
+ if ( iWaiterData[i].iComm == aComm )
+ {
+ break;
+ }
+ }
+ if ( i >= count ||
+ aFirstFree < 0 ||
+ aFirstFree >= iParent.iChannelData.Count() )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::FillNewWaiterChannelData() (not found) complete" )));
+ return KErrNotFound;
+ }
+ TUid thisUid = iWaiterData[i].iOwnerUid; // pick up before remove
+ TDunChannelData& channelData = iParent.iChannelData[aFirstFree];
+ TDunWaiterData& waiterData = iWaiterData[i];
+ channelData.iComm = waiterData.iComm;
+ channelData.iChannelName = waiterData.iChannelName;
+ channelData.iUpstreamRW->SetMedia( aComm, EDunMediaContextLocal );
+ channelData.iDownstreamRW->SetMedia( aComm, EDunMediaContextLocal );
+ channelData.iOwnerUid = thisUid;
+ // Channel now occupied
+ channelData.iChannelInUse = ETrue;
+ // Restore data from waiter to transfer objects
+ RestoreWaiterData( i, aFirstFree );
+ // Now delete waiters before request issuing
+ DeleteWaiters( i, ETrue );
+ iWaiterData.Remove( i );
+ // Issue transfer requests
+ iUtility->DoIssueTransferRequests( aFirstFree );
+ // Clear the queue, just to be sure
+ iPluginManager->NotifyPluginDequeueRequest( thisUid );
+ FTRACE(FPrint( _L("CDunChanMan::FillNewWaiterChannelData() complete" )));
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Restores saved waiter data to connection data
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::RestoreWaiterData( TInt aWaiterIndex,
+ TInt aChannelIndex )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::RestoreWaiterData()" )));
+ if ( aWaiterIndex < 0 ||
+ aWaiterIndex >= iWaiterData.Count() ||
+ aChannelIndex < 0 ||
+ aChannelIndex >= iParent.iChannelData.Count() )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::RestoreWaiterData() (not found) complete" )));
+ return KErrNotFound;
+ }
+ TInt i;
+ TInt count = iWaiterData[aWaiterIndex].iConnMons.Count();
+ for ( i=0; i<count; i++ )
+ {
+ TDunConnMonCallback& connMon = iWaiterData[aWaiterIndex].iConnMons[i];
+ // Add connection monitor callbacks (ignore errors)
+ // Errors are ignored because in this phase they cannot be reported to
+ // plugins. Instead add error checking to
+ // CDunTransporter::AddConnMonCallbackL() if needed
+ iUtility->DoAddConnMonCallback( aChannelIndex,
+ connMon.iCallback,
+ connMon.iDirection,
+ NULL );
+ }
+ count = iWaiterData[aWaiterIndex].iOkErrors.Count();
+ for (i=0; i<count; i++)
+ {
+ TDunSkippedError& skippedError = iWaiterData[aWaiterIndex].iOkErrors[i];
+ // Add skipped errors (ignore errors)
+ // Errors are ignored because in this phase they cannot be reported to
+ // plugins. Instead add error checking to
+ // CDunTransporter::AddSkippedErrorL() if needed
+ iUtility->DoAddSkippedError( aChannelIndex,
+ skippedError.iError,
+ skippedError.iDirection );
+ }
+ FTRACE(FPrint( _L("CDunChanMan::RestoreWaiterData() complete" )));
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Deletes waiter objects of aIndex:th waiters
+// ---------------------------------------------------------------------------
+//
+TInt CDunChanMan::DeleteWaiters( TInt aIndex, TBool aNewOwnership )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::DeleteWaiters()" )));
+
+ if ( aIndex < 0 ||
+ aIndex >= iWaiterData.Count() )
+ {
+ FTRACE(FPrint( _L("CDunChanMan::DeleteWaiters() (not found) complete" )));
+ return KErrNotFound;
+ }
+
+ TDunWaiterData& waiterData = iWaiterData[aIndex];
+ if ( !aNewOwnership )
+ {
+ delete waiterData.iChannelName;
+ }
+ waiterData.iChannelName = NULL;
+ delete waiterData.iSignalWaiter;
+ waiterData.iSignalWaiter = NULL;
+ delete waiterData.iDataWaiter;
+ waiterData.iDataWaiter = NULL;
+
+ waiterData.iConnMons.Close();
+ waiterData.iOkErrors.Close();
+
+ FTRACE(FPrint( _L("CDunChanMan::DeleteWaiters() complete" )));
+ return KErrNone;
+ }