Re: send_reply not accepting values

Henning Westerholt via sr-users <[email protected]>
Newsgroups gmane.comp.voip.ser
Message-ID <AS8PR07MB8103B1DA1C6881DCC0ADFD85BF09A@AS8PR07MB8103.eurprd07.prod.outlook.com>
Thanks for reporting back, great that its solved.

Cheers,

Henning

From: Sergio Charrua <[email protected]>
Sent: Thursday, September 11, 2025 3:24 PM
To: Henning Westerholt <[email protected]>
Cc: Kamailio (SER) - Users Mailing List <[email protected]>
Subject: Re: [SR-Users] send_reply not accepting values

Found the issue!
for future reference, after every evapi_{async}_relay() call, there should be an exit().
In the route[NOTIFY_CALL_REJECT] block, after the evapi_async_relay call,  I added an exit(); and it worked ! Solved both issues I was getting!



Atenciosamente / Kind Regards / Cordialement / Un saludo,



Sérgio Charrua



On Thu, Sep 11, 2025 at 1:00 PM Sergio Charrua <[email protected]<mailto:[email protected]>> wrote:
Hi Henning,

Below is part of the Kamailio script that i'm developing. I've run with debug level 3, but there is nothing helpful found on log.
There are 2 issues which i cannot get a solution, so far:
1 - after a 1st call to EVAPI script where the list of routes are returned (RTJson object), the transaction continues fine. When the INVITE cannot be relayed to the egress endpoint (because it is off-line) there is the obvious 408 Session Timeout error, the route[NOTIFY_CALL_REJECT] is executed calling EVAPI script and when event_route[evapi:message-received] is executed apparently the t_continue() fails because there is no transaction available! I have tested multiple ways, with t_new_trans + evapi_relay(), just evapi_realy() or evapi_async_relay but in the NOTIFY_CALL_REJECT block, but always get the same error

2 - that nasty 503 - Service Unavailable error which, IMHO, doesn't make sense.

Greatly appreciate the help.


These are parts of the logs that are generated, with debug level 3:

Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.971352 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: EVAPIRESPONSE - Resumed with JSON: {"action": "ROUTE", "call_id": "my_call_id", "error_code": 0, "error_text": "", "retry_on_failure": "0", "rtjson": {"routes": [{"branch_flags": 8, "default_timeout": 10, "dst_uri": "sip:10.20.0.6:5060<http://10.20.0.6:5060>", "headers": {"extra": "X-Hdr-A: abc\r\n", "from": {"display": "Alice", "uri": "sip:[email protected]@10.20.0.5<http://10.20.0.5>"}, "to": {"display": "Bob", "uri": "sip:[email protected]<mailto:sip%[email protected]>"}}, "route_id": "123", "socket": "udp:10.20.0.4:5060<http://10.20.0.4:5060>", "uri": "sip:[email protected]@10.20.0.5<http://10.20.0.5>"}, {"branch_flags": 8, "default_timeout": 10, "dst_uri": "sip:10.20.0.7:5060<http://10.20.0.7:5060>", "headers": {"extra": "P-Asserted-Identity: sip:+12122478000;[email protected]:5060<http://[email protected]:5060>\r\nIdentity: eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly9wcm9kMDAxLXByb2QwMTEtY3IucmJibmlkaHViLmNvbS9DbWJ5aVlISWd6L3Rlc3RucHJvZHB1YmxpYyJ9.eyJhdHRlc3QiOiJDIiwiZGVzdCI6eyJ0biI6WyIxMjAyMzI0MzAwMCJdfSwiaWF0IjoxNzEwMzk1NjAwLCJvcmlnIjp7InRuIjoiMTIxMjM0NzgwMzQifSwib3JpZ2lkIjoiYmFkYTM4OWYtOWM3MS00NWE2LThlNzgtODRjNDgwZjJlNjk5In0.xCMtauutY5K1kyS5htnXohjRSYluEFs_YIjURmTxhzifGaLDfF5pYgL_vt6jIiwvghBbL3V0Cw2UcPb-YMl8Tg;info=<https://prod001-prod011-cr.rbbnidhub.com/CmbyiYHIgz/testnprodpublic>;alg=ES256;ppt=shaken\r\n", "from": {"display": "Mary", "uri": "sip:[email protected]@10.20.0.5<http://10.20.0.5>"}, "to": {"display": "Dave", "uri": "sip:[email protected]<mailto:sip%[email protected]>"}}, "path": "", "route_id": "456", "socket": "udp:10.20.0.4:5060<http://10.20.0.4:5060>", "uri": ""}], "routing": "serial", "success": "True", "version": "1.0"}}
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.971782 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: EVAPIRESPONSE - retry_on_failure = 0
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.971860 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: RTJSON_PROCESS - Initializing RTJSON routes
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.972103 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: RELAY - Modifying SIP headers from INVITE
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: ERROR: {1757587920.972120 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} app_jsdt [app_jsdt_mod.c:332]: w_app_jsdt_run(): p1 too long 1319
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: ERROR: {1757587920.972210 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} pv [pv_core.c:261]: pv_get_ruri(): failed to parse the R-URI
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.972651 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_BRANCH - {"routes":[{"branch_flags":8,"default_timeout":10,"dst_uri":"sip:10.20.0.6:5060<http://10.20.0.6:5060>","headers":{"extra":"X-Hdr-A: abc\r\n","from":{"display":"Alice","uri"
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.972697 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_BRANCH - using new route index 0
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: ERROR: {1757587920.972835 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} pv [pv_core.c:261]: pv_get_ruri(): failed to parse the R-URI
Sep 11 12:52:00 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587920.972835 567385 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_BRANCH - New branch [1] to <null> - route ID 123
Sep 11 12:52:03 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587923.201293 567378 1 1 OPTIONS 123} <script>: Destination down: OPTIONS sip:10.20.0.7:5060<http://10.20.0.7:5060> (<null>)
Sep 11 12:52:03 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587923.201722 567378 1 1 OPTIONS 123} <script>: NOTIFY_ENDPOINT_STATUS - notifying XPhere with SBC_STATUS:{"type":"SBC_STATUS","endpoint":"sip:10.20.0.7:5060<http://10.20.0.7:5060>","sip_code":0,"reason":"DOWN","timestamp":"1757587923.201674"}
Sep 11 12:52:03 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587923.201827 567378 1 1 OPTIONS 123} <script>: Destination down: OPTIONS sip:10.20.0.6:5060<http://10.20.0.6:5060> (<null>)
Sep 11 12:52:03 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587923.202010 567378 1 1 OPTIONS 123} <script>: NOTIFY_ENDPOINT_STATUS - notifying XPhere with SBC_STATUS:{"type":"SBC_STATUS","endpoint":"sip:10.20.0.6:5060<http://10.20.0.6:5060>","sip_code":0,"reason":"DOWN","timestamp":"1757587923.201975"}
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587925.951168 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: SPOOL_CALL_STATUS - spooling CALL_STATUS SBC_STATUS:{"type":"SBC_STATUS","endpoint":"sip:10.20.0.6:5060<http://10.20.0.6:5060>","sip_code":0,"reason":"DOWN","timestamp":"1757587923.201975"}
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587925.951877 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_FAILURE - next RTJson route selected - relaying call - retry_on_failure = 0 route_index=1
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587925.951944 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: RELAY - Modifying SIP headers from INVITE
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: ERROR: {1757587925.951951 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} app_jsdt [app_jsdt_mod.c:332]: w_app_jsdt_run(): p1 too long 1319
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587925.952251 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_BRANCH - {"routes":[{"branch_flags":8,"default_timeout":10,"dst_uri":"sip:10.20.0.6:5060<http://10.20.0.6:5060>","headers":{"extra":"X-Hdr-A: abc\r\n","from":{"display":"Alice","uri"
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587925.952311 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_BRANCH - using new route index 1
Sep 11 12:52:05 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587925.952425 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_BRANCH - New branch [2] to sip:[email protected]<mailto:sip%[email protected]> - route ID 456
Sep 11 12:52:10 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587930.951206 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: SPOOL_CALL_STATUS - spooling CALL_STATUS SBC_STATUS:{"type":"SBC_STATUS","endpoint":"sip:10.20.0.6:5060<http://10.20.0.6:5060>","sip_code":0,"reason":"DOWN","timestamp":"1757587923.201975"}
Sep 11 12:52:10 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587930.951665 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_FAILURE - retry_on_failure = 0
Sep 11 12:52:10 ire-lab-kamailio1 kamailio[567378]: ERROR: {1757587930.951721 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: MANAGE_FAILURE - no more routes available for RTJson
Sep 11 12:52:10 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587930.952238 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: NOTIFY_CALL_REJECT - notifying XPhere with CALL_REJECT:54929:139397316:{"type":"CALL_REJECT","remote_ip_port":"10.20.0.5:5060<http://10.20.0.5:5060>","local_ip_port":"10.20.0.4:5060<http://10.20.0.4:5060>","protocol":"udp","sip_error":{"error_code":"408","error_text":"Request Timeout","from":"\"Anonymous\" <sip:[email protected]>;tag=as54ab6b37","to":"<sip:[email protected]<mailto:sip%[email protected]>>","call_id":"[email protected]:5060<http://[email protected]:5060>"},"crankback_history":[{"route_id":"123","error_code":408,"reason":"Request Timeout"},{"route_id":"456","error_code":408,"reason":"Request Timeout"}],"timestamp":"1757587930.952136"}
Sep 11 12:52:10 ire-lab-kamailio1 kamailio[567378]: NOTICE: {1757587930.952260 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} tm [tm.c:1735]: w_t_newtran(): transaction already in process 0x7f4622dccf30
Sep 11 12:52:10 ire-lab-kamailio1 kamailio[567378]: INFO: {1757587930.952368 567378 1 102 INVITE [email protected]:5060<http://[email protected]:5060>} <script>: NOTIFY_CALL_REJECT - CALL_REJECT:54929:139397316:{"type":"CALL_REJECT","remote_ip_port":"10.20.0.5:5060<http://10.20.0.5:5060>","local_ip_port":"10.20.0.4:5060<http://10.20.0.4:5060>","protocol":"udp","sip_error":{"error_code":"408","error_text":"Request Timeout","from":"\"Anonymous\" <sip:[email protected]>;tag=as54ab6b37","to":"<sip:[email protected]<mailto:sip%[email protected]>>","call_id":"[email protected]:5060<http://[email protected]:5060>"},"crankback_history":[{"route_id":"123","error_code":408,"reason":"Request Timeout"},{"route_id":"456","error_code":408,"reason":"Request Timeout"}],"timestamp":"1757587930.952136"}
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587931.484662 567385 1 1 OPTIONS 123} <script>: evapi:message-received - Received EVAPI message: RESPONSE:54929:139397316:{"action": "CALL_REJECT", "call_id": "[email protected]:5060<http://[email protected]:5060>", "reject": {"error_code": 480, "error_text": "some text"}}
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587931.484727 567385 1 1 OPTIONS 123} <script>: Part 0: 'RESPONSE'
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587931.484733 567385 1 1 OPTIONS 123} <script>: Part 1: '54929'
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587931.484739 567385 1 1 OPTIONS 123} <script>: Part 2: '139397316'
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587931.484743 567385 1 1 OPTIONS 123} <script>: Part 3: '{"action": "CALL_REJECT", "call_id": "[email protected]:5060<http://[email protected]:5060>", "reject": {"error_code": 480, "error_text": "some text"}}'
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: INFO: {1757587931.484768 567385 1 1 OPTIONS 123} <script>: evapi:message-received - t_continue for 54929/139397316
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: WARNING: {1757587931.484775 567385 1 1 OPTIONS 123} tm [t_suspend.c:197]: t_continue_helper(): active transaction not found
Sep 11 12:52:11 ire-lab-kamailio1 kamailio[567385]: WARNING: {1757587931.484775 567385 1 1 OPTIONS 123} tmx [tmx_mod.c:818]: w_t_continue(): resuming the processing of transaction [54929:139397316] failed
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: tm [timer.c:642]: wait_handler(): finished transaction: 0x7f4622dc3da0 (p:0x7f4622bc7700/n:0x7f4622bc7700)
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: tm [h_table.c:133]: free_cell_helper(): freeing transaction 0x7f4622dc3da0 from timer.c:651
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: tm [timer.c:642]: wait_handler(): finished transaction: 0x7f4622dc61e0 (p:0x7f4622bc76a0/n:0x7f4622bc76a0)
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: tm [h_table.c:133]: free_cell_helper(): freeing transaction 0x7f4622dc61e0 from timer.c:651
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: dialog [dlg_cseq.c:116]: dlg_cseq_prepare_new_msg(): prepare new msg for cseq update operations
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/parse_fline.c:247]: parse_first_line(): first line type 1 (request) flags 1
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/msg_parser.c:721]: parse_msg(): SIP Request:
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/msg_parser.c:722]: parse_msg():  method:  <OPTIONS>
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/msg_parser.c:724]: parse_msg():  uri:     <sip:10.20.0.7:5060<http://10.20.0.7:5060>>
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/msg_parser.c:726]: parse_msg():  version: <SIP/2.0>
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/parse_hname2.c:314]: parse_sip_header_name(): parsed header name [Via] type 1
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/parse_via.c:1309]: parse_via_param(): Found param type 232, <branch> = <z9hG4bK379b.1343f1a4000000000000000000000000.0>; state=16
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/parse_via.c:2663]: parse_via(): end of header reached, state=5
Sep 11 12:52:17 ire-lab-kamailio1 kamailio[567379]: DEBUG: <core> [core/parser/msg_parser.c:591]: parse_headers(): Via found, flags=2


And the Kamailio script:

#!KAMAILIO

#!define FLT_ACC 1
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3
#!define WITH_ACL
#!define WITH_MONITORING
##!define WITH_DMQ  # uncomment if DMQ is needed

####### Global Parameters #########
debug=3
log_stderror=no
memdbg=5
memlog=5
log_facility=LOG_LOCAL0
fork=yes
children=2
log_prefix_mode = 1
log_prefix="{$TV(Sn) $pp $mt $hdr(CSeq) $ci} "
disable_sctp = yes
force_rport  = yes
rundir="/tmp"
pv_buffer_size=65536



####### Modules Section ########
mpath="/usr/local/lib64/kamailio/modules/"

loadmodule "jsonrpcs.so"
loadmodule "db_mysql.so"
loadmodule "db_cluster.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "acc.so"
loadmodule "evapi.so"
loadmodule "jansson.so"
loadmodule "rtjson.so"
loadmodule "dispatcher.so"
loadmodule "dialog.so"
loadmodule "permissions"
loadmodule "app_jsdt.so"
#!ifdef WITH_DMQ
loadmodule "dmq.so"
#!endif
loadmodule "htable.so"

include_file "listen.cfg"
include_file "db_conn.cfg"

####### Setting module-specific parameters #######
# ----- Permissions params -----
modparam("permissions", "db_url", "cluster://k1")
modparam("permissions", "db_mode", 1)
modparam("permissions", "reload_delta", 10)

# ----- jsonrpcs params -----
modparam("jsonrpcs", "pretty_format", 1)
/* set the path to RPC fifo control file */
modparam("jsonrpcs", "fifo_name", "/tmp/kamailio_ire1_rpc.fifo")
/* set the path to RPC unix socket control file */
modparam("jsonrpcs", "dgram_socket", "/tmp/kamailio_ire1_rpc.sock")

# ----- ctl params -----
/* set the path to RPC unix socket control file */
modparam("ctl", "binrpc", "unix:/tmp/kamailio_ire1_ctl")


# ----- ctl params -----
/* set the path to RPC unix socket control file */
modparam("ctl", "binrpc", "unix:/tmp/kamailio_ire1_ctl")

# ----- tm params -----
modparam("tm", "auto_inv_100",             1)      # automatically send a 100 reply to INVITEs (0 is off).
modparam("tm", "max_inv_lifetime",         180000) # Maximum time an INVITE transaction is allowed to be active (in milliseconds).
modparam("tm", "failure_reply_mode",       3)      # all previous branches are discarded if there is a new serial forking leg. This is the default behaviour
modparam("tm", "fr_timer",                 5000)   # Timer which hits if no final reply for a request or ACK for a negative INVITE reply arrives (in milliseconds).
#modparam("tm", "fr_inv_timer",             30000)   # Timer which hits if no final reply for an INVITE arrives after a provisional message was received (in milliseconds).
#modparam("tm", "restart_fr_on_each_reply", 1)      # if 1, fr_inv_timer for an INVITE transaction will be restarted for each provisional reply received (rfc3261 mandated behaviour).
                                                   # if 0, he fr_inv_timer will be restarted only for the first provisional replies and for increasing replies greater or equal 180
modparam("tm", "retr_timer1",              1000)   # Initial
modparam("tm", "cancel_b_method",          2)      # used when attempting to CANCEL an unreplied transaction branch (a branch where no response was received). The possible values are 0, 1, and 2.

# ----- rr params -----
modparam("rr", "enable_full_lr",    1)
modparam("rr", "append_fromtag",    1)
modparam("rr", "enable_double_rr",  0)

# ----- evapi params -----
modparam("evapi", "workers", 4)
modparam("evapi", "bind_addr", "10.20.0.4:8448<http://10.20.0.4:8448>")
modparam("evapi", "netstring_format", 1)


# ----- dmq params -----
#!ifdef WITH_DMQ
modparam("dmq", "server_address",       DMQ_SERVER_ADDRESS )
modparam("dmq", "notification_address", DMQ_NOTIFICATION_ADDRESS_1 )
# repeat previous line according to number of notification addresses of your environment
modparam("dmq", "multi_notify",         0)
modparam("dmq", "num_workers",          6)
modparam("dmq", "ping_interval",        60)
#modparam("dmq_usrloc", "enable",        1)
#!endif

# ----- dialog params -----
# Optimized for high CPS
modparam("dialog", "db_mode",               1)
modparam("dialog", "db_url",                "cluster://k1")
modparam("dialog", "dlg_flag",         4)
modparam("dialog", "track_cseq_updates", 1)
modparam("dialog", "dlg_match_mode", 1)
modparam("dialog", "default_timeout", 43200) // 12hours call duration limit by default
modparam("dialog", "profiles_with_value", "concurrent")
modparam("dialog", "profiles_no_value", "total")
modparam("dialog", "hash_size",         16384)  # Increased for 4000+ CPS
#!ifdef WITH_DMQ
modparam("dialog", "enable_dmq",            1)
#!endif

# ----- dispatcher params -----
#!ifdef WITH_MONITORING
    modparam("dispatcher", "db_url",                        "cluster://k1")         # Use DBURL variable for database parameters
    modparam("dispatcher", "ds_ping_interval",              3)                      # How often to ping destinations to check status
    modparam("dispatcher", "ds_ping_method",                "OPTIONS")              # Send SIP Options ping
    modparam("dispatcher", "ds_ping_from",                  "sip:[email protected]")
    modparam("dispatcher", "ds_probing_threshold",          3)                      # How many failed pings in a row do we need before we consider it down
    modparam("dispatcher", "ds_inactive_threshold",         2)                      # How many sucessful pings in a row do we need before considering it up
    modparam("dispatcher", "ds_ping_latency_stats",         1)                      # Enables stats on latency
    modparam("dispatcher", "ds_probing_mode",               1)                      # Keeps pinging gateways when state is known (to detect change in state)
    modparam("dispatcher", "ds_ping_latency_stats",         1)                      # for algorithm 13 - Latency check
    modparam("dispatcher", "ds_latency_estimator_alpha",    200)                    # configure latency estimator
    modparam("dispatcher", "reload_delta",                  5)                      # number of seconds to wait before a new reload of dispatcher records is executed. default is 5
    modparam("dispatcher", "flags",                         2)                      # Enable database storage of flags
#!endif

# ----- app_jsdt params -----
modparam("app_jsdt", "load",                 "/etc/kamailio/functions.js")

# ----- rtjson params -----
modparam("rtjson", "xavp_cfg", "rtjson")

# ----- htable definition for evapi_event message response processing
modparam("htable", "db_url", "cluster://k1")
modparam("htable", "htable", "evcache=>size=64;autoexpire=120;dbmode=1;")


####### Routing Logic ########

# Main SIP request routing logic
request_route {

    $avp(START_TIME)=$utimef(%Y-%m-%d %H:%M:%S);
    $var(send_sock) = $null;


    #!ifdef WITH_ACL
        $avp(GROUPID) = allow_address_group($si, $sp);

        if ( $avp(GROUPID) == 100 || !allow_address_group($si, $sp) ) {
                xlog("L_INFO", "INIT - $si:$sp is not in the allowed ACL Group ID !\n");
                # uncoment below to return SIP 401 error to non-allowed clients
                #sl_reply("401", "Address not allowed");
                exit;
        }

        if (is_method("OPTIONS")){
            sl_send_reply("200","OK");
            exit;
        }
    #!endif

    #!ifdef WITH_DMQ
    route(HANDLE_DMQ);
    #!endif

    # per request initial checks
    route(REQINIT);

    # CANCEL processing
    if (is_method("CANCEL")) {
        if (t_check_trans()) {
            xlog("L_INFO","INIT - CANCEL detected\n");
            route(SEND_CALL_STATUS);
            t_relay();
        }
        exit;
    }

    # handle retransmissions
    if (!is_method("ACK")) {
        if(t_precheck_trans()) {
            t_check_trans();
            exit;
        }
        t_check_trans();
    }

    # handle requests within SIP dialogs
    route(WITHINDLG);

    # record routing for dialog forming requests (in case they are routed)
# - remove preloaded route headers
remove_hf("Route");
if (is_method("INVITE"))
record_route();

    # record routing for dialog forming requests
    if (is_method("INVITE"))
    {
        $var(json_headers) = $null;
        $var(route_index)  = 0;
        $var(retry)        = 0;
        setflag(1);  # Using the same flag as dlg_flag from dialog module
        $dlg_var(routeid) = $null;
        $dlg_var(branch_stats) = '[]'; # empty JSON array for keeping track of route status (failures)

        dlg_manage();
        route(HANDLE_INVITE);
        exit;
    }

    route(RELAY);
    exit;
}


# Handle INVITE requests
route[HANDLE_INVITE] {
    # Send INVITE details to Python script
    # Convert headers to JSON
    //if ($var(s:json_headers) == $null)
        route(HEADERS_TO_JSON);

    # Send to Python via EVAPI
    xlog("L_INFO", "HANDLE_INVITE - suspended transaction for INVITE. Index: $T(id_index) - Label: $T(id_label) \n" );
    $var(evmsg) = "INVITE:" + $T(id_index) + ":" + $T(id_label) + ":" + $var(json_headers);

    evapi_async_relay("INVITE:$T(id_index):$T(id_label):$var(json_headers)");
    exit;
}

# Handle responses from Python script
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<http://s.int>});
    $var(tlabel) = $(var(msg){s.select,2,:}{s.int<http://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 - t_continue for $var(tindex)/$var(tlabel)\n");
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;
    }
}


# Resume processing after Python response
route[EVAPIRESPONSE] {
    xlog("L_INFO", "EVAPIRESPONSE - Resuming Call 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");
        //t_reply("500", "Internal Server Error");
        $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);
            exit;
        }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);
                exit;
            }
        }
    }

    # 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_INFO", "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_INFO", "EVAPIRESPONSE - Invalid response format from Python\n");
        //t_reply("500", "Internal Server Error");
        $var(code) = 500;
        $var(text) = "Internal Server Error";
        route(REPLY_SAFE);
        exit;
    }
}

route[NOTIFY_CALL_REJECT]
{
    # Send route failure notification to Python
    $var(failure_data) = $null;
    jansson_set("string" , "type"           , "CALL_REJECT"             , "$var(failure_data)" );

    jansson_set("string" , "remote_ip_port" , "$si:$sp"                 , "$var(failure_data)" );
    jansson_set("string" , "local_ip_port"  , "$RAi:$RAp"               , "$var(failure_data)" );
    jansson_set("string" , "protocol"       , "$pr"                     , "$var(failure_data)" );

    jansson_set("string", "error_code"      , "$T(reply_code)"          , "$var(sip_error_code_obj)");
    jansson_set("string", "error_text"      , "$T(reply_reason)"        , "$var(sip_error_code_obj)");
    jansson_set("string", "from"            , "$hdr(From)"              , "$var(sip_error_code_obj)");
    jansson_set("string", "to"              , "$hdr(To)"                , "$var(sip_error_code_obj)");
    jansson_set("string", "call_id"         , "$ci"                     , "$var(sip_error_code_obj)" );

    jansson_set("obj"   , "sip_error"       , "$var(sip_error_code_obj)", "$var(failure_data)");
    jansson_set("array" ,"crankback_history", "$dlg_var(branch_stats)"  ,  "$var(failure_data)");
    jansson_set("string", "timestamp"       , "$TV(Sn)"                 , "$var(failure_data)" );

    $var(evmsg) = "CALL_REJECT:" + $T(id_index) + ":" + $T(id_label) + ":" + $var(failure_data);
    xlog("L_INFO","NOTIFY_CALL_REJECT - notifying XPhere with $var(evmsg) \n");

    evapi_relay("CALL_REJECT:$T(id_index):$T(id_label):$var(failure_data)");
}


# 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");
        sl_send_reply("$var(code)", "$var(text)");
    }
    xlog("L_INFO", "REPLY_SAFE - replied $var(code) - $var(text)\n");
    exit;
}

# Failure route
failure_route[MANAGE_FAILURE] {

    if (t_is_canceled()) {
        exit;
    }

    route(SPOOL_CALL_STATUS);
    route(PIN_SOCKET);
    # Try next route if available
    if (rtjson_next_route()) {
        # increase the route index
        $var(route_index) = $var(route_index) + 1;
        # Try next route from RTJson if available
        xlog("L_INFO","MANAGE_FAILURE - next RTJson route selected - relaying call - retry_on_failure = $dlg_var(retry_on_failure) route_index=$var(route_index)\n");
        route(RELAY);
    } else {
        xlog("L_INFO","MANAGE_FAILURE - retry_on_failure = $dlg_var(retry_on_failure)\n");
        if ($dlg_var(retry_on_failure) == 1)
        {   // if the routes received have property retry_on_failure = 1 then
            // request a new list of routes and retry
            $var(retry) = 1;
            $var(route_index) = 0;
            xlog("L_INFO","MANAGE_FAILURE - all routes failed. requesting new RTJson\n");
            route(HANDLE_INVITE); // send a new request for new routes
        }else{
            # No more routes available
            xlog("L_ERROR","MANAGE_FAILURE - no more routes available for RTJson\n");
            #### FIX ME - implement CALL_REJECT
            route(NOTIFY_CALL_REJECT);
            t_reply("503", "Service Unavailable!");
            exit;
        }
    }

    exit;
}

# Relay route
route[RELAY] {
    if (is_method("INVITE|UPDATE|BYE"))  # |BYE
    {
        xlog("L_INFO","RELAY - Modifying SIP headers from INVITE\n");
        jsdt_run("modify_invite_headers", "$dlg_var(rtjson_str)", "$var(route_index)" );
        if (!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
    }
    if (is_method("INVITE|UPDATE")) {
        if (!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
    }
    if (is_method("INVITE")) {
        if (!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
    }
    route(PIN_SOCKET);
    if (!t_relay())
    {
        xlog("L_INFO","RELAY - Returned from event");
        sl_reply_error();
    }
    exit;
}

route[PIN_SOCKET] {
    # routing block that sets the socket IP:PORT to SIP messages
    # sent to the egress side
    if (is_method("INVITE") && !has_totag()) {
        dlg_manage();
        $var(proto) = $pr;                  # "udp" / "tcp"
        xlog("L_DEBUG", "PIN_SOCKET - stored dlg_sock=< $pr:$Ri:$Rp > \n");
        $dlg_var(send_sock) = "$pr:$Ri:$Rp";      # e.g. udp:10.20.0.4:5061<http://10.20.0.4:5061>
    }

    # choose the socket we’ll force
    if ($dlg_var(send_sock) != $null) {
        $var(sock) = $dlg_var(send_sock);
    } else {
        $var(proto) = $pr;
        xlog("L_DEBUG", "PIN_SOCKET - setting $pr:$Ri:$Rp \n");
        $var(sock)  = "$pr:$Ri:$Rp";              # requests without dialog
    }

    xlog("L_DEBUG", "PIN_SOCKET - forcing <$var(sock)> (recv $pr:$Ri:$Rp)\n");
    set_send_socket($var(sock));
    xlog("L_DEBUG", "PIN_SOCKET - $$var(sock) = $var(sock)  -  $$dlg_var(send_sock) = $dlg_var(send_sock) \n");
}




Atenciosamente / Kind Regards / Cordialement / Un saludo,



Sérgio Charrua





On Tue, Sep 9, 2025 at 2:39 PM Henning Westerholt <[email protected]<mailto:[email protected]>> wrote:
Hello,

did not looked to the whole script, but the usual action would be enabling the debug log and see where the 503 is actually generated from.

Cheers,

Henning

From: Sergio Charrua via sr-users <[email protected]<mailto:[email protected]>>
Sent: Freitag, 5. September 2025 19:34
To: Kamailio (SER) - Users Mailing List <[email protected]<mailto:[email protected]>>
Cc: Sergio Charrua <[email protected]<mailto:[email protected]>>
Subject: [SR-Users] send_reply not accepting values

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<http://s.int>});
    $var(tlabel) = $(var(msg){s.select,2,:}{s.int<http://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": "[email protected]:5060<http://[email protected]: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": "[email protected]:5060<http://[email protected]: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": "[email protected]:5060<http://[email protected]: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:

[cid:[email protected]]

Any suggestions?

Thanks in advance.


Atenciosamente / Kind Regards / Cordialement / Un saludo,



Sérgio Charrua

__________________________________________________________
Kamailio - Users Mailing List - Non Commercial Discussions -- [email protected]
To unsubscribe send an email to [email protected]
Important: keep the mailing list in the recipients, do not reply only to the sender!
image001.png (image/png, 29.4 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.