Hello,

I have not reviewed your cfg in detail. But I am wondering why you go this way 
of adding additional complexity (e.g. using a htable, use special message 
sending functions)? The easiest approach would be to use the http_async_client 
module in a way it was designed in the first place, with the tm module and 
transactions.

Cheers,

Henning

From: Sergio Charrua via sr-users <[email protected]>
Sent: Sonntag, 22. Dezember 2024 00:34
To: Kamailio (SER) - Users Mailing List <[email protected]>
Cc: Alexis Fidalgo <[email protected]>; Sergio Charrua <[email protected]>
Subject: [SR-Users] Re: Transactions help

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]<mailto:sip%[email protected]>", 
"sip:[email protected]<mailto: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]<mailto:sip%[email protected]>,sip:[email protected]<mailto: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]<mailto:[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]<mailto:[email protected]>
To unsubscribe send an email to 
[email protected]<mailto:[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!

Reply via email to