IP Address change and Symbian Access Point Reconnection Issues

来源:互联网 发布:淘宝美邦哪个是真的 编辑:程序博客网 时间:2024/05/21 07:48

IP Address change and Symbian Access Point Reconnection Issues ¶

Table of Contents

  1. Problem description
  2. Issues and solution related to IP address change
    1. Approach 1: Restart everything
    2. Approach 2: Selective update
  3. Symbian specific issues and solution

This article describes some issues and their corresponding solutionsrelated to access point disconnection, reconnection, IP address change,and how to handle these events in your PJSIP applications. The generalissues related to the discussion will be explained, along with somespecific issues to Symbian applications.

 

Problem description ¶

Access point disconnection and reconnection are scenarios that needto be handled in mobile applications. Few issues or scenarios relatedto this for example are:

  • user moves outside the range of a Wi-Fi access point (AP) and lost the connection
  • user moves outside the range of one AP and reconnect to another
  • the handset may get new IP address if user reconnects to different AP

Each of the scenarios above may need different handling in the application.

 

Issues and solution related to IP address change ¶

When the connection is reconnected, the handset may get different IPaddress than what it previously got. There are few ramifications ofthis, for example if PJSUA-LIB is used:

  • the SIP registration needs to be updated with a new Contact URI
  • the account URI also needs to be updated
  • media addresses need to be updated
  • if there is ongoing dialog, the remote party needs to beinformed with new Contact URI as well as new media (RTP/RTCP)addresses.

Note that the monitoring of connection/interface statusis outside the scope of PJSIP, so the application must implement thisitself (for example using connection progress monitor in Symbian).Having said that, PJSIP does have some capability to detect some IPaddress change scenarios, for example by monitoring the IP address inSIP REGISTER response or in STUN Binding response when ICE transport isused and STUN is enabled.

Once the application has detected that the IP interface address has changed, there are two solutions to inform PJSIP about this.

 

Approach 1: Restart everything ¶

The most straightforward solution is of course to restart everything, which means in pjsua terms to call pjsua_destroy() and followed by pjsua_create(), pjsua_init(),and so on. While this solution may sound crude, it is the easiest to doand as will be explained later it is not considerably worse then themore refined alternative.

 

Approach 2: Selective update ¶

Alternatively there may be a way to allow the stack to continue torun, updating the address information when necessary. This approachwill require some specific features to be used, as well as some actionsby the application when it detects that the IP address has changed.

The specific configuration and tasks will be explained below. Note weassume that the SIP and media sockets are bound to INADDR_ANY (0.0.0.0)and not to a specific interface IP address (this is the defaultbehavior).

Account Contact URI update ¶

Task:
The account URI needs to beupdated with the new address, and re-registration is necessary toinform the registrar about the new URI.
Description:
PJSUA-LIB has thecapability to detect the (SIP) IP address change based on the responseof REGISTER request and automatically update the registration with thecorrect IP if it detects that the IP/port seen by the server isdifferent than the address specified in the Contact URI. This featureis enabled by default, via the pjsua_acc_config.allow_contact_rewrite setting.

So the solution is simply to trigger the re-registration by calling pjsua_acc_set_registration()function (after the new connection is up of course). The PJSUA-LIB willsend re-REGISTER request, check the IP address/port in the response,and re-REGISTER again and update the account URI as necessary.

Media addresses update ¶

Task:
The media (RTP/RTCP) addressesin PJSUA-LIB are normally determined during PJSUA-LIB startup, hencethey need to be updated with the new address.
Description:
If ICE media transport isused, and STUN is enabled on the media transport, then the mediatransport will automatically update its publicly mapped IP address fromthe STUN Binding response. The transport should send STUN Bindingrequest periodically (approximately every 15 seconds) as NAT keep-alivemechanism, so the address change will be detected by the transportautomatically during this operation.

Note that at present there is no API to explicitly request the ICE media transport to initiate STUN Binding request immediately.

If ICE is not used, then at present there is no mechanism to updatethe IP address of media transport, nor the media transport will updateits address even when STUN is used. The only solution would be torecreate the media transports and supply them to PJSUA-LIB with pjsua_media_transports_attach().

Call in progress issues ¶

Task:
Dialog's Contact URI needs to be updated.
Description:
The dialog's Contact URI is set initially when the dialog is created,from the account's Contact URI. While at the PJSIP level the pjsip_inv_reinvite() allows changing of Contact URI via the new_contact argument, currently this feature is not used by PJSUA-LIB, i.e. the pjsua_call_reinvite() does not allow the application to change the Contact URI.

So this is an open issue.

Task:
Changing of RTP/RTCP media addresses of ongoing call
Description:
If ICE is used, then new STUN srflx address will be signaled in updated SDP offer, as long as:
  • ICE media transport has detected that the IP address has changed (via the keep-alive above), and
  • the media was previously inactive, since if media has beenactive (hence ICE session is active), the SDP will contain only theused candidates and not all the list of candidates.

Alternatively, we may not need to inform the new RTP/RTCP address at all.If the remote media endpoint has the capability to switch its RTP/RTCPtransmission to the source address of the RTP/RTCP packets (note:PJMEDIA has this capability), then it should automatically switch itsdestination address to our new address.

 

Symbian specific issues and solution ¶

Being a mobile operating system, Symbian has good supports in managing access point connection. In Symbian, the RConnection object is used to manage the connection, and each socket handle (RSocket) is created in a context of an RConnection. The RConnection.ProgressNotification()method can be used to register an Active Object to be run when theconnection status has changed, so the application has good control overthe connection.

However there are still couple of unsolved issues remaining (probably due to lack of knowledge in our part):

  • when the connection in RConnection is down, it seemsthat the sockets created with that RConnection will detach themselvesfrom the connection, so even though the RConnection is reconnected,this will not automatically make the sockets recover to a "good" state.If the application tries to make use of the socket, for example, tocall !SendTo(), it will cause the socket to pop up the access point selection dialog again
  • more over, if user selects different access point in thedialog, this will put the sockets in somewhat worse state. If theapplication tries to make use of the socket, for example, to call !SendTo(),it will cause the TRequestStatus associated with the operation to blockfor a long time (about one and half minute). And even worse, a secondcall to !SendTo() will cause the TRequestStatus to block indefinitely!

At the moment we are not aware of any solutions for the above issues.Lacking this, we created a workaround in PJLIB to prevent it fromaccessing any Symbian socket API's when the connection has been downand reconnected. The API is pj_symbianos_set_connection_status() and it was added in PJSIP version 1.0.2/1.1 (ticket #733 and #732 respectively).

Below is a sample code, implemented in symbian_ua/ua.cpp sample application, to restart PJSIP and use the pj_symbianos_set_connection_status() function.

class CConnMon : public CActive {
public:
static CConnMon* NewL(RConnection &conn, RSocketServ &sserver) {
CConnMon *self = new (ELeave) CConnMon(conn, sserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}

void Start() {
conn_.ProgressNotification(nif_progress_, iStatus);
SetActive();
}

void Stop() {
Cancel();
}

~CConnMon() { Stop(); }

private:
CConnMon(RConnection &conn, RSocketServ &sserver) :
CActive(EPriorityHigh),
conn_(conn),
sserver_(sserver)
{
CActiveScheduler::Add(this);
}

void ConstructL() {}

void DoCancel() {
conn_.CancelProgressNotification();
}

void RunL() {
if (nif_progress_().iStage == KLinkLayerClosed) {
pj_status_t status;
TInt err;

// Tell pjlib the connection has been down.
pj_symbianos_set_connection_status(PJ_FALSE);

PJ_LOG(3, (THIS_FILE, "RConnection closed, restarting PJSUA.."));

// Destroy pjsua
pjsua_destroy();
PJ_LOG(3, (THIS_FILE, "PJSUA destroyed."));

// Reopen the connection
err = conn_.Open(sserver_);
if (err == KErrNone)
err = conn_.Start();
if (err != KErrNone) {
CActiveScheduler::Stop();
return;
}

// Reinit Symbian OS param before pj_init()
pj_symbianos_params sym_params;
pj_bzero(&sym_params, sizeof(sym_params));
sym_params.rsocketserv = &sserver_;
sym_params.rconnection = &conn_;
pj_symbianos_set_params(&sym_params);

// Reinit pjsua
status = app_startup();
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "app_startup() error", status);
CActiveScheduler::Stop();
return;
}


PJ_LOG(3, (THIS_FILE, "PJSUA restarted."));
PrintMenu();
}

Start();
}

private:
RConnection& conn_;
RSocketServ& sserver_;
TNifProgressBuf nif_progress_;
};

What the code in RunL() above does is it shuts downPJSIP when the connection is down, ask user to reconnect by showing upthe access point dialog, and (re)start the application.

Note that the drawback with this approach is that it does not cleanup the registration and calls properly, that is no SIP unregistrationwill be sent and if the application is in the middle of a call whilethe connection is down then no BYE will be sent either. Currently wecan't suggest any other solution, as we can't get rid of the socketgets stuck problem.

More about the socket stuck problem

This is a problem with the socket in general. Below are steps to reproduce with a plain UDP socket:

  1. Create RConnection, call Start() to connect to AP
  2. Create UDP socket, call SendTo() to send a packet
  3. Disconnect the AP (Menu -> Connectivity -> Conn. mgr.-> Active data connections -> (highlight the AP) -> Options(menu) -> Disconnect).
  4. Call udp.SendTo() again
  5. AP selection dialog appears, select different AP
  6. WaitForRequest() to the udp.SendTo() operation now will get stuck for 1-2 minutes before tcpip6_error_NoRoute error (-5105) is returned.
  7. Now if you call udp.SendTo() again, now WaitForRequest() will get stuck indefinitely

The problem above does not occur if:

  • the user selects the same AP. In this case the udp.SendTo() should complete successfully
  • the user cancels the AP selection dialog. In this case theudp.SendTo() will fail immediately with KErrCancel without blocking theapplication.
  • the socket is closed and re-opened. In this case the udp.SendTo() should complete successfully

As additional info:

  • the problem still persists even if the RConnection is restarted(RConnection.Start() is called to select new AP) in between step 3 and4 above.
原创粉丝点击