Skip to content

Commit

Permalink
[dialog] added support for delayed dialog deletion
Browse files Browse the repository at this point in the history
Once terminated, instead of deleting / destroying the in-memory dialog right away, by setting the 'delete_delay' parameter, the dialog may be kept for a while in memory, in a read-only state (no action, no changes, nothing).
This delaying may be used to help with the routing of late in-dialog request that may be received after the dialog terminated (like late BYE's due to retransmissions, cross BYE requests, auth'ed BYE request, slow ACK on re-INVITEs, etc).

This work was sponsored by 46Labs, a true OpenSIPS supporter!
  • Loading branch information
bogdan-iancu committed Oct 26, 2022
1 parent 3186096 commit 82475b9
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 58 deletions.
8 changes: 8 additions & 0 deletions modules/dialog/dialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ int dlg_bulk_del_no = 1; /* delete one by one */
int seq_match_mode = SEQ_MATCH_FALLBACK;
int options_ping_interval = 30; /* seconds */
int reinvite_ping_interval = 300; /* seconds */
int dlg_del_delay = 0; /* in seconds, default off */
str dlg_extra_hdrs = {NULL,0};
int race_condition_timeout = 5; /* seconds until call termination is triggered,
after 200OK -> CANCEL race detection */
Expand Down Expand Up @@ -286,6 +287,7 @@ static param_export_t mod_params[]={
{ "default_timeout", INT_PARAM, &default_timeout },
{ "options_ping_interval", INT_PARAM, &options_ping_interval },
{ "reinvite_ping_interval",INT_PARAM, &reinvite_ping_interval },
{ "delete_delay", INT_PARAM, &dlg_del_delay },
{ "dlg_extra_hdrs", STR_PARAM, &dlg_extra_hdrs.s },
{ "dlg_match_mode", INT_PARAM, &seq_match_mode },
{ "db_url", STR_PARAM, &db_url.s },
Expand Down Expand Up @@ -858,6 +860,11 @@ static int mod_init(void)
return -1;
}

if (init_dlg_del_timer(dlg_ondelete )!=0) {
LM_ERR("cannot init delete timer list\n");
return -1;
}

if (init_dlg_ping_timer()!=0) {
LM_ERR("cannot init ping timer\n");
return -1;
Expand Down Expand Up @@ -960,6 +967,7 @@ static void mod_destroy(void)
dlg_db_mode = DB_MODE_NONE;
destroy_dlg_table();
destroy_dlg_timer();
destroy_dlg_del_timer();
destroy_ping_timer();
destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
destroy_dlg_handlers();
Expand Down
80 changes: 78 additions & 2 deletions modules/dialog/dlg_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
return;
}

dlg = lookup_dlg( h_entry, h_id);
dlg = lookup_dlg( h_entry, h_id, 0);
if (dlg==0) {
LM_DBG("unable to find dialog for %.*s "
"with route param '%.*s'\n",
Expand Down Expand Up @@ -1981,6 +1981,46 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
dlg_set_tm_dialog_ctx(dlg, t);

/* run actions for the transition */
if (new_state==DLG_STATE_DELETED && old_state==DLG_STATE_DELETED) {
/* a request after dialog termination */

/* within dialog request */
run_dlg_callbacks(DLGCB_REQ_WITHIN, dlg, req, dir, NULL, 0, 1);

/* update the cseq */
dlg_lock (d_table,d_entry);
if (dlg->legs[dst_leg].last_gen_cseq) {

update_val = ++(dlg->legs[dst_leg].last_gen_cseq);
dlg_unlock (d_table,d_entry);

if (update_msg_cseq(req,0,update_val) != 0)
LM_ERR("failed to update BYE msg cseq\n");

msg_cseq = &((struct cseq_body *)req->cseq->parsed)->number;

final_cseq = shm_malloc(msg_cseq->len + 1);
if (final_cseq == 0) {
LM_ERR("no more shm mem\n");
goto after_unlock5;
}

memcpy(final_cseq,msg_cseq->s,msg_cseq->len);
final_cseq[msg_cseq->len] = 0;

if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
fix_final_cseq,
(void*)final_cseq, free_final_cseq)<0 ) {
LM_ERR("failed to register TMCB (2)\n");
}
}
else
dlg_unlock (d_table,d_entry);

return;
}


if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED &&
old_state!=DLG_STATE_DELETED) {

Expand Down Expand Up @@ -2470,6 +2510,42 @@ void dlg_ontimeout(struct dlg_tl *tl)
return;
}

#define get_dlg_del_tl_payload(_tl_) ((struct dlg_cell*)((char *)(_tl_)- \
(unsigned long)(&((struct dlg_cell*)0)->del_tl)))

/* This timer handler is triggered when the done with "waiting" after the
* dialog got into the TERMINATED state (to be deleted). Take care as
* the dialog may or not be ref counted here (and still in hash)
*/
void dlg_ondelete(struct dlg_tl *tl)
{
/* just removed from del timer, it already has the marker, so it will
* not be subject to another adding */
/* del timer - unlocked */
/* dlg cell - unlocked */
struct dlg_entry *d_entry;
struct dlg_cell *dlg;

dlg = get_dlg_del_tl_payload(tl);

d_entry = &(d_table->entries[dlg->h_entry]);

dlg_lock( d_table, d_entry);

LM_DBG("delete handler for dlg %p, ref=%d\n",dlg, dlg->ref);

if (dlg->ref<=0) {
/* dlg not ref'ed, so safe to destroy.*/
LM_DBG("destroying dlg %p\n",dlg);
unlink_unsafe_dlg( d_entry, dlg);
destroy_dlg(dlg);
} /* if the dialog is still ref'ed, it will be destroyed when
* the ref gets to 0 (and del timer waiting is already done) */

dlg_unlock( d_table, d_entry);
}


#define ROUTE_STR "Route: "
#define CRLF "\r\n"
#define ROUTE_LEN (sizeof(ROUTE_STR) - 1)
Expand Down Expand Up @@ -2847,7 +2923,7 @@ int terminate_dlg(const str *callid, unsigned int h_entry, unsigned int h_id,
if (callid)
dlg = get_dlg_by_callid(callid, 1);
else
dlg = lookup_dlg(h_entry, h_id);
dlg = lookup_dlg(h_entry, h_id, 1);

if(!dlg)
return 0;
Expand Down
2 changes: 2 additions & 0 deletions modules/dialog/dlg_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ void dlg_onroute(struct sip_msg* req, str *rr_param, void *param);

void dlg_ontimeout( struct dlg_tl *tl);

void dlg_ondelete(struct dlg_tl *tl);

str *dlg_get_did(struct dlg_cell *dlg);

int dlg_validate_dialog( struct sip_msg* req, struct dlg_cell *dlg);
Expand Down
7 changes: 4 additions & 3 deletions modules/dialog/dlg_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,8 @@ int dlg_update_routing(struct dlg_cell *dlg, unsigned int leg,



struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id)
struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id,
int active_only )
{
struct dlg_cell *dlg;
struct dlg_entry *d_entry;
Expand All @@ -771,7 +772,7 @@ struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id)

for( dlg=d_entry->first ; dlg ; dlg=dlg->next ) {
if (dlg->h_id == h_id) {
if (dlg->state==DLG_STATE_DELETED) {
if (active_only && dlg->state==DLG_STATE_DELETED) {
dlg_unlock( d_table, d_entry);
goto not_found;
}
Expand Down Expand Up @@ -948,7 +949,7 @@ struct dlg_cell *get_dlg_by_dialog_id(str *dialog_id)
/* we might have a dialog did */
LM_DBG("ID: %*s (h_entry %u h_id %u)\n",
dialog_id->len, dialog_id->s, h_entry, h_id);
dlg = lookup_dlg(h_entry, h_id);
dlg = lookup_dlg(h_entry, h_id, 1);
}
if (!dlg) {
/* the ID is not a number, so let's consider
Expand Down
21 changes: 16 additions & 5 deletions modules/dialog/dlg_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct dlg_cell
unsigned int initial_t_label;
unsigned int replicated; /* indicates if the dialog is replicated */
struct dlg_tl tl;
struct dlg_tl del_tl;
struct dlg_ping_list *pl;
struct dlg_ping_list *reinvite_pl;
str terminate_reason;
Expand Down Expand Up @@ -327,8 +328,16 @@ void destroy_dlg(struct dlg_cell *dlg);
abort(); \
}\
if ((_dlg)->ref<=0) { \
unlink_unsafe_dlg( _d_entry, _dlg);\
destroy_dlg(_dlg);\
/* dlg good to be destried, but be sure it went first
* via the delete timer */ \
if (dlg_del_delay==0 || \
insert_attempt_dlg_del_timer(&_dlg->del_tl, dlg_del_delay)==-2) {\
/* no delay on del or not in del timer anymore -> destroy */ \
LM_DBG("Destroying dialog %p\n",_dlg); \
unlink_unsafe_dlg( _d_entry, _dlg);\
destroy_dlg(_dlg);\
} /* else, either still in timer (-1), either
* inserted now in del timer (0) -> nothing to do*/ \
}\
}while(0)

Expand Down Expand Up @@ -396,11 +405,13 @@ int dlg_update_leg_info(int leg_idx, struct dlg_cell *dlg, str* tag, str *rr,
str *mangled_from,str *mangled_to,str *in_sdp, str *out_sdp);

int dlg_update_cseq(struct dlg_cell *dlg, unsigned int leg, str *cseq,
int field_type);
int field_type);

int dlg_update_routing(struct dlg_cell *dlg, unsigned int leg,str *rr, str *contact);
int dlg_update_routing(struct dlg_cell *dlg, unsigned int leg,str *rr,
str *contact);

struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id);
struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id,
int active_only);

struct dlg_cell* get_dlg(str *callid, str *ftag, str *ttag,
unsigned int *dir, unsigned int *dst_leg);
Expand Down
2 changes: 1 addition & 1 deletion modules/dialog/dlg_replication.c
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ int dlg_replicated_delete(bin_packet_t *packet)
DLG_BIN_POP(int, packet, h_id, malformed);

h_entry = dlg_hash(&call_id);
dlg = lookup_dlg(h_entry, h_id);
dlg = lookup_dlg(h_entry, h_id, 1);
} else {
dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg);
}
Expand Down

0 comments on commit 82475b9

Please sign in to comment.