Hi all!
I'm using EVAPI module. Upon INVITE, Kamailio gets a list of routes from a
script using *evapi_async_relay*() . The EVAPI script (Python) then returns
a RTJson structure.
The Kamailio logic is set to iterate through each route and if at the end
all routes have failed (ex.: if all egress endpoints are unavailable), then
sends a EVAPI request using *evapi_relay*() to the script. Note that this
request is not asynchronous (using evapi_async_relay() would fail with
error stating that there is no transaction available....).
This is my evapi:message-received:
event_route[evapi:message-received]
{
# Parse the message format: RESPONSE:index:label:data
$var(msg) = $evapi(msg);
#$var(logmsg) = $(var(msg){s.substr,0,100});
xlog("L_INFO", "evapi:message-received - Received EVAPI message:
$var(msg) ...\n");
$var(type) = $(var(msg){s.select,0,:});
$var(tindex) = $(var(msg){s.select,1,:}{s.int});
$var(tlabel) = $(var(msg){s.select,2,:}{s.int});
$var(response) = $(var(msg){re.subst,/^[^:]*:[^:]*:[^:]*://});
xlog("L_INFO", "Part 0: '$var(type)'\n");
xlog("L_INFO", "Part 1: '$var(tindex)'\n");
xlog("L_INFO", "Part 2: '$var(tlabel)'\n");
xlog("L_INFO", "Part 3: '$var(response)'\n");
if ( $var(type) == "RESPONSE" && $var(tindex) =~ "^[0-9]+$" &&
$var(tlabel) =~ "^[0-9]+$" )
{
xlog("L_INFO", "evapi:message-received - RESPONSE index
$var(tindex) label $var(tlabel) \n");
xlog("L_INFO", "evapi:message-received - Continue Call
processing\n");
if (jansson_get("action", $var(response), "$var(action)")){
if ($var(action) == "CALL_REJECT"){
route(EVAPIRESPONSE);
}
}
# Resume transaction
t_continue("$var(tindex)", "$var(tlabel)", "EVAPIRESPONSE");
}
else
{
xlog("L_INFO", "evapi:message-received - invalid message received
from EVAPI. Cancelling the call \n");
t_reply("500", "Internal Server Error");
exit;
}
}
CALL_REJECT action is received after the *evapi_relay*() request to the
EVAPI script (python) that is launched after a route_failure.
For example, Kamailio requests for error mappings when a call has been
tried and no egress endpoint was reachable.
My EVAPIRESPONSE route block is:
route[EVAPIRESPONSE] {
xlog("L_INFO", "EVAPIRESPONSE - Resuming INVITE processing with index
$var(tindex) label $var(tlabel)\n");
xlog("L_INFO", "EVAPIRESPONSE - JSON : $var(response) \n");
# Test each condition individually
if ($var(response) == "FALSE" or $var(response) == "NO_ROUTES")
{
# Check if response is FALSE (drop the call)
xlog("L_ERR", "EVAPIRESPONSE - Python script returned FALSE or NO
ROUTES, dropping call\n");
$var(code) = 500;
$var(text) = "Internal Server Error";
route(REPLY_SAFE);
exit;
}
if (jansson_get("action", $var(response), "$var(action)")){
if ($var(action) == "DROP") {
jansson_get("error_code", $var(response), "$var(error_code)");
jansson_get("error_text", $var(response), "$var(error_text)");
xlog("L_INFO", "EVAPIRESPONSE - dropping call with returned
error $var(error_code) - $var(error_text) \n");
$var(code) = $var(error_code);
$var(text) = $var(error_text);
route(REPLY_SAFE);
}else
if ($var(action) == "CALL_REJECT")
{
jansson_get("reject", $var(response), "$var(sip_error)");
if ( "$var(sip_error)" == "" )
{
xlog("L_INFO", "EVAPIRESPONSE - CALL_REJECT with no
specific error code; return the received error\n");
return;
}
else
{
jansson_get("error_code", $var(sip_error),
"$var(error_code)");
jansson_get("error_text", $var(sip_error),
"$var(error_text)");
xlog("L_INFO", "EVAPIRESPONSE - CALL_REJECT with
$var(error_code) - $var(error_text)\n");
$var(code) = $var(error_code);
$var(text) = $var(error_text);
route(REPLY_SAFE);
}
}
}
# Process RTJSON routing
if (jansson_get("rtjson", $var(response), "$var(rtjson_str)")) {
jansson_get("retry_on_failure", $var(response),
"$dlg_var(retry_on_failure)");
xlog("L_DEBUG", "EVAPIRESPONSE - retry_on_failure =
$dlg_var(retry_on_failure) \n");
$dlg_var(rtjson_str) = $var(rtjson_str);
# Process routes from RTJSON
route(RTJSON_PROCESS);
} else {
xlog("L_ERR", "EVAPIRESPONSE - Invalid response format from
Python\n");
$var(code) = 500;
$var(text) = "Internal Server Error";
route(REPLY_SAFE);
exit;
}
}
# Tiny helper to reply correctly inside/outside TM
route[REPLY_SAFE] {
# validate code (default to 480 if bad/empty)
if (!($var(code) =~ "^[1-6][0-9][0-9]$")) $var(code) = 480;
if ($var(text) == "") $var(text) = "Temporarily Unavailable";
# remove CR/LF that can break the reason phrase
$var(text) = $(var(text){re.subst,/[\r\n]/ /g});
if (t_check_trans()) {
xlog("L_INFO", "REPLY_SAFE - replying with t_reply\n");
t_reply("$var(code)", "$var(text)");
} else {
xlog("L_INFO", "REPLY_SAFE - replying with send_reply\n");
send_reply("$var(code)", "$var(text)");
}
exit;
}
I have tried with t_reply, sl_send_reply, send_reply but the SIP trace only
shows SIP 503 Service Unavailable being sent from Kamailio to the ingress
endpoint.
Setting log to DEBUG level doesn't show anything neither:
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169257 457395 1 1 OPTIONS 123} <script>: evapi:message-received
- Received EVAPI message: RESPONSE:2825:1816929401:{"action":
"CALL_REJECT", "call_id": "338632827805594c569838281a742c0b@10.20.0.5:5060",
"reject": {"error_code": 480, "error_text": "some text"}} ...
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169485 457395 1 1 OPTIONS 123} <script>: Part 0: 'RESPONSE'
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169497 457395 1 1 OPTIONS 123} <script>: Part 1: '2825'
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169506 457395 1 1 OPTIONS 123} <script>: Part 2: '1816929401'
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169514 457395 1 1 OPTIONS 123} <script>: Part 3: '{"action":
"CALL_REJECT", "call_id": "338632827805594c569838281a742c0b@10.20.0.5:5060",
"reject": {"error_code": 480, "error_text": "some text"}}'
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169639 457395 1 1 OPTIONS 123} <script>: evapi:message-received
- RESPONSE index 2825 label 1816929401
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169654 457395 1 1 OPTIONS 123} <script>: evapi:message-received
- Continue Call processing
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169816 457395 1 1 OPTIONS 123} <script>: EVAPIRESPONSE -
Resuming INVITE processing with index 2825 label 1816929401
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169829 457395 1 1 OPTIONS 123} <script>: EVAPIRESPONSE - JSON :
{"action": "CALL_REJECT", "call_id": "
338632827805594c569838281a742c0b@10.20.0.5:5060", "reject": {"error_code":
480, "error_text": "some text"}}
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.169998 457395 1 1 OPTIONS 123} <script>: EVAPIRESPONSE -
CALL_REJECT with 480 - some text
Sep 5 19:16:48 ire-lab-kamailio1 kamailio[457395]: INFO:
{1757092608.170253 457395 1 1 OPTIONS 123} <script>: REPLY_SAFE - replying
with send_reply
And nothing helps is found in logs.
The goal is to send a custom SIP error and message depending if the
error_code and error_text is specified. If not, then the message received
from egress endpoint should be forwarded to the ingress endpoint.
I just can't understand why the response is always SIP 503.
Here is a SIP trace:
[image: image.png]
Any suggestions?
Thanks in advance.
Atenciosamente / Kind Regards / Cordialement / Un saludo,
*Sérgio Charrua*