This brief tutorial shows how to “freeze” SIP transaction to the moment the subscriber wakes up. The logic is simple here:
- Asterisk sends SIP INVITE to Kamailio SIP Proxy
- Kamailio detects device type by specific X-header and freezes incoming SIP transaction
- Kamailio sends “push” via http request to PHP script
- Once Kamailio detects new REGISTER from device, it resumes transaction
- Kamailio sends SIP INVITE to the subscriber
Module settings:
#htable module setting. vtp keeps transaction details.modparam("htable", "htable", "vtp=>size=10;autoexpire=120;")
Kamailio script building blocks:
#Detecting device type via custom SIP header X-phone.if ( (is_method("INVITE")) && (!has_totag()) && ($(hdr(X-phone) =~ "iphone") ) { send_reply("100", "Suspending"); route(SUSPEND); }#Suspending transaction and store index and label in vtp for the future needs.route[SUSPEND] { if ( !t_suspend() ) { xlog("L_ERROR","[SUSPEND] failed suspending trasaction [$T(id_index):$T(id_label)]\n"); send_reply("501", "Suspending error"); exit; } else { xlog("L_INFO","[SUSPEND] suspended transaction [$T(id_index):$T(id_label)] $fU=> $rU\n"); $sht(vtp=>id_index::$rU) = $T(id_index); $sht(vtp=>id_label::$rU) = $T(id_label); xlog("L_INFO","[SUSPEND] htable key value [$sht(vtp=>id_index::$rU) -- $sht(vtp=>id_label::$rU)]\n"); route(SENDPUSH); exit; }
In my case Kamailio runs the intermediate PHP script (push.php) with needed parameters for sending request to APN. You might use app_luamodule to push directly from Kamailio.
#Below is a pushing service. It calls push.php script with parameters. Htable $sht(tokens=>$rU) keeps needed token. And after PHP script connects to APN.route[SENDPUSH] { ... http_client_query("http://url/push.php", "user=$rU\r\npn-tok=$sht(tokens=>$rU)\r\n","Content-Type: text/plain", "$var(result)"); ... sl_send_reply("100", "Pushing"); }
Here we are detecting incoming REGISTER message from pushed device:
#Unfreezing by new incoming REGISTER message. if ( (is_method("REGISTER")) && (($hdr(Expires) != "0") || ($hdr(Contact) !~ "expires=0")) && ($sht(vtp=>id_index::$tU) != $null) ) { xlog("L_INFO", "New $rm ru=$ru tu=$tu \n"); route(JOIN); }
Resuming SIP transaction using stored label and index:
#Resuming transaction.route[JOIN] { xlog("L_INFO","[JOIN] htable key value [$sht(vtp=>id_index::$tU) -- $sht(vtp=>id_label::$tU)]\n"); t_continue("$sht(vtp=>id_index::$tU)", "$sht(vtp=>id_label::$tU)", "RESUME"); }#Lookup into location database and relaying.route[RESUME] { lookup("location"); xlog("L_INFO","[RESUME] rm=$rm ru=$ru du=$du \n"); t_relay(); exit; }