int send_leg_msg(struct dlg_cell *dlg,str *method,int src_leg,int dst_leg, str *hdrs,str *body,dlg_request_callback func,void *param,dlg_release_func release) { context_p old_ctx; dlg_t* dialog_info; int result; unsigned int method_type; if (parse_method(method->s,method->s+method->len,&method_type) == 0) { LM_ERR("Failed to parse method - [%.*s]\n",method->len,method->s); return -1; } if (method_type == METHOD_INVITE && (body == NULL || body->s == NULL || body->len == 0)) { LM_ERR("Cannot send INVITE without SDP body\n"); return -1; } if ((dialog_info = build_dialog_info(dlg, dst_leg, src_leg)) == 0) { LM_ERR("failed to create dlg_t\n"); return -1; } LM_DBG("sending [%.*s] to %s (%d)\n",method->len,method->s, (dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg); /* set new processing context */ if (push_new_processing_context( dlg, &old_ctx, NULL)!=0) return -1; dialog_info->T_flags=T_NO_AUTOACK_FLAG; result = d_tmb.t_request_within (method, /* method*/ hdrs, /* extra headers*/ body, /* body*/ dialog_info, /* dialog structure*/ func, /* callback function*/ param, /* callback parameter*/ release); /* release function*/ /* reset the processing contect */ current_processing_ctx = old_ctx; if(result < 0) { LM_ERR("failed to send the in-dialog request\n"); free_tm_dlg(dialog_info); return -1; } free_tm_dlg(dialog_info); return 0; }
/* cell- pointer to a struct dlg_cell * leg - a dialog leg to be BYE'ed : * = 0: caller leg * > 0: callee legs */ static inline int send_leg_bye(struct dlg_cell *cell, int dst_leg, int src_leg, str *extra_hdrs) { context_p old_ctx; context_p *new_ctx; dlg_t* dialog_info; str met = {"BYE", 3}; int result; if ((dialog_info = build_dlg_t(cell, dst_leg, src_leg)) == 0){ LM_ERR("failed to create dlg_t\n"); goto err; } LM_DBG("sending BYE to %s (%d)\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg); /* set new processing context */ if (push_new_processing_context( cell, &old_ctx, &new_ctx, NULL)!=0) goto err; ctx_lastdstleg_set(dst_leg); ref_dlg(cell, 1); result = d_tmb.t_request_within (&met, /* method*/ extra_hdrs, /* extra headers*/ NULL, /* body*/ dialog_info, /* dialog structure*/ bye_reply_cb, /* callback function*/ (void*)cell, /* callback parameter*/ NULL); /* release function*/ /* reset the processing contect */ if (current_processing_ctx == NULL) *new_ctx = NULL; else context_destroy(CONTEXT_GLOBAL, *new_ctx); current_processing_ctx = old_ctx; if(result < 0){ LM_ERR("failed to send the BYE request\n"); goto err1; } free_tm_dlg(dialog_info); LM_DBG("BYE sent to %s\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee"); return 0; err1: unref_dlg(cell, 1); err: return -1; }
static void dual_bye_event(struct dlg_cell* dlg, struct sip_msg *req, int extra_unref) { int event, old_state, new_state, unref, ret; struct sip_msg *fake_msg=NULL; context_p old_ctx; event = DLG_EVENT_REQBYE; next_state_dlg(dlg, event, DLG_DIR_DOWNSTREAM, &old_state, &new_state, &unref, dlg->legs_no[DLG_LEG_200OK], 0); unref += extra_unref; if(new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED){ LM_DBG("removing dialog with h_entry %u and h_id %u\n", dlg->h_entry, dlg->h_id); /*destroy linkers */ dlg_lock_dlg(dlg); destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; dlg_unlock_dlg(dlg); /* remove from timer */ ret = remove_dlg_timer(&dlg->tl); if (ret < 0) { LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", 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)); } else if (ret > 0) { LM_DBG("dlg already expired (not in timer list) %p [%u:%u] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", 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)); } else { /* successfully removed from timer list */ unref++; } if (req==NULL) { /* set new msg & processing context */ if (push_new_processing_context( dlg, &old_ctx, &fake_msg)==0) { /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, fake_msg, DLG_DIR_NONE, 0); /* reset the processing contect */ current_processing_ctx = old_ctx; } /* no CB run in case of failure FIXME */ } else { /* we should have the msg and context from upper levels */ /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, DLG_DIR_NONE, 0); } LM_DBG("first final reply\n"); /* derefering the dialog */ unref_dlg(dlg, unref); if_update_stat( dlg_enable_stats, active_dlgs, -1); } if(new_state == DLG_STATE_DELETED && old_state == DLG_STATE_DELETED ) { /* trash the dialog from DB and memory */ LM_DBG("second final reply\n"); /* delete the dialog from DB */ if (should_remove_dlg_db()) remove_dialog_from_db(dlg); /* force delete from mem */ unref_dlg(dlg, unref); } }