Skip to content

Commit

Permalink
Use processing context instead of static variables.
Browse files Browse the repository at this point in the history
Current_dlg, last_dst_leg, timeout moved into processing context, so their value will survive a async jump.
  • Loading branch information
bogdan-iancu committed Dec 17, 2014
1 parent aa48678 commit 6351bef
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 125 deletions.
29 changes: 15 additions & 14 deletions modules/dialog/dialog.c
Expand Up @@ -111,8 +111,6 @@ struct rr_binds d_rrb;
static str db_url = {NULL,0};
static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;

extern int last_dst_leg;

/* cachedb stuff */
str cdb_url = {0,0};

Expand Down Expand Up @@ -779,6 +777,8 @@ static int mod_init(void)

/* allocate a slot in the processing context */
ctx_dlg_idx = context_register_ptr(CONTEXT_GLOBAL);
ctx_timeout_idx = context_register_int(CONTEXT_GLOBAL);
ctx_lastdstleg_idx = context_register_int(CONTEXT_GLOBAL);

/* create dialog state changed event */
if (state_changed_event_init() < 0) {
Expand Down Expand Up @@ -1509,14 +1509,17 @@ int pv_get_dlg_timeout(struct sip_msg *msg, pv_param_t *param,
if ( (dlg=get_current_dialog())!=NULL ) {

dlg_lock_dlg(dlg);
if (dlg->state < DLG_STATE_CONFIRMED_NA)
if (dlg->state == DLG_STATE_DELETED)
l = 0;
else if (dlg->state < DLG_STATE_CONFIRMED_NA)
l = dlg->lifetime;
else
l = dlg->tl.timeout - get_ticks();
dlg_unlock_dlg(dlg);

} else if (msg->id == dlg_tmp_timeout_id && dlg_tmp_timeout != -1) {
l = dlg_tmp_timeout;
} else if (current_processing_ctx) {
if ((l=ctx_timeout_get())==0)
return pv_get_null( msg, param, res);
} else {
return pv_get_null( msg, param, res);
}
Expand All @@ -1540,10 +1543,10 @@ int pv_get_dlg_dir(struct sip_msg *msg, pv_param_t *param,
if(res==NULL)
return -1;

if ( (dlg=get_current_dialog())==NULL || last_dst_leg<0)
if ( (dlg=get_current_dialog())==NULL || ctx_lastdstleg_get()<0)
return pv_get_null( msg, param, res);

if (last_dst_leg==0) {
if (ctx_lastdstleg_get()==0) {
res->rs.s = "upstream";
res->rs.len = 8;
} else {
Expand Down Expand Up @@ -1682,18 +1685,16 @@ int pv_set_dlg_timeout(struct sip_msg *msg, pv_param_t *param,
if (replication_dests)
replicate_dialog_updated(dlg);

/* make sure we don't update it again later */
dlg_tmp_timeout = -1;
dlg_tmp_timeout_id = -1;

if (timer_update && update_dlg_timer(&dlg->tl, timeout) < 0) {
LM_ERR("failed to update timer\n");
return -1;
}
} else {
} else if (current_processing_ctx) {
/* store it until we match the dialog */
dlg_tmp_timeout = timeout;
dlg_tmp_timeout_id = msg->id;
ctx_timeout_set( timeout );
} else {
LM_CRIT("BUG - no proicessing context found !\n");
return -1;
}

return 0;
Expand Down
66 changes: 36 additions & 30 deletions modules/dialog/dlg_handlers.c
Expand Up @@ -85,9 +85,8 @@ extern stat_var *processed_dlgs;
extern stat_var *expired_dlgs;
extern stat_var *failed_dlgs;

int last_dst_leg = -1;
int dlg_tmp_timeout = -1;
int dlg_tmp_timeout_id = -1;
int ctx_lastdstleg_idx = -1;
int ctx_timeout_idx = -1;

void init_dlg_handlers(int default_timeout_p)
{
Expand Down Expand Up @@ -469,18 +468,21 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
replicate_dialog_created(dlg);
}

if (type==TMCB_TRANS_DELETED)
if (type==TMCB_TRANS_DELETED) {
event = DLG_EVENT_TDEL;
else if (param->code<200)
} else if (param->code<200) {
event = DLG_EVENT_RPL1xx;
else if (param->code<300)
ctx_lastdstleg_set(DLG_CALLER_LEG);
} else if (param->code<300) {
event = DLG_EVENT_RPL2xx;
else
ctx_lastdstleg_set(DLG_CALLER_LEG);
} else {
event = DLG_EVENT_RPL3xx;
ctx_lastdstleg_set(DLG_CALLER_LEG);
}

last_dst_leg = DLG_CALLER_LEG;
next_state_dlg(dlg, event, DLG_DIR_UPSTREAM, &old_state, &new_state,
&unref, 0);
&unref, DLG_CALLER_LEG, 0);

if (new_state==DLG_STATE_EARLY && old_state!=DLG_STATE_EARLY) {
run_dlg_callbacks(DLGCB_EARLY, dlg, rpl, DLG_DIR_UPSTREAM, 0);
Expand Down Expand Up @@ -748,8 +750,8 @@ static void dlg_seq_down_onreply(struct cell* t, int type,

inline static int get_dlg_timeout(struct sip_msg *msg)
{
return ((dlg_tmp_timeout != -1 && dlg_tmp_timeout_id == msg->id) ?
dlg_tmp_timeout: default_timeout);
return (current_processing_ctx && (ctx_timeout_get()!=0)) ?
ctx_timeout_get() : default_timeout;
}


Expand Down Expand Up @@ -888,7 +890,7 @@ int dlg_create_dialog(struct cell* t, struct sip_msg *req,unsigned int flags)

/* set current dialog */
ctx_dialog_set(dlg);
last_dst_leg = DLG_FIRST_CALLEE_LEG;
ctx_lastdstleg_set(DLG_FIRST_CALLEE_LEG);

extra_ref=2; /* extra ref for the callback and current dlg hook */
if (dlg_db_mode == DB_MODE_DELAYED)
Expand Down Expand Up @@ -984,10 +986,10 @@ static inline int switch_cseqs(struct dlg_cell *dlg,unsigned int leg_no)

static inline void log_bogus_dst_leg(struct dlg_cell *dlg)
{
if (last_dst_leg>=dlg->legs_no[DLG_LEGS_USED])
if (ctx_lastdstleg_get()>=dlg->legs_no[DLG_LEGS_USED])
LM_CRIT("bogus dst leg %d in state %d for dlg %p [%u:%u] with "
"clid '%.*s' and tags '%.*s' '%.*s'. legs used %d\n",
last_dst_leg,dlg->state, dlg, dlg->h_entry, dlg->h_id,
ctx_lastdstleg_get(),dlg->state, dlg, dlg->h_entry, dlg->h_id,
dlg->callid.len, dlg->callid.s,
dlg_leg_print_info( dlg, DLG_CALLER_LEG, tag),
dlg_leg_print_info( dlg, callee_idx(dlg), tag),dlg->legs_no[DLG_LEGS_USED]);
Expand Down Expand Up @@ -1123,13 +1125,11 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
event = DLG_EVENT_REQ;
}

/* save last_dst_leg before running state machine
* helpful for logging various bogus cases according to the RFC */
last_dst_leg = dst_leg;
next_state_dlg( dlg, event, dir, &old_state, &new_state, &unref, 0);
next_state_dlg( dlg, event, dir, &old_state, &new_state, &unref, dst_leg, 0);

/* set current dialog - it will keep a ref! */
ctx_dialog_set(dlg);
ctx_lastdstleg_set(dst_leg);
log_bogus_dst_leg(dlg);
d_entry = &(d_table->entries[dlg->h_entry]);

Expand All @@ -1148,13 +1148,13 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
dlg_unlock_dlg(dlg);

if (!dlg->terminate_reason.s) {
if (last_dst_leg == 0)
if (dst_leg == 0)
init_dlg_term_reason(dlg,"Upstream BYE",sizeof("Upstream BYE")-1);
else
init_dlg_term_reason(dlg,"Downstream BYE",sizeof("Downstream BYE")-1);
}

LM_DBG("BYE successfully processed - dst_leg = %d\n",last_dst_leg);
LM_DBG("BYE successfully processed - dst_leg = %d\n",dst_leg);

if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) {
dlg_lock (d_table,d_entry);
Expand Down Expand Up @@ -1234,8 +1234,9 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
LM_DBG("sequential request successfully processed (dst_leg=%d)\n",
dst_leg);

if (dlg_tmp_timeout != -1 && dlg_tmp_timeout_id == req->id) {
dlg->lifetime = dlg_tmp_timeout;
/* update the dialog timeout from the processing context */
if (current_processing_ctx && (ctx_timeout_get()!=0) ) {
dlg->lifetime = ctx_timeout_get();
dlg->lifetime_dirty = 1;
} else {
dlg->lifetime_dirty = 0;
Expand Down Expand Up @@ -1414,6 +1415,8 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
*/
void dlg_ontimeout( struct dlg_tl *tl)
{
struct sip_msg *fake_msg;
context_p old_ctx;
struct dlg_cell *dlg;
int new_state;
int old_state;
Expand All @@ -1439,9 +1442,8 @@ void dlg_ontimeout( struct dlg_tl *tl)
}

/* act like as if we've received a BYE from caller */
last_dst_leg = dlg->legs_no[DLG_LEG_200OK];
next_state_dlg( dlg, DLG_EVENT_REQBYE, DLG_DIR_DOWNSTREAM, &old_state,
&new_state, &unref, 0);
&new_state, &unref, dlg->legs_no[DLG_LEG_200OK], 0);

if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
LM_DBG("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
Expand All @@ -1458,7 +1460,11 @@ void dlg_ontimeout( struct dlg_tl *tl)
dlg_unlock_dlg(dlg);

/* dialog timeout */
run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0);
if (push_new_processing_context( dlg, &old_ctx, &fake_msg)==0) {
run_dlg_callbacks( DLGCB_EXPIRED, dlg, fake_msg, DLG_DIR_NONE, 0);
/* reset the processing context */
current_processing_ctx = old_ctx;
}

/* delete the dialog from DB */
if (should_remove_dlg_db())
Expand Down Expand Up @@ -1496,13 +1502,13 @@ int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg)
struct sip_uri fru;
int next_strict = 0;

if (last_dst_leg<0 || last_dst_leg>=dlg->legs_no[DLG_LEGS_USED]) {
if (ctx_lastdstleg_get()<0 || ctx_lastdstleg_get()>=dlg->legs_no[DLG_LEGS_USED]) {
log_bogus_dst_leg(dlg);
LM_ERR("Script error - validate function before having a dialog\n");
return -1;
}

leg = & dlg->legs[ last_dst_leg ];
leg = & dlg->legs[ ctx_lastdstleg_get() ];

if (dlg->state <= DLG_STATE_EARLY && !(dlg->flags & DLG_FLAG_TOPHIDING))
return 0;
Expand Down Expand Up @@ -1726,13 +1732,13 @@ int dlg_validate_dialog( struct sip_msg* req, struct dlg_cell *dlg)
int nr_routes,i,src_leg;
str *rr_uri,*route_uris;

if (last_dst_leg<0 || last_dst_leg>=dlg->legs_no[DLG_LEGS_USED]) {
if (ctx_lastdstleg_get()<0 || ctx_lastdstleg_get()>=dlg->legs_no[DLG_LEGS_USED]) {
log_bogus_dst_leg(dlg);
LM_ERR("Script error - validate function before having a dialog\n");
return -4;
}

leg = & dlg->legs[ last_dst_leg ];
leg = & dlg->legs[ ctx_lastdstleg_get() ];

/* first check the cseq */
if ( (!req->cseq && parse_headers(req,HDR_CSEQ_F,0)<0) || !req->cseq ||
Expand All @@ -1745,7 +1751,7 @@ int dlg_validate_dialog( struct sip_msg* req, struct dlg_cell *dlg)

if (req->first_line.u.request.method_value == METHOD_ACK) {
/* ACKs should have the same cseq as INVITEs */
if (last_dst_leg == DLG_CALLER_LEG)
if (ctx_lastdstleg_get() == DLG_CALLER_LEG)
src_leg = callee_idx(dlg);
else
src_leg = DLG_CALLER_LEG;
Expand Down
19 changes: 19 additions & 0 deletions modules/dialog/dlg_handlers.h
Expand Up @@ -61,6 +61,25 @@ typedef int (*create_dlg_f)(struct sip_msg *req,int flags);
typedef void (*set_mod_flag_f)(struct dlg_cell *dlg, unsigned int flags);
typedef int (*is_mod_flag_set_f)(struct dlg_cell *dlg, unsigned int flags);

extern int ctx_timeout_idx;

#define ctx_timeout_get() \
context_get_int(CONTEXT_GLOBAL,current_processing_ctx,ctx_timeout_idx)

#define ctx_timeout_set(_timeout) \
context_put_int(CONTEXT_GLOBAL,current_processing_ctx, ctx_timeout_idx, _timeout)

/* IMPORTANT - as the default value for INT in context is 0, we shift the
last leg idx with +1 to avoid having idx 0; this shifting is hidden by the
get / set functions, so transparent for the usage */
extern int ctx_lastdstleg_idx;

#define ctx_lastdstleg_get() \
(context_get_int(CONTEXT_GLOBAL,current_processing_ctx,ctx_lastdstleg_idx)-1)

#define ctx_lastdstleg_set(_lastleg) \
context_put_int(CONTEXT_GLOBAL,current_processing_ctx, ctx_lastdstleg_idx, _lastleg+1)

void init_dlg_handlers(int default_timeout);

void destroy_dlg_handlers();
Expand Down
31 changes: 16 additions & 15 deletions modules/dialog/dlg_hash.c
Expand Up @@ -67,7 +67,6 @@


extern struct tm_binds d_tmb;
extern int last_dst_leg;


struct dlg_table *d_table = NULL;
Expand All @@ -91,9 +90,6 @@ int dialog_cleanup( struct sip_msg *msg, void *param )
unref_dlg( ctx_dialog_get(), 1);
ctx_dialog_set(NULL);
}
last_dst_leg = -1;
dlg_tmp_timeout = -1;
dlg_tmp_timeout_id = -1;

return SCB_RUN_ALL;
}
Expand All @@ -104,18 +100,22 @@ struct dlg_cell *get_current_dialog(void)
{
struct cell *trans;

if (current_processing_ctx) {
if (current_processing_ctx && ctx_dialog_get()) {
/* use the processing context */
return ctx_dialog_get();
} else {
/* use current transaction to get dialog */
trans = d_tmb.t_gett();
if (trans==NULL || trans==T_UNDEFINED) {
/* no transaction */
return NULL;
}
return (struct dlg_cell*)trans->dialog_ctx;
}
/* look into transaction */
trans = d_tmb.t_gett();
if (trans==NULL || trans==T_UNDEFINED) {
/* no transaction */
return NULL;
}
if (current_processing_ctx)
/* if we have context, but no dlg info, and we
found dlg info into transaction, populate
the dialog too */
ctx_dialog_set(trans->dialog_ctx);
return (struct dlg_cell*)trans->dialog_ctx;
}


Expand Down Expand Up @@ -839,7 +839,7 @@ static inline void log_next_state_dlg(const int event,


void next_state_dlg(struct dlg_cell *dlg, int event, int dir, int *old_state,
int *new_state, int *unref, char is_replicated)
int *new_state, int *unref, int last_dst_leg, char is_replicated)
{
struct dlg_entry *d_entry;

Expand Down Expand Up @@ -931,7 +931,8 @@ void next_state_dlg(struct dlg_cell *dlg, int event, int dir, int *old_state,
switch (dlg->state) {
case DLG_STATE_CONFIRMED_NA:
case DLG_STATE_CONFIRMED:
if (dir == DLG_DIR_DOWNSTREAM && last_dst_leg!=dlg->legs_no[DLG_LEG_200OK] )
if (dir == DLG_DIR_DOWNSTREAM &&
last_dst_leg!=dlg->legs_no[DLG_LEG_200OK] )
/* to end the call, the BYE must be received
* on the same leg as the 200 OK for INVITE */
break;
Expand Down
7 changes: 2 additions & 5 deletions modules/dialog/dlg_hash.h
Expand Up @@ -160,9 +160,6 @@ struct dlg_table
extern struct dlg_table *d_table;
extern int ctx_dlg_idx;

extern int dlg_tmp_timeout;
extern int dlg_tmp_timeout_id;

#define callee_idx(_dlg) \
(((_dlg)->legs_no[DLG_LEG_200OK]==0)? \
DLG_FIRST_CALLEE_LEG : (_dlg)->legs_no[DLG_LEG_200OK])
Expand Down Expand Up @@ -315,8 +312,8 @@ void unref_dlg(struct dlg_cell *dlg, unsigned int cnt);

void ref_dlg(struct dlg_cell *dlg, unsigned int cnt);

void next_state_dlg(struct dlg_cell *dlg, int event,
int dir, int *old_state, int *new_state, int *unref, char is_replicated);
void next_state_dlg(struct dlg_cell *dlg, int event, int dir, int *old_state,
int *new_state, int *unref, int last_dst_leg, char is_replicated);

struct mi_root * mi_print_dlgs(struct mi_root *cmd, void *param );
struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd, void *param );
Expand Down

0 comments on commit 6351bef

Please sign in to comment.