localconnectivityservice/dun/plugins/src/bt/DunBtListen.cpp
branchRCL_3
changeset 19 0aa8cc770c8a
equal deleted inserted replaced
18:453dfc402455 19:0aa8cc770c8a
       
     1 /*
       
     2 * Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  DUN Bluetooth plugin's listener
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <btsdp.h>
       
    20 #include <e32std.h>
       
    21 #include <bt_sock.h>
       
    22 #include <btengdiscovery.h>
       
    23 #include "DunPlugin.h"
       
    24 #include "DunBtListen.h"
       
    25 #include "DunBtPlugin.h"
       
    26 #include "DunDebug.h"
       
    27 
       
    28 const TInt KListenQueSize   = 1;
       
    29 const TInt KDunFixedChannel = 22;  // Hack/kludge for Apple Bug ID 6527598
       
    30 
       
    31 //Service Class Bits supported by DUN
       
    32 static const TUint16 KCoDDunServiceClass = EMajorServiceTelephony | EMajorServiceNetworking;
       
    33 
       
    34 // ======== MEMBER FUNCTIONS ========
       
    35 
       
    36 // ---------------------------------------------------------------------------
       
    37 // Two-phased constructor.
       
    38 // ---------------------------------------------------------------------------
       
    39 //
       
    40 CDunBtListen* CDunBtListen::NewL( MDunServerCallback* aServer,
       
    41                                   MDunListenCallback* aParent,
       
    42                                   CDunTransporter* aTransporter,
       
    43                                   TBtPortEntity& aEntity )
       
    44     {
       
    45     CDunBtListen* self = new (ELeave) CDunBtListen( aServer,
       
    46                                                     aParent,
       
    47                                                     aTransporter,
       
    48                                                     aEntity );
       
    49     CleanupStack::PushL( self );
       
    50     self->ConstructL();
       
    51     CleanupStack::Pop( self );
       
    52     return self;
       
    53     }
       
    54 
       
    55 // ---------------------------------------------------------------------------
       
    56 // Destructor.
       
    57 // ---------------------------------------------------------------------------
       
    58 //
       
    59 CDunBtListen::~CDunBtListen()
       
    60     {
       
    61     FTRACE(FPrint( _L("CDunBtListen::~CDunBtListen()") ));
       
    62     ResetData();
       
    63     FTRACE(FPrint( _L("CDunBtListen::~CDunBtListen() complete") ));
       
    64     }
       
    65 
       
    66 // ---------------------------------------------------------------------------
       
    67 // Resets data to initial values
       
    68 // ---------------------------------------------------------------------------
       
    69 //
       
    70 void CDunBtListen::ResetData()
       
    71     {
       
    72     // APIs affecting this:
       
    73     // IssueRequestL()
       
    74     Stop();
       
    75     StopServiceAdvertisement();
       
    76     // NewL()
       
    77     iTransporter->FreeAdvertisementMonitor( KDunBtPluginUid, this );
       
    78     delete iDiscovery;
       
    79     iDiscovery = NULL;
       
    80     if ( iSockServer.Handle() != KNullHandle )
       
    81         {
       
    82         iSockServer.Close();
       
    83         }
       
    84     // Internal
       
    85     Initialize();
       
    86     }
       
    87 
       
    88 // ---------------------------------------------------------------------------
       
    89 // Registers itself to SDP and BT manager, opens a socket
       
    90 // and starts to listen it.
       
    91 // ---------------------------------------------------------------------------
       
    92 //
       
    93 void CDunBtListen::IssueRequestL()
       
    94     {
       
    95     FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL()" ) ));
       
    96 
       
    97     if ( iListenState == EBtListenStateListening )
       
    98         {
       
    99         FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() (already active) complete" ) ));
       
   100         User::Leave( KErrNotReady );
       
   101         }
       
   102 
       
   103     TBool advertise = iTransporter->AdvertisementStatus();
       
   104     if ( !advertise )
       
   105         {
       
   106         // Return silently here as CDunTransporter will notify later
       
   107         return;
       
   108         }
       
   109 
       
   110     TBool inUse = EFalse;
       
   111     TInt numOfChans = 0;
       
   112     TInt retTemp = StartServiceAdvertisement( inUse );
       
   113     if ( retTemp != KErrNone )
       
   114         {
       
   115         if ( inUse )
       
   116             {
       
   117             numOfChans = iTransporter->GetNumberOfAllocatedChannelsByUid(
       
   118                 KDunBtPluginUid );
       
   119             if ( numOfChans == 0)
       
   120                 {
       
   121                 // No channels so parent can't reissue requests of this object
       
   122                 // This is fatal case -> leave.
       
   123                 // NOTE: To add full support for this case a poller (timer) is
       
   124                 // needed that polls for free RFCOMM channel by given interval.
       
   125                 User::Leave( retTemp );
       
   126                 }
       
   127             // If in use and parent has channels then just fail silently.
       
   128             // Let this object to wait until parent finds new resources.
       
   129             FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() complete" ) ));
       
   130             return;
       
   131             }
       
   132         FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() (failed!) complete" ) ));
       
   133         User::Leave( retTemp );
       
   134         }
       
   135 
       
   136     // Not already active here so start listening
       
   137     // First open blank data socket
       
   138     retTemp = iEntity.iBTPort.Open( iSockServer );
       
   139     if ( retTemp != KErrNone )
       
   140         {
       
   141         FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() (ERROR) complete (%d)" ), retTemp));
       
   142         User::Leave( retTemp );
       
   143         }
       
   144     iStatus = KRequestPending;
       
   145     iListenSocket.Accept( iEntity.iBTPort, iStatus );
       
   146     SetActive();
       
   147     iListenState = EBtListenStateListening;
       
   148 
       
   149     FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() complete") ));
       
   150     }
       
   151 
       
   152 // ---------------------------------------------------------------------------
       
   153 // Stops listening
       
   154 // ---------------------------------------------------------------------------
       
   155 //
       
   156 TInt CDunBtListen::Stop()
       
   157     {
       
   158     FTRACE(FPrint( _L( "CDunBtListen::Stop()") ));
       
   159     if ( iListenState != EBtListenStateListening )
       
   160         {
       
   161         FTRACE(FPrint( _L("CDunBtListen::Stop() (not ready) complete" )));
       
   162         return KErrNotReady;
       
   163         }
       
   164     iListenSocket.CancelAccept();
       
   165     Cancel();
       
   166     iListenState = EBtListenStateIdle;
       
   167     FTRACE(FPrint( _L( "CDunBtListen::Stop() complete") ));
       
   168     return KErrNone;
       
   169     }
       
   170 
       
   171 // ---------------------------------------------------------------------------
       
   172 // CDunBtListen::CDunBtListen
       
   173 // ---------------------------------------------------------------------------
       
   174 //
       
   175 CDunBtListen::CDunBtListen( MDunServerCallback* aServer,
       
   176                             MDunListenCallback* aParent,
       
   177                             CDunTransporter* aTransporter,
       
   178                             TBtPortEntity& aEntity ) :
       
   179     CActive( EPriorityStandard ),
       
   180     iServer( aServer ),
       
   181     iParent( aParent ),
       
   182     iTransporter( aTransporter ),
       
   183     iEntity( aEntity )
       
   184     {
       
   185     Initialize();
       
   186     }
       
   187 
       
   188 // ---------------------------------------------------------------------------
       
   189 // CDunBtListen::ConstructL
       
   190 // ---------------------------------------------------------------------------
       
   191 //
       
   192 void CDunBtListen::ConstructL()
       
   193     {
       
   194     FTRACE(FPrint(_L("CDunBtListen::ConstructL()")));
       
   195     if ( !iServer || !iParent || !iTransporter )
       
   196         {
       
   197         User::Leave( KErrGeneral );
       
   198         }
       
   199 
       
   200     CBTEngDiscovery* discovery = CBTEngDiscovery::NewLC();
       
   201     FTRACE(FPrint(_L("CDunBtListen::ConstructL: iSockServer.Connect")));
       
   202     User::LeaveIfError( iSockServer.Connect() );
       
   203 
       
   204     // Set advertisement monitor
       
   205     iTransporter->SetAdvertisementMonitorL( KDunBtPluginUid, this );
       
   206 
       
   207     // Then we are ready to start listening and accepting incoming connection
       
   208     // requests.
       
   209     CleanupStack::Pop( discovery );
       
   210     iDiscovery = discovery;
       
   211     CActiveScheduler::Add( this );
       
   212     FTRACE(FPrint(_L("CDunBtListen::ConstructL() complete")));
       
   213     }
       
   214 
       
   215 // ---------------------------------------------------------------------------
       
   216 // Initializes this class
       
   217 // ---------------------------------------------------------------------------
       
   218 //
       
   219 void CDunBtListen::Initialize()
       
   220     {
       
   221     // Don't initialize iServer here (it is set through NewL)
       
   222     // Don't initialize iParent here (it is set through NewL)
       
   223     // Don't initialize iTransporter here (it is set through NewL)
       
   224     // Don't initialize iEntity here (it is set through NewL)
       
   225     iListenState = EBtListenStateIdle;
       
   226     iDiscovery = NULL;
       
   227     iChannelNum = 0;
       
   228     iSDPHandleDun = 0;
       
   229     }
       
   230 
       
   231 // ---------------------------------------------------------------------------
       
   232 // Starts dialup service advertisement
       
   233 // ---------------------------------------------------------------------------
       
   234 //
       
   235 TInt CDunBtListen::StartServiceAdvertisement( TBool& aInUse )
       
   236     {
       
   237     FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement()" ) ));
       
   238 
       
   239     TInt retTemp = ReserveLocalChannel( iSockServer,
       
   240                                         iListenSocket,
       
   241                                         iChannelNum,
       
   242                                         aInUse );
       
   243     if ( retTemp != KErrNone )
       
   244         {
       
   245         FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement() (ERROR) complete" ) ));
       
   246         return retTemp;
       
   247         }
       
   248 
       
   249     // Now RFCOMM channel number of the next data socket must be the same as
       
   250     // the current listener's RFCOMM channel number. Set that now.
       
   251     iEntity.iChannelNum = iChannelNum;
       
   252 
       
   253     // Register SDP record
       
   254     iSDPHandleDun = 0;
       
   255     retTemp = iDiscovery->RegisterSdpRecord( KDialUpNetworkingUUID,
       
   256                                              iChannelNum,
       
   257                                              iSDPHandleDun );
       
   258     if ( retTemp != KErrNone )
       
   259         {
       
   260         FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement() (failed!) complete (%d)" ), retTemp));
       
   261         return retTemp;
       
   262         }
       
   263     FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement() complete" ) ));
       
   264     return KErrNone;
       
   265     }
       
   266 
       
   267 // ---------------------------------------------------------------------------
       
   268 // Stops dialup service advertisement
       
   269 // ---------------------------------------------------------------------------
       
   270 //
       
   271 TInt CDunBtListen::StopServiceAdvertisement()
       
   272     {
       
   273     FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement()" ) ));
       
   274     if ( !iDiscovery )
       
   275         {
       
   276         FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement() (iDiscovery) not initialized!" ) ));
       
   277         return KErrGeneral;
       
   278         }
       
   279     if ( iSDPHandleDun != 0 )
       
   280         {
       
   281         TInt retTemp = iDiscovery->DeleteSdpRecord( iSDPHandleDun );
       
   282         FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement() record closed (%d)" ), retTemp ));
       
   283         iSDPHandleDun = 0;
       
   284         }
       
   285     if ( iListenSocket.SubSessionHandle() )
       
   286         {
       
   287         iListenSocket.Close();
       
   288         }
       
   289     FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement() complete" ) ));
       
   290     return KErrNone;
       
   291     }
       
   292 
       
   293 // ---------------------------------------------------------------------------
       
   294 // Method which reserves local RFCOMM channel (from possible channels 1-30)
       
   295 // and returns it to client.
       
   296 // ---------------------------------------------------------------------------
       
   297 //
       
   298 TInt CDunBtListen::ReserveLocalChannel( RSocketServ& aSocketServ,
       
   299                                         RSocket& aListenSocket,
       
   300                                         TUint& aChannelNum,
       
   301                                         TBool& aInUse )
       
   302     {
       
   303     FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel()")));
       
   304     aInUse = EFalse;
       
   305     if ( aListenSocket.SubSessionHandle() )
       
   306         {
       
   307         FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() (open socket!) complete")));
       
   308         return KErrArgument;
       
   309         }
       
   310     TInt retTemp;
       
   311     TProtocolDesc pInfo;
       
   312     retTemp = aSocketServ.FindProtocol( TProtocolName(KRFCOMMDesC), pInfo );
       
   313     if ( retTemp != KErrNone )
       
   314         {
       
   315         FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() (FindProtocol failed) complete (%d)"), retTemp));
       
   316         return retTemp;
       
   317         }
       
   318     retTemp = aListenSocket.Open( aSocketServ,
       
   319                                   pInfo.iAddrFamily,
       
   320                                   pInfo.iSockType,
       
   321                                   pInfo.iProtocol );
       
   322     if ( retTemp != KErrNone )
       
   323         {
       
   324         FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() (Open failed) complete (%d)"), retTemp));
       
   325         return retTemp;
       
   326         }
       
   327     TRfcommSockAddr addr;
       
   328     TBTServiceSecurity sec;
       
   329     sec.SetAuthentication( ETrue );
       
   330     sec.SetAuthorisation( ETrue );
       
   331     sec.SetEncryption( ETrue );
       
   332     sec.SetPasskeyMinLength( 0 );
       
   333     addr.SetSecurity( sec );
       
   334     addr.SetPort( KRfcommPassiveAutoBind );
       
   335     // When fix from Apple, replace the following with
       
   336     // "retTemp = aListenSocket.Bind( addr );"
       
   337     retTemp = DoExtendedBind( aListenSocket, addr );
       
   338     if ( retTemp != KErrNone )
       
   339         {
       
   340         aListenSocket.Close();
       
   341         aInUse = ETrue;
       
   342         FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() Bind() complete (%d)"), retTemp));
       
   343         return KErrInUse;
       
   344         }
       
   345     aChannelNum = aListenSocket.LocalPort();
       
   346 
       
   347     // We try to set the Telephony and Networking bits in our service class.  If this fails we
       
   348     // ignore it, as it's better to carry on without it than to fail to start listening.
       
   349     aListenSocket.SetOpt(KBTRegisterCodService, KSolBtRFCOMM, KCoDDunServiceClass);
       
   350 
       
   351     retTemp = aListenSocket.Listen( KListenQueSize );
       
   352     if ( retTemp != KErrNone )
       
   353         {
       
   354         aListenSocket.Close();
       
   355         FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() Listen() complete (%d)"), retTemp));
       
   356         return retTemp;
       
   357         }
       
   358     FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() complete (%d)"), aChannelNum));
       
   359     return KErrNone;
       
   360     }
       
   361 
       
   362 // ---------------------------------------------------------------------------
       
   363 // Tries to bind to a fixed port and if that fails with KRfcommPassiveAutoBind.
       
   364 // This is for spec breaking solutions like the OSX Leopard.
       
   365 // ---------------------------------------------------------------------------
       
   366 //
       
   367 TInt CDunBtListen::DoExtendedBind( RSocket& aListenSocket,
       
   368                                    TRfcommSockAddr& aSockAddr )
       
   369     {
       
   370     FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind()")));
       
   371     if ( !aListenSocket.SubSessionHandle() )
       
   372         {
       
   373         FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind() (closed socket!) complete")));
       
   374         return KErrGeneral;
       
   375         }
       
   376     TRfcommSockAddr fixedAddr = aSockAddr;
       
   377     fixedAddr.SetPort( KDunFixedChannel );
       
   378     TInt retTemp = aListenSocket.Bind( fixedAddr );
       
   379     if ( retTemp == KErrNone )
       
   380         {
       
   381         FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind() complete")));
       
   382         return KErrNone;
       
   383         }
       
   384     TInt retVal = aListenSocket.Bind( aSockAddr );
       
   385     FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind() complete")));
       
   386     return retVal;
       
   387     }
       
   388 
       
   389 // ---------------------------------------------------------------------------
       
   390 // From class CActive.
       
   391 // Called when a service is requested via BT.
       
   392 // ---------------------------------------------------------------------------
       
   393 //
       
   394 void CDunBtListen::RunL()
       
   395     {
       
   396     FTRACE(FPrint( _L( "CDunBtListen::RunL()" ) ));
       
   397     iListenState = EBtListenStateIdle;
       
   398 
       
   399     StopServiceAdvertisement();
       
   400 
       
   401     TInt retTemp = iStatus.Int();
       
   402     if ( retTemp != KErrNone )
       
   403         {
       
   404         FTRACE(FPrint( _L( "CDunBtListen::RunL() (ERROR) complete (%d)" ), retTemp));
       
   405         iServer->NotifyPluginCloseRequest( KDunBtPluginUid, ETrue );
       
   406         return;
       
   407         }
       
   408     // Notify new connection
       
   409     TBool noFreeChans = EFalse;
       
   410     retTemp = iParent->NotifyChannelAllocate( noFreeChans );
       
   411     if ( retTemp != KErrNone )
       
   412         {
       
   413         FTRACE(FPrint( _L( "CDunBtListen::RunL() channel allocation failed! (%d)" ), retTemp));
       
   414         // Other error than no free channels, close plugin now
       
   415         if ( !noFreeChans )
       
   416             {
       
   417             iServer->NotifyPluginCloseRequest( KDunBtPluginUid, ETrue );
       
   418             }
       
   419         return;
       
   420         }
       
   421 
       
   422     // Don't restart listening here. Request is issued via
       
   423     // NotifyAdvertisementStart()
       
   424 
       
   425     FTRACE(FPrint( _L( "CDunBtListen::RunL() complete" ) ));
       
   426     }
       
   427 
       
   428 // ---------------------------------------------------------------------------
       
   429 // From class CActive.
       
   430 // Cancel current activity.
       
   431 // ---------------------------------------------------------------------------
       
   432 //
       
   433 void CDunBtListen::DoCancel()
       
   434     {
       
   435     }
       
   436 
       
   437 // ---------------------------------------------------------------------------
       
   438 // From class MDunServAdvMon.
       
   439 // Gets called when advertisement status changes to start.
       
   440 // ---------------------------------------------------------------------------
       
   441 //
       
   442 void CDunBtListen::NotifyAdvertisementStart( TBool aCreation )
       
   443     {
       
   444     FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementStart()" ) ));
       
   445     // Remove the "if" below when fix comes from Apple
       
   446     if ( !aCreation )
       
   447         {
       
   448         TRAP_IGNORE( IssueRequestL() );
       
   449         }
       
   450     FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementStart() complete" ) ));
       
   451     }
       
   452 
       
   453 // ---------------------------------------------------------------------------
       
   454 // From class MDunServAdvMon.
       
   455 // Gets called when advertisement status changes to end.
       
   456 // ---------------------------------------------------------------------------
       
   457 //
       
   458 void CDunBtListen::NotifyAdvertisementEnd()
       
   459     {
       
   460     FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementEnd()" ) ));
       
   461     Stop();
       
   462     StopServiceAdvertisement();
       
   463     FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementEnd() complete" ) ));
       
   464     }