localconnectivityservice/dun/utils/src/DunChanMan.cpp
branchRCL_3
changeset 19 0aa8cc770c8a
--- /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;
+    }