3434#include "../../parser/contact/parse_contact.h"
3535#include "../tm/dlg.h"
3636#include "../tm/tm_load.h"
37+ #include "../tm/t_hooks.h"
3738#include "../../ipc.h"
3839#include "dlg_hash.h"
3940#include "dlg_req_within.h"
4445
4546extern str dlg_extra_hdrs ;
4647
48+ #define DLG_AUTO_PRACK_FR_TIMEOUT 2
49+ #define DLG_TM_TID_LEN ((sizeof(int) * 2) + 1 + (sizeof(int) * 2))
50+
51+ struct dlg_auto_prack_ctx {
52+ unsigned int invite_hash_index ;
53+ unsigned int invite_label ;
54+ str invite_tid ;
55+ str invite_totag ;
56+ };
57+
58+ static void dlg_auto_prack_free (void * ctx )
59+ {
60+ shm_free (ctx );
61+ }
62+
63+ static void dlg_auto_prack_reply_failure (struct dlg_auto_prack_ctx * ctx )
64+ {
65+ str reason = str_init ("Bad Gateway" );
66+ struct cell * invite_t ;
67+ int rc ;
68+
69+ rc = d_tmb .t_lookup_ident (& invite_t , ctx -> invite_hash_index ,
70+ ctx -> invite_label );
71+ if (rc < 0 ) {
72+ LM_ERR ("failed to lookup correlated INVITE transaction <%.*s> for auto PRACK failure handling\n" ,
73+ ctx -> invite_tid .len , ctx -> invite_tid .s );
74+ return ;
75+ }
76+
77+ LM_DBG ("auto PRACK failure: sending native 502 reply on correlated INVITE transaction <%.*s>, to-tag <%.*s>\n" ,
78+ ctx -> invite_tid .len , ctx -> invite_tid .s ,
79+ ctx -> invite_totag .len , ctx -> invite_totag .s );
80+ rc = d_tmb .t_reply_with_body (invite_t , 502 , & reason , NULL , NULL ,
81+ & ctx -> invite_totag );
82+ d_tmb .unref_cell (invite_t );
83+
84+ if (rc < 0 )
85+ LM_ERR ("failed to send native 502 reply on correlated INVITE transaction <%.*s>\n" ,
86+ ctx -> invite_tid .len , ctx -> invite_tid .s );
87+ else
88+ LM_DBG ("native 502 reply sent on correlated INVITE transaction <%.*s>\n" ,
89+ ctx -> invite_tid .len , ctx -> invite_tid .s );
90+ }
91+
92+ static int dlg_format_trans_id (unsigned int hash_index , unsigned int label ,
93+ str * out , char * buf , unsigned int size )
94+ {
95+ char * p ;
96+ int left ;
97+
98+ if (size < DLG_TM_TID_LEN )
99+ return -1 ;
100+
101+ p = buf ;
102+ left = size ;
103+ int2reverse_hex (& p , & left , label );
104+ * (p ++ ) = '.' ;
105+ left -- ;
106+ int2reverse_hex (& p , & left , hash_index );
107+
108+ out -> s = buf ;
109+ out -> len = p - buf ;
110+ return 0 ;
111+ }
112+
113+ static void dlg_auto_prack_tmcb (struct cell * t , int type , struct tmcb_params * ps )
114+ {
115+ char prack_tid_buf [DLG_TM_TID_LEN ];
116+ str prack_tid = STR_NULL ;
117+ struct dlg_auto_prack_ctx * ctx ;
118+ int rc = 0 ;
119+
120+ if (!ps || !ps -> param || !(* ps -> param ))
121+ return ;
122+
123+ ctx = (struct dlg_auto_prack_ctx * )(* ps -> param );
124+ if (dlg_format_trans_id (t -> hash_index , t -> label , & prack_tid , prack_tid_buf ,
125+ sizeof (prack_tid_buf )) < 0 ) {
126+ LM_ERR ("failed to format auto PRACK transaction id for [%u:%u]\n" ,
127+ t -> hash_index , t -> label );
128+ return ;
129+ }
130+
131+ switch (type ) {
132+ case TMCB_LOCAL_COMPLETED :
133+ LM_DBG ("auto PRACK local transaction <%.*s> completed with code %d; correlated INVITE tid <%.*s>, to-tag <%.*s>\n" ,
134+ prack_tid .len , prack_tid .s , ps -> code , ctx -> invite_tid .len ,
135+ ctx -> invite_tid .s , ctx -> invite_totag .len , ctx -> invite_totag .s );
136+ if (ps -> code < 300 )
137+ break ;
138+ LM_DBG ("auto PRACK local transaction <%.*s> completed negatively with code %d; triggering correlated INVITE failure handling\n" ,
139+ prack_tid .len , prack_tid .s , ps -> code );
140+ rc = 1 ;
141+ break ;
142+ case TMCB_ON_FAILURE :
143+ LM_DBG ("auto PRACK local transaction <%.*s> failed with code %d; correlated INVITE tid <%.*s>, to-tag <%.*s>\n" ,
144+ prack_tid .len , prack_tid .s , ps -> code , ctx -> invite_tid .len ,
145+ ctx -> invite_tid .s , ctx -> invite_totag .len , ctx -> invite_totag .s );
146+ rc = 1 ;
147+ break ;
148+ }
149+
150+ if (rc )
151+ dlg_auto_prack_reply_failure (ctx );
152+ }
153+
154+ static void dlg_auto_prack_t_created (struct cell * t , void * param )
155+ {
156+ char prack_tid_buf [DLG_TM_TID_LEN ];
157+ str prack_tid = STR_NULL ;
158+ struct dlg_auto_prack_ctx * ctx = param ;
159+
160+ t -> fr_timeout = DLG_AUTO_PRACK_FR_TIMEOUT ;
161+
162+ if (dlg_format_trans_id (t -> hash_index , t -> label , & prack_tid , prack_tid_buf ,
163+ sizeof (prack_tid_buf )) < 0 ) {
164+ LM_ERR ("failed to format newly created auto PRACK transaction id for [%u:%u]\n" ,
165+ t -> hash_index , t -> label );
166+ } else {
167+ LM_DBG ("auto PRACK created local transaction <%.*s>; correlated INVITE tid <%.*s>, to-tag <%.*s>; fr_timeout=%d\n" ,
168+ prack_tid .len , prack_tid .s , ctx -> invite_tid .len , ctx -> invite_tid .s ,
169+ ctx -> invite_totag .len , ctx -> invite_totag .s , t -> fr_timeout );
170+ }
171+
172+ if (d_tmb .register_tmcb (NULL , t , TMCB_LOCAL_COMPLETED | TMCB_ON_FAILURE ,
173+ dlg_auto_prack_tmcb , ctx , dlg_auto_prack_free ) < 0 ) {
174+ LM_ERR ("failed to register TM callbacks for auto PRACK local transaction [%u:%u]\n" ,
175+ t -> hash_index , t -> label );
176+ }
177+ }
178+
179+ static struct dlg_auto_prack_ctx * dlg_build_auto_prack_ctx (struct sip_msg * rpl )
180+ {
181+ char invite_tid_buf [DLG_TM_TID_LEN ];
182+ struct dlg_auto_prack_ctx * ctx ;
183+ unsigned int hash_index , label ;
184+ unsigned int size ;
185+ char * p ;
186+ str invite_tid = STR_NULL ;
187+ str invite_totag = STR_NULL ;
188+
189+ if (d_tmb .t_get_trans_ident (rpl , & hash_index , & label ) < 0 ) {
190+ LM_ERR ("failed to fetch correlated INVITE transaction id for auto PRACK\n" );
191+ return NULL ;
192+ }
193+ if ((!rpl -> to && parse_headers (rpl , HDR_TO_F , 0 ) < 0 ) || !rpl -> to ) {
194+ LM_ERR ("failed to parse To header while building auto PRACK correlation context\n" );
195+ return NULL ;
196+ }
197+
198+ if (dlg_format_trans_id (hash_index , label , & invite_tid , invite_tid_buf ,
199+ sizeof (invite_tid_buf )) < 0 ) {
200+ LM_ERR ("failed to format correlated INVITE transaction id for auto PRACK\n" );
201+ return NULL ;
202+ }
203+ invite_totag = get_to (rpl )-> tag_value ;
204+
205+ size = sizeof (* ctx ) + invite_tid .len + invite_totag .len ;
206+ ctx = shm_malloc (size );
207+ if (!ctx ) {
208+ LM_ERR ("oom for auto PRACK correlation context\n" );
209+ return NULL ;
210+ }
211+
212+ p = (char * )(ctx + 1 );
213+ ctx -> invite_hash_index = hash_index ;
214+ ctx -> invite_label = label ;
215+ ctx -> invite_tid .s = p ;
216+ ctx -> invite_tid .len = invite_tid .len ;
217+ memcpy (p , invite_tid .s , invite_tid .len );
218+ p += invite_tid .len ;
219+
220+ ctx -> invite_totag .s = p ;
221+ ctx -> invite_totag .len = invite_totag .len ;
222+ memcpy (p , invite_totag .s , invite_totag .len );
223+
224+ return ctx ;
225+ }
226+
47227int free_tm_dlg (dlg_t * td )
48228{
49229 if (td )
@@ -1215,6 +1395,7 @@ int send_prack_indialog_request(struct dlg_cell *dlg, struct sip_msg *rpl,
12151395 str method = str_init ("PRACK" );
12161396 str extra_headers = STR_NULL ;
12171397 struct dlg_indialog_req_param * p = NULL ;
1398+ struct dlg_auto_prack_ctx * auto_prack_ctx = NULL ;
12181399 context_p old_ctx ;
12191400 context_p * new_ctx ;
12201401 dlg_t * dialog_info = NULL ;
@@ -1251,10 +1432,23 @@ int send_prack_indialog_request(struct dlg_cell *dlg, struct sip_msg *rpl,
12511432 p -> release = release ;
12521433 p -> leg = dstleg ;
12531434
1435+ auto_prack_ctx = dlg_build_auto_prack_ctx (rpl );
1436+ if (!auto_prack_ctx )
1437+ LM_ERR ("failed to build internal auto PRACK correlation context\n" );
1438+ else {
1439+ LM_DBG ("built internal auto PRACK correlation context for INVITE tid <%.*s>, to-tag <%.*s>\n" ,
1440+ auto_prack_ctx -> invite_tid .len , auto_prack_ctx -> invite_tid .s ,
1441+ auto_prack_ctx -> invite_totag .len , auto_prack_ctx -> invite_totag .s );
1442+ dialog_info -> t_created_cb = dlg_auto_prack_t_created ;
1443+ dialog_info -> t_created_cb_param = auto_prack_ctx ;
1444+ }
1445+
12541446 if (push_new_processing_context (dlg , & old_ctx , & new_ctx , NULL ) != 0 ) {
12551447 pkg_free (extra_headers .s );
12561448 free_tm_dlg (dialog_info );
12571449 shm_free (p );
1450+ if (auto_prack_ctx )
1451+ shm_free (auto_prack_ctx );
12581452 return -1 ;
12591453 }
12601454
@@ -1281,6 +1475,8 @@ int send_prack_indialog_request(struct dlg_cell *dlg, struct sip_msg *rpl,
12811475 LM_ERR ("failed to send the PRACK request\n" );
12821476 unref_dlg (dlg , 1 );
12831477 shm_free (p );
1478+ if (auto_prack_ctx )
1479+ shm_free (auto_prack_ctx );
12841480 return -1 ;
12851481 }
12861482
0 commit comments