*
the solution needs to be stateless

Why?  This seems to be arbitrary.  Suppose you wanted to retrieve the data via 
SIP rather than http:  You'd be using a transaction.  There's no magic here, 
and the benefit of http_async_client is that you're trading off holding the the 
process with an increased usage in shared memory.

Regarding the re-transmission of the 3xx, the likely reason is that you don't 
have a Contact: header in the reply, or that the rURI of the ACK doesn't match 
the Contact, etc.  These are the typical reasons any ACK doesn't get matched.

Regarding an example, I added an example for a 300 reply to my previous example 
project
https://github.com/whosgonna/kamailio_http_async/tree/reply300

The difference from the main branch is:

  1.
300 reply is sent
  2.
The reply has a contact header (which a 3xx should have, and is probably why 
your ACK is failing)
  3.
Added a new sipp testing scenario file for handling a 300, using the received 
Contact as the ACK ruri.





Kaufman
Senior Voice Engineer



E: [email protected]







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 <[email protected]>
Sent: Sunday, December 22, 2024 6:52 AM
To: Henning Westerholt <[email protected]>
Cc: Kamailio (SER) - Users Mailing List <[email protected]>; Alexis 
Fidalgo <[email protected]>; Sergio Charrua <[email protected]>
Subject: [SR-Users] Re: Transactions help


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 Henning,

Main reason is that the solution needs to be stateless, so, in my 
understanding, TM module would turn everything stateful... Am I wrong?
This way I still end up with a stateless redirect server...

Anyway, I will give it a try. Any advice you can share?


Atenciosamente / Kind Regards / Cordialement / Un saludo,


Sérgio Charrua

On Sun, Dec 22, 2024 at 9:13 AM Henning Westerholt 
<[email protected]<mailto:[email protected]>> wrote:

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]<mailto:[email protected]>>
Sent: Sonntag, 22. Dezember 2024 00:34
To: Kamailio (SER) - Users Mailing List 
<[email protected]<mailto:[email protected]>>
Cc: Alexis Fidalgo <[email protected]<mailto:[email protected]>>; Sergio Charrua 
<[email protected]<mailto:[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]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