The kamailio script, completely stateless as I do not
need to keep track of the sessions, iterates through one of the JSON branches and adds the
destination URLs to the Contact header and replies a SIP 300 Multiple Choices.
The term 'stateless' in the scope of a SIP proxy doesn't mean to keep track of
the session (or the dialog). It means tracking the state of the transaction. In order to
pause the current transaction and resume it (using http_async_query()), a stateful
transaction must be created within Kamailio - and you've done this when you call
`t_newtran()`. As a recommendation, rather than using `sl_send_reply()`, `t_reply()`, or
`t_send_reply()`, just use `send_reply()`, which will send the reply statelessly if
there's no transaction, and statefully if there is a transaction.
If you want to make your replies LOOK stateless to request source, disable automatic 100
Trying from the TM module.
Kaufman
Senior Voice Engineer
E: bkaufman(a)bcmone.com
SIP.US Client Support: 800.566.9810 | SIPTRUNK Client Support: 800.250.6510 |
Flowroute Client Support: 855.356.9768
[img]<https://www.sip.us/>
[
img]<https://www.siptrunk.com/>
[
img]<https://www.flowroute.com/>
From: Sergio Charrua via sr-users <sr-users(a)lists.kamailio.org>
Sent: Monday, April 8, 2024 10:13 AM
To: Kamailio (SER) - Users Mailing List <sr-users(a)lists.kamailio.org>
Cc: Sergio Charrua <sergio.charrua(a)voip.pt>
Subject: [SR-Users] making HTTP requests in stateless redirects
CAUTION: This email originated from outside the organization. Do not click links or open
attachments unless you recognize the sender and know the content is safe.
Hi all!
For testing purposes, while I am waiting for the ST/SH REST API to be available from other
teams, I developed a small python REST API that returns a mockup of a JSON object with
some of the required values.
The kamailio script, completely stateless as I do not need to keep track of the sessions,
iterates through one of the JSON branches and adds the destination URLs to the Contact
header and replies a SIP 300 Multiple Choices.
This works: the UAC does receive the SIP response with the Contacts , but it also receives
a SIP 500 error message right after, and I can't figure out why. And i bet this is
simple to solve....
Any clue? I'm aware I'm not processing ACK messages, but the sl_send_reply 403
should do the trick right? ... at least while testing....
Also, as this is a stateless script, is there another way of using async http or making
http requests to a REST API without having to use TM Module?
Thanks in advance.
The kamailio script is has follows:
#!KAMAILIO
/* add API http timeout */
#!define HTTP_API_TIMEOUT 5000
#!define HTTP_API_ROUTING_ENDPOINT "http://some_python_rest_api/get_route"
### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR
debug=4
log_stderror=no
memdbg=5
memlog=5
log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "
/* number of SIP routing processes */
children=2
/* set paths to location of modules */
loadmodule "tm.so"
loadmodule "jsonrpcs.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "sl.so"
loadmodule "db_mysql.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "ipops.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "uac.so"
loadmodule "counters.so"
loadmodule "http_async_client.so"
loadmodule "jansson.so"
loadmodule "usrloc.so"
/* listen addresses */
listen=udp:10.20.0.2:5060
<http://10.20.0.2:5060/>listen=udp:10.20.0.2:5062
<http://10.20.0.2:5062/>advertised_address="10.20.0.2";
# ----- http_async_client params -----
modparam("http_async_client", "workers", HTTP_ASYNC_CLIENT_WORKERS)
modparam("http_async_client", "connection_timeout", 2000)
request_route {
#route(HANDLE_DMQ);
route(HANDLE_OPTIONS);
if (is_method("INVITE"))
{
xlog("L_INFO","MAIN - calling TO_CARRIER");
route(TO_CARRIER);
exit;
}
else{
sl_send_reply("401","UNAUTHORIZED");
}
}
route[TO_CARRIER]{
xlog("L_INFO","TO_CARRIER - calling RELAY_API");
route(RELAY_API); #Route relay
xlog("L_INFO","TO_CARRIER - return");
return;
}
# Relay request using the API (response)
route[RELAY_API_RESPONSE] {
xlog("L_INFO","RELAY_API_RESPONSE - got response from REST API");
if ($http_ok==1 && $http_rs==200)
{
xlog("L_INFO","RELAY_API_RESPONSE - HTTP RESPONSE:
$http_rb\n");
if (jansson_get("json", $http_rb, "$var(json)")) {
xlog("L_INFO","RELAY_API_RESPONSE - JSON =
$var(json)");
$var(count) = 0;
jansson_array_size("routes", $var(json),
"$var(size)");
xlog("L_INFO","RELAY_API_RESPONSE -
jansson_array_size");
while ( $var(count) < $var(size) ){
jansson_get("routes[$var(count)].headers.to.uri", $var(rtjson),
"$var(v)");
xlog("L_INFO","JSON - routes[$var(count)] -
$var(v)");
#$(avp(mycontacts)[$var(count)]) = $avp(mycontacts) +
$var(v) + "\r\n";
$avp(mycontacts) = $avp(mycontacts) + $var(v) +
";";
append_to_reply("Contact: <" + $var(v)
+">"+ "\r\n"); /* ---- IS THERE A BETTER ?? ..... */
$var(count) = $var(count) + 1;
}
xlog("L_INFO","RELAY_API_RESPONSE - RELAY");
xlog("L_INFO","MAIN - calling REPLY_302");
route(REPLY_302);
return;
}
}
send_reply(500, "API Not Available - http response = $http_rs
$http_ok");
exit;
}
route[RELAY_API] {
xlog("L_INFO","RELAY_API - from_ip $si:$sp from_number $fU
to_number $ru");
$http_req(all) = $null;
$http_req(suspend) = 1;
$http_req(timeout) = HTTP_API_TIMEOUT;
$http_req(method) = "POST";
$http_req(hdr) = "Content-Type: application/json";
jansson_set("string","from_ip",$si,
"$var(http_routing_query)");
jansson_set("string","from_port",$sp,
"$var(http_routing_query)");
jansson_set("string","from_number",$fU,
"$var(http_routing_query)");
jansson_set("string","to_number",$ru ,
"$var(http_routing_query)");
xlog("L_INFO","RELAY_API - API ASYNC ROUTING REQUEST:
$var(http_routing_query)\n");
$http_req(body) = $var(http_routing_query);
t_newtran();
http_async_query(HTTP_API_ROUTING_ENDPOINT, "RELAY_API_RESPONSE");
xlog("L_INFO","RELAY_API - Waiting for Response");
}
route[REPLY_302] {
# Sends a 300 Multiple Choices back to the proxy that requested the routing lookup
xlog("L_INFO","REPLY_302 - send reply");
sl_send_reply("300", "Multiple Choices");
xlog("L_INFO","REPLY_302 - exit");
exit;
}
route[HANDLE_OPTIONS]{
if(is_method("OPTIONS"))
{
sl_send_reply(200, "OK");
exit;
}
if ($fU=="ping")
{
sl_send_reply("200","OK");
exit;
}
}
SNGrep output:
1 - INVITE from UAC to Kamailio
INVITE sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2> SIP/2.0
Via: SIP/2.0/UDP 10.20.0.1:5063;branch=z9hG4bK58aa83f4
Max-Forwards: 70
From: "Anonymous" <sip:anonymous@anonymous.invalid:5063>;tag=as192b8891
To: <sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2>>
Contact: <sip:anonymous@10.20.0.1:5063<http://sip:anonymous@10.20.0.1:5063/>>
Call-ID:
531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063<http://531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063/>
CSeq: 102 INVITE
User-Agent: SIPp
Date: Mon, 08 Apr 2024 15:09:51 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH,
MESSAGE
Supported: replaces, timer
Content-Type: application/sdp
Content-Length: 270
v=0
o=root 2021555890 2021555890 IN IP4 10.20.0.1
s=SIPp
c=IN IP4 10.20.0.1
t=0 0
m=audio 18422 RTP/AVP 8 0 101
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:150
a=sendrecv
2 - Reply from Kamailio to UAC
SIP/2.0 100 trying -- your call is important to us
Via: SIP/2.0/UDP 10.20.0.1:5063;branch=z9hG4bK58aa83f4
From: "Anonymous" <sip:anonymous@anonymous.invalid:5063>;tag=as192b8891
To: <sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2>>
Call-ID:
531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063<http://531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063/>
CSeq: 102 INVITE
Server: kamailio (5.7.4 (x86_64/linux))
Content-Length: 0
3 - SIP 300 Multiple Choices from Kamailio to UAC
SIP/2.0 300 Multiple Choices
Via: SIP/2.0/UDP 10.20.0.1:5063;branch=z9hG4bK58aa83f4
From: "Anonymous" <sip:anonymous@anonymous.invalid:5063>;tag=as192b8891
To:
<sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2>>;tag=57c593265e21c2b70aea50cb414df9cd.32679ccd
Call-ID:
531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063<http://531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063/>
CSeq: 102 INVITE
Contact: <sip:sip:918228990@10.20.0.2@sip.domain.io<http://sip.domain.io/>>
Contact: <sip:+351sip:918228990@10.20.0.2@10.20.0.3<http://10.20.0.3/>>
Server: kamailio (5.7.4 (x86_64/linux))
Content-Length: 0
4 - SIP 500 from Kamailio to UAC
SIP/2.0 500 I'm terribly sorry, server error occurred (1/TM)
Via: SIP/2.0/UDP 10.20.0.1:5063;branch=z9hG4bK58aa83f4
From: "Anonymous" <sip:anonymous@anonymous.invalid:5063>;tag=as192b8891
To:
<sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2>>;tag=4eb2322b7d2b68e6fc3168f503344c21-32679ccd
Call-ID:
531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063<http://531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063/>
CSeq: 102 INVITE
Server: kamailio (5.7.4 (x86_64/linux))
Content-Length: 0
5 - ACK from UAC to Kamailio
ACK sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2> SIP/2.0
Via: SIP/2.0/UDP 10.20.0.1:5063;branch=z9hG4bK58aa83f4
Max-Forwards: 70
From: "Anonymous" <sip:anonymous@anonymous.invalid:5063>;tag=as192b8891
To:
<sip:918228990@10.20.0.2<mailto:sip%3A918228990@10.20.0.2>>;tag=57c593265e21c2b70aea50cb414df9cd.32679ccd
Contact: <sip:anonymous@10.20.0.1:5063<http://sip:anonymous@10.20.0.1:5063/>>
Call-ID:
531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063<http://531668b959674f9f667f1c923d1d6c94@10.20.0.1:5063/>
CSeq: 102 ACK
User-Agent: SIPp
Content-Length: 0
and continues with ACK and repeating SIP 500 above....
Sérgio Charrua
.