Issue with dialling REGISTERED (but offline) users

i’m facing the following scenario:
we have to local (REGISTERED) users (iOS apps pjSIP) which initiating local calls between each other.
the problem arise when one of the users (let’s say user B) is closing the application few minutes after he successfully REGISTERS.
now, when user A tries to call user B we see that the INVITE is sent but we got no reply (e.g 180 ringing) from User B.

Note: when we are sending an invite to User B he get’s Push notification to his device what cases him to open the app (and to Re-REGISTER)

our targets are:

  1. determinate if user B (e.g the callee) is reachable before we are sending an INVITE in cases User B App is closed and his extension is still REGISTERED
  2. be able to send invite to user B right after he REGISTER

we tried to solve this issue from many directions:
1.Qualify - tried to decrease the qualify time of the registersion period so user B will be UNAVAILABLE as soon as possible (and we will check the device state before we will dial) but it may cause to massive OPTIONS on our network, and it’s not going to solve target #2
2.AMI Service - it can catch events like: User A Dials user B , User B is Ringing (180 Ringing) and save those statuses to ASTDB . all this logic will be prefomed before we will launch the dial.
this solution is clumsy and to cmplicated and it requires to watch yet another service

after some research i’v got to the conclusion that the most suitable solution will be to store the time of the last OPTIONS reply of each extension(requires a patch in chan_sip.c) . re-trigger sip options qualify request to user B before User A Dials . if the original value (e.g before we re-triggered the OPTIONS) is equal the value after we trigged the OPTIONS it means that User B has not replied OPTIONS.

i’m attaching the changes i’v preformed to complete this task.
i would like to know if solution for the issue is suitable and valid and of course if there is a better way to preform it.

These is the change in chan_sip (using asterisk 11.7)
i’v prefomed changes only on the following lines:
23492 to 23500


  23485 /*! \brief Handle qualification responses (OPTIONS) */
  23486 static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_request *req)
  23487 {
  23488   struct sip_peer *peer = /* sip_ref_peer( */ p->relatedpeer /* , "bump refcount on p, as it is being used in this function(handle_response_peerpoke)")*/ ; /* hope this is already refcounted! */
  23489   int statechanged, is_reachable, was_reachable;
  23490   int pingtime = ast_tvdiff_ms(ast_tvnow(), peer->ps);
  23491
  23492   time_t result = time(NULL);
  23493   result = (int)result;
  23494   char time_string[33];
  23495   sprintf(time_string,"%d",(int)result);
  23496   ast_log(LOG_NOTICE, "KOLA - Poke: %s ", peer->name);
  23497   ast_log(LOG_NOTICE, "KOLA - %d seconds since the Epoch", (int)result);.
  23498  // ast_db_put("KOLA/LastQualify", string(peer->name), (int)result);
  23499
  23500   ast_db_put("KOLA/LastQualify",peer->name, time_string);

These is the change in extension.ael



This is the dial command for this scenario:

Dial(SIP/${dest},10,Rgb(check_extension,s,1));

I'm sending the call to context before inviting ( with the "b" option)
context check_extension {
  s => {
    Set(IS_REACHABLE=0);
    Verbose(KOLA/LastQualify/${DEST}); // Display User B initial quliafy
    Set(INITIAL_QUALIFY=${DB(KOLA/LastQualify/${DEST})}); // Store it
    for(loop=0;${loop}<60;dialLoop=${loop}+1) { // Loop untill the qualify will be changes
      System(/usr/sbin/asterisk -rx "sip qualify peer ${DEST}");
      Wait(2); // we need to wait a while for a response
      Set(LAST_QUALIFY=${DB(KOLA/LastQualify/${DEST})}); // set the new qualify
      if (${LAST_QUALIFY} > ${INITIAL_QUALIFY}) { // if the new qualify is newer, User B is reachable
        Set(IS_REACHABLE=1);
        break;
      }
    }

    if (${IS_REACHABLE} = 0) {
      Verbose(Peer is not reachable);
      Hangup();
    }
  }
}

Thanks in advanced
Nir Levi

Patches can’t be used unless they are submitted through the bug tracker by someone who has “signed” the contributor agreement. As a new feature, it will need to be submitted as a patch against the trunk version. It will probably also need code to disable it by default and allow configuration to enable it.

The real solution here is for the phone to de-register itself before it goes offline.

What’s wrong with sending the invite and handling the resulting timeout?

Hello David,
i’m not attempting to release / request this change as a patch in this stage.
regarding to:

[quote]The real solution here is for the phone to de-register itself before it goes offline.
[/quote]
we can’t count the phone to de-register:

  1. the app can be shutdown brutally (e.g not in a formal way: crash or by task manager)
  2. the app can get into a state that the ISP has blocked it’s SIP Traffic (for example he switched between Wifi and 3G)

[quote]What’s wrong with sending the invite and handling the resulting timeout?
[/quote]

  1. if the client closed the app right after the REGISTRATION . asterisk will consider the client as available, the invite will be sent and the caller will have to wait the specified waiting time (120 Seconds) until he will get UNAVAILABLE message
  2. we are sending both PUSH notification and SIP INVITE. so if for example the client opened the app (and REGISTERED) after he saw the push (usually it’s takes ~2 second to REGISTER) we need to to trigger re-invite and again we will have to wait 120 seconds

the target is to find some mechanism which allow me to know if the Callee is available before we are sending the INVITE

Thanks,
Nir Levi

Is there any stable solution for this topic ? I am facing with such scenario and I like to know how to implement push notification on asterisk.

The solution lies in designing the app properly so that it keeps a background process running to handle the invite and wake up the main part of the application. INVITE then fulfils its proper role as the push notification.