localconnectivityservice/dun/plugins/src/bt/DunBtPlugin.cpp
branchRCL_3
changeset 19 0aa8cc770c8a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/localconnectivityservice/dun/plugins/src/bt/DunBtPlugin.cpp	Tue Aug 31 16:03:15 2010 +0300
@@ -0,0 +1,582 @@
+/*
+* 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:  DUN Bluetooth plugin
+*
+*/
+
+
+#include <bt_sock.h>
+#include <c32comm.h>
+#include "DunPlugin.h"
+#include "DunBtListen.h"
+#include "DunBtPlugin.h"
+#include "DunDebug.h"
+#include "DunTransporter.h"
+
+_LIT( KBtChannelName, "DUNBT::"  );
+
+const TInt KCharactersInTInt = 10;  // For "2147483648"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CDunBtPlugin::CDunBtPlugin()
+// ---------------------------------------------------------------------------
+//
+CDunBtPlugin::CDunBtPlugin() :
+    iServer( NULL ),
+    iBTListen( NULL ),
+    iTransporter( NULL )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CDunBtPlugin::~CDunBtPlugin()
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::~CDunBtPlugin()" ) ));
+    Uninitialize();
+    FTRACE(FPrint( _L( "CDunBtPlugin::~CDunBtPlugin() complete" ) ));
+    }
+
+// ---------------------------------------------------------------------------
+// State of this plugin
+// ---------------------------------------------------------------------------
+//
+TDunPluginState CDunBtPlugin::PluginState()
+    {
+    return iServer->GetPluginStateByUid( KDunBtPluginUid );
+    }
+
+// ---------------------------------------------------------------------------
+// Constructs a listener object for this plugin
+// ---------------------------------------------------------------------------
+//
+void CDunBtPlugin::ConstructListenerL()
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::ConstructListenerL()")));
+    if ( PluginState() != EDunStateLoaded )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::ConstructListenerL() (not ready) complete")));
+        User::Leave( KErrNotReady );
+        }
+    ReportStateChangeUp( EDunStateTryListen );
+    if ( iBTListen )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::ConstructListenerL() (already exists) complete")));
+        User::Leave( KErrAlreadyExists );
+        }
+    CDunBtListen* listen = CDunBtListen::NewL( iServer,
+                                               this,
+                                               iTransporter,
+                                               iEntity );
+    CleanupStack::PushL( listen );
+    listen->IssueRequestL();
+    CleanupStack::Pop( listen );
+    iBTListen = listen;
+    ReportStateChangeUp( EDunStateListening );
+    FTRACE(FPrint(_L("CDunBtPlugin::ConstructListenerL() complete")));
+    }
+
+// ---------------------------------------------------------------------------
+// Sets new state
+// New state must be one more than the old state
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::ReportStateChangeUp( TDunPluginState aPluginState )
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::ReportStateChangeUp()")));
+    TInt retTemp = iServer->NotifyPluginStateChangeUp( aPluginState,
+                                                       KDunBtPluginUid );
+    if ( retTemp != KErrNone )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::ReportStateChangeUp() (ERROR) complete")));
+        return retTemp;
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::ReportStateChangeUp() complete")));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Sets new state
+// New state must be one less than the old state
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::ReportStateChangeDown( TDunPluginState aPluginState )
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::ReportStateChangeDown()")));
+    TInt retTemp = iServer->NotifyPluginStateChangeDown( aPluginState,
+                                                         KDunBtPluginUid );
+    if ( retTemp != KErrNone )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::ReportStateChangeDown() (ERROR) complete")));
+        return retTemp;
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::ReportStateChangeDown() complete")));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Allocates a free channel
+// ---------------------------------------------------------------------------
+//
+void CDunBtPlugin::AllocateChannelL( TBool& aNoFreeChans,
+                                     TBtCleanupInfo& aCleanupInfo )
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::AllocateChannelL()")));
+    // iDataSocket has new data socket information so copy it to iBTPorts
+    TBtPortEntity* foundEntity = NULL;
+    TInt foundIndex = GetFirstFreePort( foundEntity );
+    if ( !foundEntity )  // free not found so add new
+        {
+        TBtPortEntity newEntity;
+        iBTPorts.AppendL( newEntity );
+        aCleanupInfo.iNewEntity = ETrue;
+        aCleanupInfo.iEntityIndex = iBTPorts.Count() - 1;
+        foundEntity = &iBTPorts[ aCleanupInfo.iEntityIndex ];
+        }
+    else  // free found so change array
+        {
+        aCleanupInfo.iNewEntity = EFalse;
+        aCleanupInfo.iEntityIndex = foundIndex;
+        foundEntity = &iBTPorts[ foundIndex ];
+        }
+    foundEntity->iChannelNum = iEntity.iChannelNum;
+    foundEntity->iBTPort = iEntity.iBTPort;
+    RSocket* socket = &foundEntity->iBTPort;
+    HBufC8* channelName = HBufC8::NewMaxLC( KBtChannelName().Length() +
+                          KCharactersInTInt );
+    TPtr8 channelNamePtr = channelName->Des();
+    channelNamePtr.Copy( KBtChannelName );
+    channelNamePtr.AppendNum( iEntity.iChannelNum );
+    iTransporter->AllocateChannelL( socket,
+                                    KDunBtPluginUid,
+                                    channelNamePtr,
+                                    EFalse,
+                                    aNoFreeChans );
+    iTransporter->AddConnMonCallbackL( socket,
+                                       this,
+                                       EDunReaderUpstream,
+                                       EFalse );
+    iTransporter->AddConnMonCallbackL( socket,
+                                       this,
+                                       EDunWriterUpstream,
+                                       EFalse );
+    iTransporter->AddConnMonCallbackL( socket,
+                                       this,
+                                       EDunReaderDownstream,
+                                       ETrue );
+    iTransporter->AddConnMonCallbackL( socket,
+                                       this,
+                                       EDunWriterDownstream,
+                                       EFalse );
+    iTransporter->IssueTransferRequestsL( socket );
+    CleanupStack::PopAndDestroy( channelName );
+    FTRACE(FPrint(_L("CDunBtPlugin::AllocateChannelL() complete")));
+    }
+
+// ---------------------------------------------------------------------------
+// Frees an existing channel
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::FreeChannels()
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::FreeChannels()")));
+    if ( PluginState() != EDunStateTryUninitialize )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::FreeChannels() (not ready) complete")));
+        return KErrNotReady;
+        }
+    TInt i;
+    TInt count = iBTPorts.Count();
+    for ( i=0; i<count; i++ )
+        {
+        if ( iBTPorts[i].iBTPort.SubSessionHandle() )
+            {
+            iTransporter->FreeChannel( &iBTPorts[i].iBTPort );
+            iBTPorts[i].iBTPort.Close();
+            // All channels freed and this is for Uninitialize() so don't touch
+            // advertisement monitor here!
+            }
+        iBTPorts[i].iChannelNum = KErrNotFound;
+        }
+    iBTPorts.Close();
+    FTRACE(FPrint(_L("CDunBtPlugin::FreeChannels() complete")));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Uninitializes this plugin
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::Uninitialize()
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::Uninitialize()" ) ));
+    ReportStateChangeDown( EDunStateTryUninitialize );
+    // Free channels (ignore errors)
+    FreeChannels();
+    // Delete listening object (also advertisement monitor)
+    delete iBTListen;
+    iBTListen = NULL;
+    // Set state back to loaded
+    ReportStateChangeUp( EDunStateUninitialized );
+    ReportStateChangeUp( EDunStateTryLoad );
+    ReportStateChangeUp( EDunStateLoaded );
+    FTRACE(FPrint( _L( "CDunBtPlugin::Uninitialize() complete" ) ));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Gets port's index and entity by connection ID
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::GetPortByConnId( TConnId aConnId, TBtPortEntity*& aEntity )
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::GetPortByConnId()")) );
+    TInt i;
+    TInt count = iBTPorts.Count();
+    for ( i=0; i<count; i++ )
+        {
+        if ( &iBTPorts[i].iBTPort == aConnId )
+            {
+            aEntity = &iBTPorts[i];
+            FTRACE(FPrint( _L( "CDunBtPlugin::GetPortByConnId() complete")) );
+            return i;
+            }
+        }
+    aEntity = NULL;
+    FTRACE(FPrint( _L( "CDunBtPlugin::GetPortByConnId() (not found) complete")) );
+    return KErrNotFound;
+    }
+
+// ---------------------------------------------------------------------------
+// Gets first free port's index and entity
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::GetFirstFreePort( TBtPortEntity*& aEntity )
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::GetFirstFreePort()")) );
+    TInt i;
+    TInt count = iBTPorts.Count();
+    for ( i=0; i<count; i++ )
+        {
+        if ( !iBTPorts[i].iBTPort.SubSessionHandle() )
+            {
+            aEntity = &iBTPorts[i];
+            FTRACE(FPrint( _L( "CDunBtPlugin::GetFirstFreePort() complete")) );
+            return i;
+            }
+        }
+    aEntity = NULL;
+    FTRACE(FPrint( _L( "CDunBtPlugin::GetFirstFreePort() (not found) complete")) );
+    return KErrNotFound;
+    }
+
+// ---------------------------------------------------------------------------
+// Sets modem's MSC (Modem Status Command)
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::SetRFCOMMStatusCommand( TBtPortEntity& aEntity,
+                                           TUint8 aSignal,
+                                           TBool aSignalOn )
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::SetRFCOMMStatusCommand()" ) ));
+    // Get existing Modem Status Command (MSC)
+    // Ref.: 3GPP TS 07.10 V7.2.0 (2002-03)
+    // Table 6,7, (5.4.6.3.7)
+    TUint8 modemStatus = 0;
+    TPckgBuf<TUint8> pkg( modemStatus );
+    TInt retTemp = aEntity.iBTPort.GetOpt( KRFCOMMLocalModemStatus,
+                                           KSolBtRFCOMM,
+                                           pkg );
+    if ( retTemp != KErrNone )
+        {
+        FTRACE(FPrint( _L( "CDunBtPlugin::SetRFCOMMStatusCommand() (GetOpt failed!) complete" ) ));
+        return retTemp;
+        }
+    modemStatus = pkg();
+    FTRACE(FPrint( _L( "CDunBtPlugin::SetRFCOMMStatusCommand() signals are: 0x%02X" ), modemStatus));
+    TBool changed = EFalse;
+    TUint8 signal = modemStatus & aSignal;
+    if ( aSignalOn )
+        {
+        if ( !signal )
+            {
+            modemStatus |= aSignal;
+            changed = ETrue;
+            }
+        }
+    else
+        {
+        if ( signal )
+            {
+            modemStatus &= ( ~aSignal );
+            changed = ETrue;
+            }
+        }
+    if ( changed )
+        {
+        pkg = modemStatus;
+        retTemp = aEntity.iBTPort.SetOpt( KRFCOMMLocalModemStatus,
+                                          KSolBtRFCOMM,
+                                          pkg );
+        if ( retTemp != KErrNone )
+            {
+            FTRACE(FPrint( _L( "CDunBtPlugin::SetRFCOMMStatusCommand() (SetOpt failed!) complete" ) ));
+            return retTemp;
+            }
+        }
+    FTRACE(FPrint( _L( "CDunBtPlugin::SetRFCOMMStatusCommand() complete" ) ));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Manages advertiser for channel free operation
+// ---------------------------------------------------------------------------
+//
+void CDunBtPlugin::ManageAdvertiserFreeOperationL()
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::ManageAdvertiserFreeOperationL()")));
+    TInt numOfChans = iTransporter->NumberOfAllocatedChannels();
+    // Remove of last CDunTransporter channel removes also the
+    // advertisement monitor so set it now if necessary
+    if ( numOfChans == 0 )
+        {
+        iTransporter->SetAdvertisementMonitorL( KDunBtPluginUid, iBTListen );
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::ManageAdvertiserFreeOperationL() complete")));
+    }
+
+// ---------------------------------------------------------------------------
+// Cleans partial created channel data based on TATExtCleanupInfo
+// ---------------------------------------------------------------------------
+//
+void CDunBtPlugin::CleanPartialChanneldata( TBtCleanupInfo& aCleanupInfo )
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::CleanPartialChanneldata()")));
+    RSocket* socket = &iBTPorts[aCleanupInfo.iEntityIndex].iBTPort;
+    iTransporter->FreeChannel( socket );
+    iBTPorts[aCleanupInfo.iEntityIndex].iChannelNum = KErrNotFound;
+    socket->Close();
+    if ( aCleanupInfo.iNewEntity )
+        {
+        iBTPorts.Remove( aCleanupInfo.iEntityIndex );
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::CleanPartialChanneldata() complete")));
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunLocalMediaPlugin.
+// CDunBtPlugin::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CDunBtPlugin::ConstructL( MDunServerCallback* aServer,
+                               CDunTransporter* aTransporter )
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::ConstructL()" ) ));
+    if ( !aServer || !aTransporter )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::ConstructL() not initialized!")));
+        User::Leave( KErrBadHandle );
+        }
+    iServer = aServer;
+    iTransporter = aTransporter;
+    FTRACE(FPrint( _L( "CDunBtPlugin::ConstructL() complete" ) ));
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunLocalMediaPlugin.
+// Gets called when server changes a plugin's state
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::NotifyServerStateChange( TDunPluginState aPluginState )
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange()")));
+    TInt retTemp;
+    switch ( aPluginState )
+        {
+        case EDunStateTryListen:
+            if ( PluginState() != EDunStateLoaded )
+                {
+                FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange() (not ready) complete")));
+                return KErrNotReady;
+                }
+            // Change to listening mode
+            TRAPD( retTrap, ConstructListenerL() );
+            if ( retTrap != KErrNone )
+                {
+                FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange() (ERROR) complete (%d)"), retTrap));
+                return retTrap;
+                }
+            break;
+        case EDunStateTryUninitialize:
+            if ( PluginState() == EDunStateUninitialized )
+                {
+                FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange() (not ready) complete")));
+                return KErrNotReady;
+                }
+            // Uninitialize
+            retTemp = Uninitialize();
+            if ( retTemp != KErrNone )
+                {
+                FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange() (not ready) complete (%d)"), retTemp));
+                return KErrNotReady;
+                }
+            break;
+        default:
+            FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange() (unknown state) complete")));
+            return KErrNotSupported;
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::NotifyServerStateChange() complete")));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunLocalMediaPlugin.
+// Gets called when server needs to know the active connection
+// ---------------------------------------------------------------------------
+//
+TConnId CDunBtPlugin::ActiveConnection()
+    {
+    FTRACE(FPrint(_L("CDunBtPlugin::ActiveConnection()")));
+    if ( iBTPorts.Count() >= 1 )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::ActiveConnection() complete")));
+        return &iBTPorts[0];
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::ActiveConnection() (not found) complete")));
+    return NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunListenCallback.
+// Gets called when new channel must be created
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::NotifyChannelAllocate( TBool& aNoFreeChans )
+    {
+    // Now state can be either EDunStateListening (no channels) or
+    // EDunStateChanneled (one or more channels). Support both states
+    TDunPluginState startState = PluginState();
+    if ( startState!=EDunStateListening && startState!=EDunStateChanneled )
+        {
+        FTRACE(FPrint(_L("CDunBtPlugin::NotifyChannelAllocate() (not ready) complete")));
+        return KErrNotReady;
+        }
+    if ( startState == EDunStateListening )
+        {
+        ReportStateChangeUp( EDunStateTryChannel );
+        }
+    TBtCleanupInfo cleanupInfo;
+    TRAPD( retTrap, AllocateChannelL(aNoFreeChans,cleanupInfo) );
+    if ( retTrap != KErrNone )
+        {
+        CleanPartialChanneldata( cleanupInfo );
+        FTRACE(FPrint(_L("CDunBtPlugin::NotifyChannelAllocate() (trapped!) complete")));
+        return retTrap;
+        }
+    if ( startState == EDunStateListening )
+        {
+        ReportStateChangeUp( EDunStateChanneled );
+        }
+    FTRACE(FPrint(_L("CDunBtPlugin::NotifyChannelAllocate() complete")));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunListenCallback.
+// Gets called when an existing channel must be freed
+// ---------------------------------------------------------------------------
+//
+TInt CDunBtPlugin::NotifyChannelFree()
+    {
+    // No implementation needed here
+    return KErrNotSupported;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunConnMon.
+// Gets called when line status changes or when any type of error is detected
+// ---------------------------------------------------------------------------
+//
+void CDunBtPlugin::NotifyProgressChangeL( TConnId aConnId,
+                                          TDunConnectionReason aConnReason )
+    {
+    FTRACE(FPrint( _L( "CDunBtPlugin::NotifyProgressChangeL()" ) ));
+    // Find matching failed ID
+    TBtPortEntity* foundEntity = NULL;
+    TInt foundIndex = GetPortByConnId( aConnId, foundEntity );
+    if ( !foundEntity )
+        {
+        FTRACE(FPrint( _L( "CDunBtPlugin::NotifyProgressChangeL() (not found) complete")) );
+        User::Leave( KErrNotFound );
+        }
+    if ( aConnReason.iReasonType == EDunReasonTypeSignal )
+        {
+        if ( aConnReason.iContext != EDunMediaContextNetwork )
+            {
+            // Should never come here as other signals are for RComm
+            FTRACE(FPrint( _L( "CDunBtPlugin::NotifyProgressChangeL() (ERROR) complete")) );
+            User::Leave( KErrGeneral );
+            }
+        // Signal change detected on network side -> process change
+        if ( aConnReason.iSignalType == KSignalDCD )
+            {
+            SetRFCOMMStatusCommand( *foundEntity,
+                                    KModemSignalDV,
+                                    aConnReason.iSignalHigh );
+            FTRACE(FPrint( _L( "CDunBtPlugin::NotifyProgressChangeL() DV changed")) );
+            }
+        else if ( aConnReason.iSignalType == KSignalRNG )
+            {
+            SetRFCOMMStatusCommand( *foundEntity,
+                                    KModemSignalIC,
+                                    aConnReason.iSignalHigh );
+            FTRACE(FPrint( _L( "CDunBtPlugin::NotifyProgressChangeL() IC changed")) );
+            }
+        // Omit other signals
+        }
+    else
+        {
+        // All other cases are down indications from local media side
+        if ( foundEntity->iBTPort.SubSessionHandle() )
+            {
+            iTransporter->FreeChannel( &foundEntity->iBTPort );
+            // CDunTransporter will notify the listener about advertisement
+            // status change after FreeChannel() so no need to do
+            // IssueRequestL() for CDunBtListen here after this.
+            foundEntity->iBTPort.Close();
+            }
+        ManageAdvertiserFreeOperationL();
+        // Now resources are freed so command server to reopen possibly
+        // existing queued plugins
+        iServer->NotifyPluginReopenRequest();
+        }
+    FTRACE(FPrint( _L( "CDunBtPlugin::NotifyProgressChangeL() complete")) );
+    }
+
+// ======== GLOBAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// NewLocalPluginL implements factory construction for
+// the class CDunBtPlugin.
+// The function is exported at ordinal 1.
+// ---------------------------------------------------------------------------
+//
+EXPORT_C MDunLocalMediaPlugin* NewLocalPluginL()
+    {
+    return new (ELeave) CDunBtPlugin;
+    }