/*! * \brief Helper function that run dialog callbacks on forwarded requests * \see dlg_seq_up_onreply * \see dlg_seq_down_onreply * \param t transaction, unused * \param type type of the callback, should be TMCB_RESPONSE_FWDED * \param param saved dialog structure inside the callback * \param direction direction of the request */ static void dlg_seq_onreply_helper(struct cell* t, int type, struct tmcb_params *param, const int direction) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; if (shutdown_done) return; iuid = (dlg_iuid_t*)(*param->param); dlg = dlg_get_by_iuid(iuid); if (dlg==0) return; if (type==TMCB_RESPONSE_FWDED) { run_dlg_callbacks( DLGCB_RESPONSE_WITHIN, dlg, param->req, param->rpl, direction, 0); } dlg_release(dlg); return; }
static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2) { dlg_ctx_t *dctx; dlg_cell_t *d; int val; int ret; if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0) { LM_ERR("no flag value\n"); return -1; } if(val<0 || val>31) return -1; if ( (dctx=dlg_get_dlg_ctx())==NULL ) return -1; d = dlg_get_by_iuid(&dctx->iuid); if(d!=NULL) { ret = (d->sflags&(1<<val))?1:-1; dlg_release(d); return ret; } return (dctx->flags&(1<<val))?1:-1; }
/*! * \brief Function that executes BYE reply callbacks * \param t transaction, unused * \param type type of the callback, should be TMCB_RESPONSE_FWDED * \param params saved dialog structure inside the callback */ static void dlg_terminated_confirmed(tm_cell_t *t, int type, struct tmcb_params* params) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; if(!params || !params->req || !params->param) { LM_ERR("invalid parameters!\n"); return; } iuid = (dlg_iuid_t*)*params->param; if(iuid==NULL) return; dlg = dlg_get_by_iuid(iuid); if(dlg==NULL) { LM_ERR("failed to get dialog from params!\n"); return; } /* dialog termination confirmed (BYE reply) */ run_dlg_callbacks(DLGCB_TERMINATED_CONFIRMED, dlg, params->req, params->rpl, DLG_DIR_UPSTREAM, 0); dlg_release(dlg); }
/** * run keep-alive list * */ int dlg_ka_run(ticks_t ti) { dlg_ka_t *dka; dlg_cell_t *dlg; if(dlg_ka_interval<=0) return 0; while(1) { /* get head item */ lock_get(dlg_ka_list_lock); if(*dlg_ka_list_head==NULL) { lock_release(dlg_ka_list_lock); return 0; } dka = *dlg_ka_list_head; #if 0 LM_DBG("dlg ka timer at %lu for" " dlg[%u,%u] on %lu\n", (unsigned long)ti, dka->iuid.h_entry, dka->iuid.h_id, (unsigned long)dka->katime); #endif if(dka->katime>ti) { lock_release(dlg_ka_list_lock); return 0; } if(*dlg_ka_list_head == *dlg_ka_list_tail) { *dlg_ka_list_head = NULL; *dlg_ka_list_tail = NULL; } *dlg_ka_list_head = dka->next; lock_release(dlg_ka_list_lock); /* send keep-alive for dka */ dlg = dlg_get_by_iuid(&dka->iuid); if(dlg==NULL) { shm_free(dka); dka = NULL; } else { if(dka->iflags & DLG_IFLAG_KA_SRC) dlg_send_ka(dlg, DLG_CALLER_LEG, 0); if(dka->iflags & DLG_IFLAG_KA_DST) dlg_send_ka(dlg, DLG_CALLEE_LEG, 0); dlg_release(dlg); } /* append to tail */ if(dka!=NULL) { lock_get(dlg_ka_list_lock); if(*dlg_ka_list_tail!=NULL) (*dlg_ka_list_tail)->next = dka; if(*dlg_ka_list_head==NULL) *dlg_ka_list_head = dka; *dlg_ka_list_tail = dka; lock_release(dlg_ka_list_lock); } } return 0; }
static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2) { dlg_ctx_t *dctx; dlg_cell_t *d; str val; if(fixup_get_svalue(msg, (gparam_t*)prop, &val)!=0) { LM_ERR("no property value\n"); return -1; } if(val.len<=0) { LM_ERR("empty property value\n"); return -1; } if ( (dctx=dlg_get_dlg_ctx())==NULL ) return -1; if(val.len==6 && strncmp(val.s, "ka-src", 6)==0) { dctx->iflags |= DLG_IFLAG_KA_SRC; d = dlg_get_by_iuid(&dctx->iuid); if(d!=NULL) { d->iflags |= DLG_IFLAG_KA_SRC; dlg_release(d); } } else if(val.len==6 && strncmp(val.s, "ka-dst", 6)==0) { dctx->iflags |= DLG_IFLAG_KA_DST; d = dlg_get_by_iuid(&dctx->iuid); if(d!=NULL) { d->iflags |= DLG_IFLAG_KA_DST; dlg_release(d); } } else if(val.len==15 && strncmp(val.s, "timeout-noreset", 15)==0) { dctx->iflags |= DLG_IFLAG_TIMER_NORESET; d = dlg_get_by_iuid(&dctx->iuid); if(d!=NULL) { d->iflags |= DLG_IFLAG_TIMER_NORESET; dlg_release(d); } } else { LM_ERR("unknown property value [%.*s]\n", val.len, val.s); return -1; } return 1; }
/*! * \brief Function that is registered as TM callback and called on T destroy * * - happens when wait_ack==1 * */ static void dlg_ontdestroy(struct cell* t, int type, struct tmcb_params *param) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; iuid = (dlg_iuid_t*)(*param->param); dlg = dlg_get_by_iuid(iuid); if(dlg==0) return; /* 1 for callback and 1 for dlg lookup */ dlg_unref(dlg, 2); }
/*! * \brief Unreference a dialog from tm callback (another wrapper) * \param t transaction, unused * \param type type of the entered callback * \param param saved dialog structure in the callback */ static void unref_dlg_from_cb(struct cell* t, int type, struct tmcb_params *param) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; iuid = (dlg_iuid_t*)(*param->param); if (iuid==NULL) return; dlg = dlg_get_by_iuid(iuid); if(dlg==NULL) return; /* unref by 2: 1 set when adding in tm cb, 1 sent by dlg_get_by_iuid() */ dlg_unref(dlg, 2); }
/* callback function to handle responses to the keep-alive request */ void dlg_ka_cb(struct cell* t, int type, struct tmcb_params* ps){ dlg_cell_t* dlg; dlg_iuid_t *iuid = NULL; if(ps->param == NULL || *ps->param == NULL) { LM_ERR("invalid parameter\n"); return; } if(ps->code < 200) { LM_DBG("receiving a provisional reply\n"); return; } LM_DBG("receiving a final reply %d\n",ps->code); iuid = (dlg_iuid_t*)(*ps->param); dlg = dlg_get_by_iuid(iuid); if(dlg==0) { dlg_iuid_sfree(iuid); return; } if(ps->code==408 || ps->code==481) { if(update_dlg_timer(&dlg->tl, 10)<0) { LM_ERR("failed to update dialog lifetime\n"); goto done; } dlg->lifetime = 10; dlg->dflags |= DLG_FLAG_CHANGED; } done: dlg_unref(dlg, 1); dlg_iuid_sfree(iuid); }
dlg_cell_t* dlg_get_ctx_dialog(void) { return dlg_get_by_iuid(&_dlg_ctx.iuid); }
/*! * \brief Function that is registered as TM callback and called on replies * * Function that is registered as TM callback and called on replies. It * parses the reply and set the appropriate event. This is then used to * update the dialog state, run eventual dialog callbacks and save or * update the necessary informations about the dialog. * \see next_state_dlg * \param t transaction, unused * \param type type of the entered callback * \param param saved dialog structure in the callback */ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; int new_state, old_state, unref, event; str tag; sip_msg_t *req = param->req; sip_msg_t *rpl = param->rpl; if (shutdown_done) return; iuid = (dlg_iuid_t*)(*param->param); dlg = dlg_get_by_iuid(iuid); if(dlg==0) return; unref = 0; if (type & (TMCB_RESPONSE_IN|TMCB_ON_FAILURE)) { /* Set the dialog context so it is available in onreply_route and failure_route*/ set_current_dialog(req, dlg); dlg_set_ctx_iuid(dlg); goto done; } if (type==TMCB_RESPONSE_FWDED) { /* The state does not change, but the msg is mutable in this callback*/ run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); goto done; } if (type==TMCB_DESTROY) event = DLG_EVENT_TDEL; else if (param->code<200) event = DLG_EVENT_RPL1xx; else if (param->code<300) event = DLG_EVENT_RPL2xx; else event = DLG_EVENT_RPL3xx; next_state_dlg( dlg, event, &old_state, &new_state, &unref); dlg_run_event_route(dlg, (rpl==FAKED_REPLY)?NULL:rpl, old_state, new_state); if (new_state==DLG_STATE_EARLY) { run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (old_state!=DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, 1); goto done; } if (new_state==DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) { LM_DBG("dialog %p confirmed (ACK pending)\n",dlg); if (rpl != FAKED_REPLY) { /* get to tag*/ if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0) || !rpl->to) ) { LM_ERR("bad reply or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else { tag = get_to(rpl)->tag_value; if (tag.s==0 || tag.len==0) { LM_ERR("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } /* save callee's tag, cseq, contact and record route*/ if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) { LM_ERR("could not add further info to the dialog\n"); } } else { LM_ERR("Faked reply!\n"); } /* set start time */ dlg->start_ts = (unsigned int)(time(0)); /* save the settings to the database, * if realtime saving mode configured- save dialog now * else: the next time the timer will fire the update*/ dlg->dflags |= DLG_FLAG_NEW; if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) { LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else { /* dialog pointer inserted in timer list */ dlg_ref(dlg, 1); } /* dialog confirmed (ACK pending) */ run_dlg_callbacks( DLGCB_CONFIRMED_NA, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (old_state==DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, -1); if (unref) dlg_unref(dlg, unref); if_update_stat(dlg_enable_stats, active_dlgs, 1); goto done; } if ( new_state==DLG_STATE_DELETED && (old_state==DLG_STATE_UNCONFIRMED || old_state==DLG_STATE_EARLY) ) { LM_DBG("dialog %p failed (negative reply)\n", dlg); /* dialog setup not completed (3456XX) */ run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if(dlg_wait_ack==1) dlg_set_tm_waitack(t, dlg); /* do unref */ if (unref) dlg_unref(dlg, unref); if (old_state==DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, -1); if_update_stat(dlg_enable_stats, failed_dlgs, 1); goto done; } if (unref) dlg_unref(dlg, unref); done: /* unref due to dlg_get_by_iuid() */ dlg_release(dlg); return; }
/** * @brief ht dmq callback */ int dlg_dmq_handle_msg(struct sip_msg* msg, peer_reponse_t* resp, dmq_node_t* node) { int content_length; str body; dlg_cell_t *dlg; int unref = 0; int ret; srjson_doc_t jdoc, prof_jdoc; srjson_t *it = NULL; dlg_dmq_action_t action = DLG_DMQ_NONE; dlg_iuid_t iuid; str profiles = {0, 0}, callid = {0, 0}, tag1 = {0,0}, tag2 = {0,0}, contact1 = {0,0}, contact2 = {0,0}, k={0,0}, v={0,0}; str cseq1 = {0,0}, cseq2 = {0,0}, route_set1 = {0,0}, route_set2 = {0,0}, from_uri = {0,0}, to_uri = {0,0}, req_uri = {0,0}; unsigned int init_ts = 0, start_ts = 0, lifetime = 0; unsigned int state = 1; srjson_t *vj; /* received dmq message */ LM_DBG("dmq message received\n"); if(!msg->content_length) { LM_ERR("no content length header found\n"); goto invalid2; } content_length = get_content_length(msg); if(!content_length) { LM_DBG("content length is 0\n"); goto invalid2; } body.s = get_body(msg); body.len = content_length; if (!body.s) { LM_ERR("unable to get body\n"); goto error; } /* parse body */ LM_DBG("body: %.*s\n", body.len, body.s); srjson_InitDoc(&jdoc, NULL); jdoc.buf = body; if(jdoc.root == NULL) { jdoc.root = srjson_Parse(&jdoc, jdoc.buf.s); if(jdoc.root == NULL) { LM_ERR("invalid json doc [[%s]]\n", jdoc.buf.s); goto invalid; } } for(it=jdoc.root->child; it; it = it->next) { if ((it->string == NULL) || (strcmp(it->string, "vars")==0)) continue; LM_DBG("found field: %s\n", it->string); if (strcmp(it->string, "action")==0) { action = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "h_entry")==0) { iuid.h_entry = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "h_id")==0) { iuid.h_id = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "init_ts")==0) { init_ts = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "start_ts")==0) { start_ts = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "state")==0) { state = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "lifetime")==0) { lifetime = SRJSON_GET_UINT(it); } else if (strcmp(it->string, "callid")==0) { callid.s = it->valuestring; callid.len = strlen(callid.s); } else if (strcmp(it->string, "profiles")==0) { profiles.s = it->valuestring; profiles.len = strlen(profiles.s); } else if (strcmp(it->string, "tag1")==0) { tag1.s = it->valuestring; tag1.len = strlen(tag1.s); } else if (strcmp(it->string, "tag2")==0) { tag2.s = it->valuestring; tag2.len = strlen(tag2.s); } else if (strcmp(it->string, "cseq1")==0) { cseq1.s = it->valuestring; cseq1.len = strlen(cseq1.s); } else if (strcmp(it->string, "cseq2")==0) { cseq2.s = it->valuestring; cseq2.len = strlen(cseq2.s); } else if (strcmp(it->string, "route_set1")==0) { route_set1.s = it->valuestring; route_set1.len = strlen(route_set1.s); } else if (strcmp(it->string, "route_set2")==0) { route_set2.s = it->valuestring; route_set2.len = strlen(route_set2.s); } else if (strcmp(it->string, "contact1")==0) { contact1.s = it->valuestring; contact1.len = strlen(contact1.s); } else if (strcmp(it->string, "contact2")==0) { contact2.s = it->valuestring; contact2.len = strlen(contact2.s); } else if (strcmp(it->string, "from_uri")==0) { from_uri.s = it->valuestring; from_uri.len = strlen(from_uri.s); } else if (strcmp(it->string, "to_uri")==0) { to_uri.s = it->valuestring; to_uri.len = strlen(to_uri.s); } else if (strcmp(it->string, "req_uri")==0) { req_uri.s = it->valuestring; req_uri.len = strlen(req_uri.s); } else { LM_ERR("unrecognized field in json object\n"); } } dlg = dlg_get_by_iuid(&iuid); if (dlg) { LM_DBG("found dialog [%u:%u] at %p\n", iuid.h_entry, iuid.h_id, dlg); unref++; } switch(action) { case DLG_DMQ_UPDATE: LM_DBG("Updating dlg [%u:%u] with callid [%.*s]\n", iuid.h_entry, iuid.h_id, callid.len, callid.s); if (!dlg) { dlg = build_new_dlg(&callid, &from_uri, &to_uri, &tag1, &req_uri); if (!dlg) { LM_ERR("failed to build new dialog\n"); goto error; } if(dlg->h_entry != iuid.h_entry){ LM_ERR("inconsistent hash data from peer: " "make sure all Kamailio's use the same hash size\n"); shm_free(dlg); goto error; } /* link the dialog */ link_dlg(dlg, 0, 0); dlg_set_leg_info(dlg, &tag1, &route_set1, &contact1, &cseq1, 0); /* override generated h_id */ dlg->h_id = iuid.h_id; /* prevent DB sync */ dlg->dflags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED); dlg->iflags |= DLG_IFLAG_DMQ_SYNC; } else { /* remove existing profiles */ if (dlg->profile_links!=NULL) { destroy_linkers(dlg->profile_links); dlg->profile_links = NULL; } } dlg->init_ts = init_ts; dlg->start_ts = start_ts; vj = srjson_GetObjectItem(&jdoc, jdoc.root, "vars"); if(vj!=NULL) { for(it=vj->child; it; it = it->next) { k.s = it->string; k.len = strlen(k.s); v.s = it->valuestring; v.len = strlen(v.s); set_dlg_variable(dlg, &k, &v); } } /* add profiles */ if(profiles.s!=NULL) { srjson_InitDoc(&prof_jdoc, NULL); prof_jdoc.buf = profiles; dlg_json_to_profiles(dlg, &prof_jdoc); srjson_DestroyDoc(&prof_jdoc); } if (state == dlg->state) { break; } /* intentional fallthrough */ case DLG_DMQ_STATE: if (!dlg) { LM_ERR("dialog [%u:%u] not found\n", iuid.h_entry, iuid.h_id); goto error; } if (state < dlg->state) { LM_NOTICE("Ignoring backwards state change on dlg [%u:%u]" " with callid [%.*s] from state [%u] to state [%u]\n", iuid.h_entry, iuid.h_id, dlg->callid.len, dlg->callid.s, dlg->state, state); break; } LM_DBG("State update dlg [%u:%u] with callid [%.*s] from state [%u]" " to state [%u]\n", iuid.h_entry, iuid.h_id, dlg->callid.len, dlg->callid.s, dlg->state, state); switch (state) { case DLG_STATE_EARLY: dlg->start_ts = start_ts; dlg->lifetime = lifetime; dlg_set_leg_info(dlg, &tag1, &route_set1, &contact1, &cseq1, 0); break; case DLG_STATE_CONFIRMED: dlg->start_ts = start_ts; dlg->lifetime = lifetime; dlg_set_leg_info(dlg, &tag1, &route_set1, &contact1, &cseq1, 0); dlg_set_leg_info(dlg, &tag2, &route_set2, &contact2, &cseq2, 1); if (insert_dlg_timer( &dlg->tl, dlg->lifetime ) != 0) { LM_CRIT("Unable to insert dlg timer %p [%u:%u]\n", dlg, dlg->h_entry, dlg->h_id); } else { /* dialog pointer inserted in timer list */ dlg_ref(dlg, 1); } break; case DLG_STATE_DELETED: if (dlg->state == DLG_STATE_CONFIRMED) { ret = remove_dialog_timer(&dlg->tl); if (ret == 0) { /* one extra unref due to removal from timer list */ unref++; } else if (ret < 0) { LM_CRIT("unable to unlink the timer on dlg %p [%u:%u]\n", dlg, dlg->h_entry, dlg->h_id); } } /* prevent DB sync */ dlg->dflags |= DLG_FLAG_NEW; /* keep dialog around for a bit, to prevent out-of-order * syncs to reestablish the dlg */ dlg->init_ts = time(NULL); break; default: LM_ERR("unhandled state update to state %u\n", state); dlg_unref(dlg, unref); goto error; } dlg->state = state; break; case DLG_DMQ_RM: if (!dlg) { LM_DBG("dialog [%u:%u] not found\n", iuid.h_entry, iuid.h_id); goto error; } LM_DBG("Removed dlg [%u:%u] with callid [%.*s] int state [%u]\n", iuid.h_entry, iuid.h_id, dlg->callid.len, dlg->callid.s, dlg->state); if (dlg->state==DLG_STATE_CONFIRMED || dlg->state==DLG_STATE_EARLY) { ret = remove_dialog_timer(&dlg->tl); if (ret == 0) { /* one extra unref due to removal from timer list */ unref++; } else if (ret < 0) { LM_CRIT("unable to unlink the timer on dlg %p [%u:%u]\n", dlg, dlg->h_entry, dlg->h_id); } } /* prevent DB sync */ dlg->dflags |= DLG_FLAG_NEW; unref++; break; case DLG_DMQ_SYNC: dmq_send_all_dlgs(0); break; case DLG_DMQ_NONE: break; } if (dlg && unref) dlg_unref(dlg, unref); srjson_DestroyDoc(&jdoc); resp->reason = dmq_200_rpl; resp->resp_code = 200; return 0; invalid: srjson_DestroyDoc(&jdoc); invalid2: resp->reason = dmq_400_rpl; resp->resp_code = 400; return 0; error: srjson_DestroyDoc(&jdoc); resp->reason = dmq_500_rpl; resp->resp_code = 500; return 0; }
/* callback function to handle responses to the BYE request */ void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps){ struct dlg_cell* dlg; int event, old_state, new_state, unref, ret; dlg_iuid_t *iuid = NULL; if(ps->param == NULL || *ps->param == NULL){ LM_ERR("invalid parameter\n"); return; } if(ps->code < 200){ LM_DBG("receiving a provisional reply\n"); return; } LM_DBG("receiving a final reply %d\n",ps->code); iuid = (dlg_iuid_t*)(*ps->param); dlg = dlg_get_by_iuid(iuid); if(dlg==0) return; event = DLG_EVENT_REQBYE; next_state_dlg(dlg, event, &old_state, &new_state, &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); /* remove from timer */ ret = remove_dialog_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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else if (ret > 0) { LM_WARN("inconsitent dlg timer data 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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else { unref++; } /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, ps->rpl, DLG_DIR_NONE, 0); LM_DBG("first final reply\n"); /* derefering the dialog */ dlg_unref(dlg, unref+1); 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 (dlg_db_mode) remove_dialog_from_db(dlg); /* force delete from mem */ dlg_unref(dlg, 1); } dlg_iuid_sfree(iuid); }
int pv_get_dlg(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { dlg_cell_t *dlg = NULL; int res_type = 0; str sv = { 0 }; unsigned int ui = 0; if(param==NULL) return -1; if(_dlg_ctx.iuid.h_id==0) { /* Retrieve the dialog for current message */ dlg=dlg_get_msg_dialog(msg); } else { /* Retrieve the dialog for current context */ dlg=dlg_get_by_iuid(&_dlg_ctx.iuid); } if(dlg == NULL) return pv_get_null(msg, param, res); switch(param->pvn.u.isname.name.n) { case 1: res_type = 1; ui = (unsigned int)dlg->h_id; break; case 2: res_type = 1; ui = (unsigned int)dlg->state; break; case 3: if(dlg->route_set[DLG_CALLEE_LEG].s==NULL || dlg->route_set[DLG_CALLEE_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->route_set[DLG_CALLEE_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->route_set[DLG_CALLEE_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 4: res_type = 1; ui = (unsigned int)dlg->dflags; break; case 5: res_type = 1; ui = (unsigned int)dlg->sflags; break; case 6: if(dlg->callid.s==NULL || dlg->callid.len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->callid.len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->callid.s, sv.len); sv.s[sv.len] = '\0'; break; case 7: if(dlg->to_uri.s==NULL || dlg->to_uri.len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->to_uri.len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->to_uri.s, sv.len); sv.s[sv.len] = '\0'; break; case 8: if(dlg->tag[DLG_CALLEE_LEG].s==NULL || dlg->tag[DLG_CALLEE_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->tag[DLG_CALLEE_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->tag[DLG_CALLEE_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 9: res_type = 1; ui = (unsigned int)dlg->toroute; break; case 10: if(dlg->cseq[DLG_CALLEE_LEG].s==NULL || dlg->cseq[DLG_CALLEE_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->cseq[DLG_CALLEE_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->cseq[DLG_CALLEE_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 11: if(dlg->route_set[DLG_CALLER_LEG].s==NULL || dlg->route_set[DLG_CALLER_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->route_set[DLG_CALLER_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->route_set[DLG_CALLER_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 12: if(dlg->from_uri.s==NULL || dlg->from_uri.len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->from_uri.len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->from_uri.s, sv.len); sv.s[sv.len] = '\0'; break; case 13: if(dlg->tag[DLG_CALLER_LEG].s==NULL || dlg->tag[DLG_CALLER_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->tag[DLG_CALLER_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->tag[DLG_CALLER_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 14: res_type = 1; ui = (unsigned int)dlg->lifetime; break; case 15: res_type = 1; ui = (unsigned int)dlg->start_ts; break; case 16: if(dlg->cseq[DLG_CALLER_LEG].s==NULL || dlg->cseq[DLG_CALLER_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->cseq[DLG_CALLER_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->cseq[DLG_CALLER_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 17: if(dlg->contact[DLG_CALLEE_LEG].s==NULL || dlg->contact[DLG_CALLEE_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->contact[DLG_CALLEE_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->contact[DLG_CALLEE_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 18: if(dlg->bind_addr[DLG_CALLEE_LEG]==NULL) goto done; sv.s = pv_get_buffer(); sv.len = dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s, sv.len); sv.s[sv.len] = '\0'; break; case 19: if(dlg->contact[DLG_CALLER_LEG].s==NULL || dlg->contact[DLG_CALLER_LEG].len<=0) goto done; sv.s = pv_get_buffer(); sv.len = dlg->contact[DLG_CALLER_LEG].len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->contact[DLG_CALLER_LEG].s, sv.len); sv.s[sv.len] = '\0'; break; case 20: if(dlg->bind_addr[DLG_CALLER_LEG]==NULL) goto done; sv.s = pv_get_buffer(); sv.len = dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len; if(pv_get_buffer_size()<sv.len) goto done; res_type = 2; strncpy(sv.s, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s, sv.len); sv.s[sv.len] = '\0'; break; case 21: res_type = 1; ui = (unsigned int)dlg->h_entry; break; default: res_type = 1; ui = (unsigned int)dlg->ref; } done: dlg_release(dlg); switch(res_type) { case 1: return pv_get_uintval(msg, param, res, ui); case 2: return pv_get_strval(msg, param, res, &sv); default: return pv_get_null(msg, param, res); } }