/*! * \brief Function that is registered as TM callback and called on requests * \see dlg_new_dialog * \param t transaction, used to created the dialog * \param type type of the entered callback * \param param saved dialog structure in the callback */ void dlg_onreq(struct cell* t, int type, struct tmcb_params *param) { sip_msg_t *req = param->req; dlg_cell_t *dlg = NULL; if(req->first_line.u.request.method_value != METHOD_INVITE) return; dlg = dlg_get_ctx_dialog(); if (dlg!=NULL) { if (!initial_cbs_inscript) { if (spiral_detected == 1) run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0); else if (spiral_detected == 0) run_create_callbacks(dlg, req); } } if (dlg==NULL) { if((req->flags&dlg_flag)!=dlg_flag) return; dlg_new_dialog(req, t, 1); dlg = dlg_get_ctx_dialog(); } if (dlg!=NULL) { dlg_set_tm_callbacks(t, req, dlg, spiral_detected); dlg_release(dlg); } }
void dlg_onreq(struct cell* t, int type, struct tmcb_params *param) { /* is the dialog already created? */ if (current_dlg_pointer!=NULL) { /* new, un-initialized dialog ? */ if ( current_dlg_pointer->flags & DLG_FLAG_ISINIT ) { /* fully init dialog -> check if attached to the transaction */ if (t->dialog_ctx==NULL) { /* set a callback to remove the ref when transaction * is destroied */ if ( d_tmb.register_tmcb( NULL, t, TMCB_TRANS_DELETED, tmcb_unreference_dialog, (void*)current_dlg_pointer, NULL)<0){ LM_ERR("failed to register TMCB\n"); return; } /* and attached the dialog to the transaction */ t->dialog_ctx = (void*)current_dlg_pointer; /* and keep a reference on it */ ref_dlg( current_dlg_pointer , 1); } return; } /* dialog was previously created by create_dialog() -> just do the last settings */ run_create_callbacks( current_dlg_pointer, param->req); LM_DBG("t hash_index = %u, t label = %u\n",t->hash_index,t->label); current_dlg_pointer->initial_t_hash_index = t->hash_index; current_dlg_pointer->initial_t_label = t->label; current_dlg_pointer->lifetime = get_dlg_timeout(param->req); t->dialog_ctx = (void*)current_dlg_pointer; /* dialog is fully initialized */ current_dlg_pointer->flags |= DLG_FLAG_ISINIT; } }
/*! * \brief Create a new dialog from a sip message * * Create a new dialog from a SIP message, register a callback * to keep track of the dialog with help of the tm module. * This function is either called from the request callback, or * from the dlg_manage function in the configuration script. * \see dlg_onreq * \see w_dlg_manage * \param msg SIP message * \param t transaction * \return 0 on success, -1 on failure */ int dlg_new_dialog(struct sip_msg *req, struct cell *t, const int run_initial_cbs) { struct dlg_cell *dlg; str s; str callid; str ftag; str ttag; str req_uri; unsigned int dir; LM_DBG("starting dlg_new_dialog and method is [%.*s]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s); if (current_dlg_pointer != NULL) return -1; if (req->first_line.u.request.method_value == METHOD_CANCEL) return -1; if (pre_match_parse(req, &callid, &ftag, &ttag, 0) < 0) { LM_WARN("pre-matching failed\n"); return -1; } if (ttag.s != 0 && ttag.len != 0) return -1; if (pv_printf_s(req, ruri_param_model, &req_uri) < 0) { LM_ERR("error - cannot print the r-uri format\n"); return -1; } trim(&req_uri); if (detect_spirals) { if (spiral_detected == 1) return 0; dir = DLG_DIR_NONE; dlg = get_dlg(&callid, &ftag, &ttag, &dir); if (dlg) { LM_DBG("Callid '%.*s' found, must be a spiraled request\n", callid.len, callid.s); spiral_detected = 1; if (run_initial_cbs) run_dlg_callbacks(DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0); //Add did to rr header for all spiralled requested INVITEs if (req->first_line.u.request.method_value == METHOD_INVITE) { if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) { LM_ERR("failed to add RR param\n"); } } // get_dlg has incremented the ref count by 1 unref_dlg(dlg, 1); goto finish; } } spiral_detected = 0; LM_DBG("Building new Dialog for call-id %.*s\n", callid.len, callid.s); LM_DBG("SIP Method: %.*s \n", req->first_line.u.request.method.len, req->first_line.u.request.method.s); dlg = build_new_dlg(&callid /*callid*/, &(get_from(req)->uri) /*from uri*/, &ftag/*from_tag*/, &req_uri /*r-uri*/); if (dlg == 0) { LM_ERR("failed to create new dialog\n"); return -1; } /* save caller's tag, cseq, contact and record route*/ if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG, &(get_from(req)->tag_value)) != 0) { LM_ERR("could not add further info to the dialog\n"); lock_destroy(dlg->dlg_out_entries_lock); lock_dealloc(dlg->dlg_out_entries_lock); shm_free(dlg); return -1; } dlg->transaction = t; /* Populate initial varlist: */ dlg->vars = get_local_varlist_pointer(req, 1); link_dlg(dlg, 0); if (run_initial_cbs) run_create_callbacks(dlg, req); //Dialog will *always* use DID cookie so no need for match mode anymore if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) { LM_ERR("failed to add RR param\n"); goto error; } if (d_tmb.register_tmcb(req, t, TMCB_RESPONSE_READY | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_OUT, dlg_onreply, (void*) dlg, unref_new_dialog) < 0) { LM_ERR("failed to register TMCB\n"); goto error; } // increase reference counter because of registered callback ref_dlg(dlg, 1); dlg->lifetime = get_dlg_timeout(req); s.s = _dlg_ctx.to_route_name; s.len = strlen(s.s); dlg_set_toroute(dlg, &s); dlg->sflags |= _dlg_ctx.flags; if (_dlg_ctx.to_bye != 0) dlg->dflags |= DLG_FLAG_TOBYE; finish: if (t) { // transaction exists ==> keep ref counter large enough to // avoid premature cleanup and ensure proper dialog referencing if (store_dlg_in_tm(req, t, dlg) < 0) { LM_ERR("failed to store dialog in transaction\n"); goto error; } } else { // no transaction exists ==> postpone work until we see the // request being forwarded statefully if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED, store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) { LM_ERR("failed to register callback for storing dialog in transaction\n"); goto error; } } LM_DBG("Setting current dialog\n"); set_current_dialog(req, dlg); _dlg_ctx.dlg = dlg; ref_dlg(dlg, 1); return 0; error: LM_DBG("Error in build_new_dlg"); if (!spiral_detected) unref_dlg(dlg, 1); // undo ref regarding linking return -1; }
/*! * \brief Create a new dialog from a sip message * * Create a new dialog from a SIP message, register a callback * to keep track of the dialog with help of the tm module. * This function is either called from the request callback, or * from the dlg_manage function in the configuration script. * \see dlg_onreq * \see w_dlg_manage * \param req SIP message * \param t transaction * \param run_initial_cbs if set zero, initial callbacks are not executed * \return 0 on success, -1 on failure */ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs) { dlg_cell_t *dlg; str s; str callid; str ftag; str ttag; str req_uri; unsigned int dir; dlg = dlg_get_ctx_dialog(); if(dlg != NULL) { dlg_release(dlg); return -1; } if(req->first_line.u.request.method_value != METHOD_INVITE) return -1; if(pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) { LM_WARN("pre-matching failed\n"); return -1; } if(ttag.s!=0 && ttag.len!=0) return -1; if(pv_printf_s(req, ruri_param_model, &req_uri)<0) { LM_ERR("error - cannot print the r-uri format\n"); return -1; } trim(&req_uri); dir = DLG_DIR_NONE; /* search dialog by SIP attributes * - hash table slot is left locked */ dlg = dlg_search(&callid, &ftag, &ttag, &dir); if(dlg) { if (detect_spirals) { if (spiral_detected == 1) { dlg_hash_release(&callid); return 0; } if ( dlg->state != DLG_STATE_DELETED ) { LM_DBG("Callid '%.*s' found, must be a spiraled request\n", callid.len, callid.s); spiral_detected = 1; if (run_initial_cbs) run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0); /* set ctx dlg id shortcuts */ _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; /* search_dlg() has incremented the ref count by 1 */ dlg_release(dlg); dlg_hash_release(&callid); return 0; } dlg_release(dlg); } } spiral_detected = 0; dlg = build_new_dlg (&callid /*callid*/, &(get_from(req)->uri) /*from uri*/, &(get_to(req)->uri) /*to uri*/, &ftag/*from_tag*/, &req_uri /*r-uri*/ ); if (dlg==0) { dlg_hash_release(&callid); LM_ERR("failed to create new dialog\n"); return -1; } /* save caller's tag, cseq, contact and record route*/ if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG, &(get_from(req)->tag_value)) !=0) { dlg_hash_release(&callid); LM_ERR("could not add further info to the dialog\n"); shm_free(dlg); return -1; } /* Populate initial varlist: */ dlg->vars = get_local_varlist_pointer(req, 1); /* after dlg_search() slot was kept locked */ link_dlg(dlg, 0, 1); /* unlock after dlg_search() */ dlg_hash_release(&callid); dlg->lifetime = get_dlg_timeout(req); s.s = _dlg_ctx.to_route_name; s.len = strlen(s.s); dlg_set_toroute(dlg, &s); dlg->sflags |= _dlg_ctx.flags; dlg->iflags |= _dlg_ctx.iflags; if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0) dlg->iflags |= DLG_IFLAG_TIMEOUTBYE; if (run_initial_cbs) run_create_callbacks( dlg, req); /* first INVITE seen (dialog created, unconfirmed) */ if ( seq_match_mode!=SEQ_MATCH_NO_ID && add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) { LM_ERR("failed to add RR param\n"); goto error; } if_update_stat( dlg_enable_stats, processed_dlgs, 1); _dlg_ctx.cpid = my_pid(); _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; set_current_dialog(req, dlg); return 0; error: if (!spiral_detected) dlg_unref(dlg, 1); // undo ref regarding linking return -1; }
int dlg_create_dialog(struct cell* t, struct sip_msg *req,unsigned int flags) { struct dlg_cell *dlg; str s; int extra_ref; /* module is stricly designed for dialog calls */ if (req->first_line.u.request.method_value!=METHOD_INVITE) return -1; if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) { LM_ERR("bad request or missing TO hdr :-/\n"); return -1; } s = get_to(req)->tag_value; if (s.s!=0 && s.len!=0) return -1; if ( parse_from_header(req)) { LM_ERR("bad request or missing FROM hdr :-/\n"); return -1; } if ((!req->callid && parse_headers(req,HDR_CALLID_F,0)<0) || !req->callid){ LM_ERR("bad request or missing CALLID hdr :-/\n"); return -1; } s = req->callid->body; trim(&s); /* some sanity checks */ if (s.len==0 || get_from(req)->tag_value.len==0) { LM_ERR("invalid request -> callid (%d) or from TAG (%d) empty\n", s.len, get_from(req)->tag_value.len); return -1; } dlg = build_new_dlg( &s /*callid*/, &(get_from(req)->uri) /*from uri*/, &(get_to(req)->uri) /*to uri*/, &(get_from(req)->tag_value)/*from_tag*/ ); if (dlg==0) { LM_ERR("failed to create new dialog\n"); return -1; } dlg->flags |= flags; /* save caller's tag, cseq, contact and record route*/ if (init_leg_info(dlg, req, t, &(get_from(req)->tag_value),NULL,NULL ) !=0) { LM_ERR("could not add further info to the dialog\n"); shm_free(dlg); return -1; } /* set current dialog */ set_current_dialog(dlg); last_dst_leg = DLG_FIRST_CALLEE_LEG; extra_ref=2; /* extra ref for the callback and current dlg hook */ if (dlg_db_mode == DB_MODE_DELAYED) extra_ref++; /* extra ref for the timer to delete the dialog */ link_dlg( dlg , extra_ref); if ( seq_match_mode!=SEQ_MATCH_NO_ID && add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) { LM_ERR("failed to add RR param\n"); goto error; } if ( d_tmb.register_tmcb( req, t, TMCB_RESPONSE_PRE_OUT|TMCB_RESPONSE_FWDED|TMCB_TRANS_CANCELLED, dlg_onreply, (void*)dlg, unreference_dialog_create)<0 ) { LM_ERR("failed to register TMCB\n"); goto error; } /* complete the dialog setup only if transaction aleady exists; if not, wait for the TMCB_REQUEST_IN callback to do this job */ if (t) { /* first INVITE seen (dialog created, unconfirmed) */ run_create_callbacks( dlg, req); LM_DBG("t hash_index = %u, t label = %u\n",t->hash_index,t->label); dlg->initial_t_hash_index = t->hash_index; dlg->initial_t_label = t->label; dlg->lifetime = get_dlg_timeout(req); t->dialog_ctx = (void*) dlg; dlg->flags |= DLG_FLAG_ISINIT; } if_update_stat( dlg_enable_stats, processed_dlgs, 1); return 0; error: unref_dlg(dlg,2); dialog_cleanup( req, NULL); if_update_stat(dlg_enable_stats, failed_dlgs, 1); return -1; }