Using the Bearer Mobility APIs

This topic describes how sockets clients can use the bearer mobility APIs.

Required background

Before you start, you must understand what Bearer Mobility is.

Introduction

The two Bearer Mobility APIs are RCommsMobilityApiExt and CActiveCommsMobilityApiExt . Both APIs provide the same functionality.

CActiveCommsMobilityApiExt is an active object. We recommend that a Socket Server client uses this class if the client uses an active scheduler.

If a socket server client does not use an active scheduler, the client must use the RCommsMobilityApiExt class. A client that uses an active scheduler can also use this class, but the class is more complicated to use.

The Bearer Mobility API requests the notification of a change to the bearer. CActiveCommsMobilityApiExt completes requests through the active scheduler, and automatically issues new requests. The users of RCommsMobilityApiExt must explicitly register for notification of changes, and must make explicit requestsfor notification after the completion of each request.

These two APIs are known as Extension APIs. Extension APIs are used to extend an existing API without adding new function members to the API class. Instead, the Extension API adds a new class that contains the function members for the extended API. The Bearer Mobility APIs extend the RConnection API. The Bearer Mobility APIs are provided as an Extension API because the Bearer Mobility APIs are classified as PublishedPartner, while the host RConnection API is classified as PublishedAll.

To use an Extension API, the client must use the existing API to connect to the server. The client passes the object for the server session to the constructor of the Extension API. The client can then use the Extension API with the same server session.

An example of how to use an Extension API is provided in sample code in the next section.

Once attached, the Extension API does not need to be detached before closing the RConnection session.

Procedure

A client that wants to use Bearer Mobility must register for notifications. A client can register for notifications even if it is already sending data. The rest of this discussion uses the CActiveCommsMobilityApiExt API.

If a client uses the CActiveCommsMobilityApiExt class to register for notifications, the client must implement the functionality of the MMobilityProtocolResp class. For example:

       
        
       
       class CBearerMobility : public MMobilityProtocolResp
    {
public:

    // constructors and other functions (not shown)

    ConnectAndProcessBearerChangesL();

private:
    // MMobilityProtocolResp
    void PreferredCarrierAvailable(TAccessPointInfo aOldAP, TAccessPointInfo aNewAP, TBool aIsUpgrade, TBool aIsSeamless);
    void NewCarrierActive(TAccessPointInfo aNewAP, TBool aIsSeamless);
    void Error(TInt aError);

    RConnection iConnection;
    RSocketServ iSocketServ;
    CActiveCommsMobilityApiExt* iMobilityExtension;
    };
      

In the above example, the same class contains the reference to the CActiveCommsMobilityApiExt Active Object used to control the requests, and contains the MMobilityProtocolResp functions that receive the requests. The following example code shows how to connect the CActiveCommsMobilityApiExt Extension API to an RConnection session and initiate the request:

       
        
       
       ConnectAndProcessBearerChangesL()
   {
   User::LeaveIfError(iSocketServ.Connect());
   CleanupClosePushL(iSocketServ);
   User::LeaveIfError(iConnection.Open(socketServ));
   CleanupClosePushL(iConnection);

   // ...possibly do more here to set the connection preferences (not shown)

   // Start the connection using an Access Point (AP) which has a bearer priority list (SNAP)
   // NOTE: The bearer priority list is dependent on the bearer implementation - for this example we use Comms Database
   const TUInt KSNAPPref = 50;    // AP Record ID in Comms Database

   TConnSnapPref snapPref(KSNAPPref);

   User::LeaveIfError(iConnection.Start(snapPref));

   iMobilityExtension = CActiveCommsMobilityApiExt::NewL(connection, *this); 
   CActiveScheduler::Start();

   // once the scheduler is stopped, close the connections
   CleanupStack::PopAndDestroy(); //iConnection.Close();
   CleanupStack::PopAndDestroy(); //iSocketServ.Close();
   }
      

The client uses the MMobilityProtocolResp class to process the notification of Bearer Mobility events. The functions are:

       
        
       
       MMobilityProtocolResp::PreferredCarrierAvailable(TAccessPointInfo aOldAP, TAccessPointInfo aNewAP, TBool aIsUpgrade, TBool aIsSeamless);
      

Comms mobility notification about a preferred bearer becoming available.

Parameter Description

TAccessPointInfo aOldAP

Information on the current access point

TAccessPointInfo aNewAP

Information on the new proposed access point

TBool aIsUpgrade

ETrue if the new bearer is preferred over the current one; EFalse if the new bearer is preferred from the rest of the bearers because the current one is no longer available

TBool aIsSeamless

Always set to EFalse. This parameter is reserved for future use.

       
        
       
       MMobilityProtocolResp::NewCarrierActive(TAccessPointInfo aNewAP, TBool aIsSeamless);
      

The Comms Stack calls this function in response to CActiveCommsMobilityApiExt::MigrateToPreferredCarrier when the migration is complete.

Parameter Description

TAccessPointInfo aNewAP

Information on the new access point

TBool aIsSeamless

Always set to EFalse. This parameter is reserved for future use.

       
        
       
       MMobilityProtocolResp::Error(TInt aError);
      

An error response for the previous request. The call to this function represents the completion of the request.

Parameter Description

TInt aError

The error code.

When a new bearer is available to the client, the Comms Stack calls PreferredCarrierAvailable .

In the simplest implementation, the client can always migrate. For example:

       
        
       
       void CBearerMobility::PreferredCarrierAvailable(TAccessPointInfo aOldAP, TAccessPointInfo aNewAP, TBool aIsUpgrade, TBool aIsSeamless)
    {
    // Arrange for migration
    iMobilityExtension->MigrateToPreferredCarrier();
    }
      

The client can indefinitely before responding to the call from PreferredCarrierAvailable .

After the client responds with MigrateToPreferredCarrier() the client must be ready for all its existing sockets to receive errors. When the client receives PreferredCarrierAvailable() it does not receive any further PreferredCarrierAvailable() requests until the bearer has been migrated or the client receives a call to the Error() function.

In the normal case, the device calls the client's NewCarrierActive() function when the new bearer is available. The client must then reconnect all the sockets.

If the device calls the client's PreferredCarrierAvailable() function and the client does not want to migrate, the client can reject the bearer by calling CActiveCommsMobilityApiExt::IgnorePreferredCarrier() . This ends the request.

If the client responds with MigrateToPreferredCarrier() and then the client decides that the new bearer is inadequate, the client can reject the new bearer by calling CActiveCommsMobilityApiExt::NewCarrierRejected() . In the normal case where the client was able to reconnect all sockets, the client calls CActiveCommsMobilityApiExt::NewCarrierAccepted() . An example NewCarrierActive function:

       
        
       
       void CBearerMobility::NewCarrierActive(TAccessPointInfo aNewAP, TBool aIsSeamless)
   {
   // Reconnect all sockets 

   TInt aRet = ReconnectSockets();   // not shown - client must implement

   if (aRet == KErrNone)
      {
      // Accept the new bearer
      iMobilityExtension->NewCarrierAccepted();
      }
   else
      {
      // problem with the new bearer
      iMobilityExtension->NewCarrierRejected();
      }
   }
      

If the client calls NewCarrierAccepted() then the Bearer Mobility request is complete.

If the client calls NewCarrierRejected() the client will be offered another bearer or will have the Error() function called.

The Error() function allows error conditions to be captured and logged. It is called by the Comms Stack as a response to a Bearer mobility request when an error occurs. Once the Error() function is called, the request is complete. Examples of error scenarios are:

  • The client receives a call to Error() after calling MigrateToPreferredCarrier() . Potential reasons for this are:

    • The preferred bearer becomes unavailable

    • Another preferred bearer becomes available so the bearer offered is no longer the best bearer available

    A possible reason for this error is that the client takes too long to respond to the PreferredCarrierAvailable() function call.

  • The client calls CActiveCommsMobilityApiExt::NewCarrierRejected() and there are no other bearers available

An example Error() function:

       
        
       
       void CBearerMobility::Error(TInt aError)
   {
   // Most likely a cancel but check for any kind of error
   if(aError == KErrCancel)
      {
      INFO_PRINTF1(_L("Mobility extension cancelled"));
      }
   else
      {
      // Some kind of unexpected error during mobility migration
      INFO_PRINTF2(_L("Unexpected error (ordinarily KErrCancel) from mobility extension. error:%d"), aError);

      // Make sure that the sockets are reconnected if the migration was attempted and then aborted
      // (client to implement ReconnectSockets function)
      TInt aRet = ReconnectSockets();

      if (aRet != KErrNone)
            {
            INFO_PRINTF2(_L("Could not reconnect sockets from mobility extension. error:%d"), aRet);
            // will need to retry reconnection at some stage
            }
      }
   }