i'm also doing some tests on my side, but in stateless mode and I came to
an interesting approach (but requires a lot more testing...).
The idea is to have http_async_client running in a stateless proxy, and the
way I did it is:
- receive the INVITE
- keep the message buffer in a htable, with key call-id
...
$var(call_id) = $ci;
$sht(stateless_calls=>$var(call_id)) = $mb;
...
- send the async http request, specifying the response route handler
in the route that handles the http response, I do:
- check if the JSON response received from HTTP includes the call-id value
(this is mandatory for the whole solution to work)
- if the call-id is present, get the value from htable with something like:
...
$var(saved_msg) = $sht(stateless_calls=>$var(call_id));
...
- then use $var(saved_msg) to create a new message buffer
with msg_set_buffer( $var(saved_msg) ); (from textopsx module)
- modify the contact header with values found in JSON object returned from
the HTTP response
- send_reply("300", "Multiple Choices");
But msg_set_buffer is not working as I would expect: not sure why, but the
Via header now includes a ;received=127.0.0.1 value (it is not present in
the original header), which results in the following SIP flow
SBC ----> INVITE ----> Kamailio
SBC <---- 100 Trying <---- Kamailio
Kamailio ----> 300 Multi Choice ----> 127.0.0.1
(but the SIP 300 Multi Choice is not the message buffer constructed in
the RELAY_API_RESPONSE
route)
This is the code I ended up so far.... If you, or anyone, manage to make
this work, please share within this thread (I will do the same too)
####### Modules Section ########
> # Load stateless reply module
> loadmodule "sl.so"
> loadmodule "tm.so"
> # Load PV module (pseudo-variables)
> loadmodule "pv.so"
> # Load http_async_client module
> loadmodule "http_async_client.so"
> # Load htable module (for storing data)
> loadmodule "htable.so"
> # Load JSON module (used if you parse JSON in responses)
> loadmodule "jansson.so"
> loadmodule "xlog.so"
> loadmodule "textops.so"
> loadmodule "textopsx.so"
> # Other modules as needed...
> # loadmodule "xlog.so"
> # loadmodule "textopsx.so"
> # ...
> ####### Module Parameters ########
> # http_async_client parameters
> #modparam("http_async_client", "http_retry", 0) # No retries
> modparam("http_async_client", "tcp_keepalive", 1)
> modparam("http_async_client", "workers", 4) # Number of async workers
> modparam("http_async_client", "connection_timeout", 200)
> # htable module parameters - define a table for storing requests
> modparam("htable", "htable", "stateless_calls=>size=8;autoexpire=3600;")
> # ^ 'stateless_calls' is just an example table name; it stores data for up
> to 1 hour, but should be reduced to seconds....
> ####### Request Routing Section ########
> include_file "includes/handle_options.cfg"
>
> # Main request route
> request_route {
> if (is_method("ACK") ) { #&& t_check_trans() ){
> exit;
> }
> route(HANDLE_OPTIONS);
> # Handle INVITE
> if (is_method("INVITE")) {
> if (is_method("INVITE")) {
> send_reply("100","Trying");
> }
>
> # A unique key to identify this call; typically use $ci (Call-ID)
> $var(call_id) = $ci;
> xlog("L_INFO", "[INVITE] Received INVITE with Call-ID:
> $var(call_id)\n");
> # ---------------------------------------------------------
> # 1) Store the SIP Message in our HTable so we can respond later
> # Key: the Call-ID
> # Value: the entire SIP message buffer ($mb) + maybe some
> headers
> # ---------------------------------------------------------
> $sht(stateless_calls=>$var(call_id)) = $mb;
> xlog("L_INFO","[INVITE] $mb \n");
> # ---------------------------------------------------------
> # 2) Generate JSON payload and Trigger asynchronous HTTP request
> #
> # We send the Call-ID so the server can return it in the
> response
> #
> # ---------------------------------------------------------
>
> jansson_set("string","from" , $hdr(From) , "$var(post)");
> jansson_set("string","to" , $hdr(To) , "$var(post)");
> jansson_set("string","r-uri" , $ru , "$var(post)");
> jansson_set("string","contact" , $hdr(Contact) , "$var(post)");
> jansson_set("string","call-id" , $ci , "$var(post)");
> if ( is_present_hf("Identity") )
> jansson_set("string","identity" , $hdr(Identity)
> , "$var(post)");
> if ( is_present_hf("P-Identity-Bypass") )
> jansson_set("string","p-identity-bypass" ,
> $hdr(P-Identity-Bypass) , "$var(post)");
> if ( is_present_hf("P-Asserted-Identity") )
> jansson_set("string","p-asserted-identity" ,
> $hdr(P-Asserted-Identity) , "$var(post)");
> if ( is_present_hf("P-STSH-UC") )
> jansson_set("string","p-stsh-uc" , $hdr(P-STSH-UC)
> , "$var(post)");
> jansson_set("string", "request-time" , $xavp(requestTime),
> "$var(post)");
>
> $http_req(all) = $null;
> $http_req(suspend) = 0
> $http_req(method) = "POST";
> $http_req(hdr) = "Content-Type: application/json";
> $http_req(suspend) = 0;
> $http_req(body) = $var(post);
>
> xlog("L_INFO", "HANDLE_STIRSHAKEN - JSON object to POST :\n
> $var(post)\n");
> xlog("L_INFO", "HANDLE_STIRSHAKEN - HTTP_STSH_QUERY URL =
> $var(REQUEST_URL)\n");
> http_async_query(
> "http://IP:PORT/ire/v1/stsh", # Endpoint
> "RELAY_API_RESPONSE" # Callback route
> );
> # ---------------------------------------------------------
> # 3) Since we are 'stateless', do NOT send a reply yet, do NOT
> forward.
> # We simply exit; the code in event_route will handle the final
> reply.
> # ---------------------------------------------------------
> xlog("L_INFO", "[INVITE] Asynchronous HTTP call triggered, exit
> now.\n");
> exit;
> }
> # For other methods or default:
> sl_send_reply("405","Method Not Allowed");
> exit;
> }
> #
> # event_route for asynchronous HTTP responses
> #
> route[RELAY_API_RESPONSE] {
> xlog("L_INFO", "[HTTP-ASYNC] HTTP response received!\n");
> xlog("L_INFO", "[HTTP-ASYNC] Response body: $(rb)\n");
> $var(rtjson) = "";
> $var(size) = "";
> $var(REQUEST_URL) = "";
> # 1) Parse the JSON (assuming you get something like: { "call_id":
> "xyz", "contacts": ["sip:[email protected]", "sip:[email protected]"] } )
> # This is an example; adapt to your actual response format.
> jansson_xdecode($http_rb, "json");
> $var(call_id) = $xavp(json=>call-id); # $(rb{s.json, call_id});
>
>
> xlog("L_INFO", "[HTTP-ASYNC] call_id from HTTP response:
> $var(call_id)\n");
> if ($var(call_id) == "") {
> xlog("L_ERR", "[HTTP-ASYNC] No call_id in HTTP response, cannot
> correlate!\n");
> return;
> }
> # 2) Retrieve the original SIP message from the HTable
> $var(saved_msg) = $sht(stateless_calls=>$var(call_id));
> if ($var(saved_msg) == $null) {
> xlog("L_ERR", "[HTTP-ASYNC] No stored message found for
> call_id=$var(call_id).\n");
> return;
> }
>
> # 3) Now we must 're-inject' or 're-process' that saved SIP message in
> Kamailio's context
> # so we can send a stateless reply.
> # We can do this by dynamically building the response.
> #
> # the typical approach is:
> # - Use 'msg_set_buffer' to load the saved message buffer into
> context
> # - Then call 'sl_send_reply()' with the desired code and reason
> msg_set_buffer( $var(saved_msg) );
> append_to_reply("Contact: $xavp(json=>contact)\r\n");
> # 4) Construct and send the 300 Multiple Choices.
> # We can add new Contacts by using `append_hf("Contact: ...\r\n")`.
> # In a perfect scenario, you'd parse the array properly. For
> demonstration,
> # let's assume $var(contacts) = "sip:[email protected],sip:[email protected]"
> # Add the 300 code and reason
> send_reply("300", "Multiple Choices");
> # 5) Clean up from the HTable
> sht_rm("stateless_calls",$var(call_id));
> # Done
> xlog("L_INFO", "[HTTP-ASYNC] 300 Multiple Choices sent for
> call_id=$var(call_id).\n");
> }
Atenciosamente / Kind Regards / Cordialement / Un saludo,
*Sérgio Charrua*
On Sat, Dec 21, 2024 at 5:31 PM Alexis Fidalgo via sr-users <
[email protected]> wrote:
> Hello, after the discussion regarding http and http_async, I started some
> labs to make a comparison and see what’s the trade off and the associated
> cost.
>
> Main problem (to me) is im not clear on how transactions behave. Im
> running some fast tests now before I start to deploy the final scenarios
> and
>
> 1. A new transaction is created before the http_async call (as the module
> example shows for http_async_query function
> 2. The http_async_query call is executed, receives a response and the
> HTTP_REPLY route for http_async_query is executed.
> 3. As we need to redirect the call, im adding Contact information with
> append_to_reply and then calling t_reply(302,”Redirect)
>
> Up to here INVITE is received, a 100 is answered and then the 302 with the
> expected Contact information (collected and built from the http_async_query
> response), problem is that the 302 is retransmitted 3 more times.
>
> So, im not even sure that im doing the correct actions to process the call
> this way. Is there a document/book/reference I can read to understand
> transactions better?
>
> By now I can not handle the call to be processed correctly (without the
> retransmissions) and finish the transaction the correct way.
>
> Any help, link, guide, will be appreciated.
>
> Regards.
>
> __________________________________________________________
> 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!
>
__________________________________________________________
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!