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;
This is how should implement dialplan with the patch:
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();
}
}
}