static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) { unsigned int h_entry, h_id; dlg_cell_t * dlg = NULL; str rpc_extra_hdrs = {NULL,0}; int n; n = rpc->scan(c, "dd", &h_entry, &h_id); if (n < 2) { LM_ERR("unable to read the parameters (%d)\n", n); rpc->fault(c, 500, "Invalid parameters"); return; } if(rpc->scan(c, "*S", &rpc_extra_hdrs)<1) { rpc_extra_hdrs.s = NULL; rpc_extra_hdrs.len = 0; } dlg = dlg_lookup(h_entry, h_id); if(dlg==NULL) { rpc->fault(c, 404, "Dialog not found"); return; } dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL); dlg_release(dlg); }
/*! * \brief Search a dialog in the global list by iuid * * Note that the caller is responsible for decrementing (or reusing) * the reference counter by one again if a dialog has been found. * \param diuid internal unique id per dialog * \return dialog structure on success, NULL on failure */ dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid) { if(diuid==NULL) return NULL; if(diuid->h_id==0) return NULL; /* dlg ref counter is increased by next line */ return dlg_lookup(diuid->h_entry, diuid->h_id); }
static int w_dlg_set_timeout(struct sip_msg *msg, char *pto, char *phe, char *phi) { int to = 0; unsigned int he = 0; unsigned int hi = 0; dlg_cell_t *dlg = NULL; if(fixup_get_ivalue(msg, (gparam_p)pto, &to)!=0) { LM_ERR("no timeout value\n"); return -1; } if(phe!=NULL) { if(fixup_get_ivalue(msg, (gparam_p)phe, (int*)&he)!=0) { LM_ERR("no hash entry value value\n"); return -1; } if(fixup_get_ivalue(msg, (gparam_p)phi, (int*)&hi)!=0) { LM_ERR("no hash id value value\n"); return -1; } dlg = dlg_lookup(he, hi); } else { dlg = dlg_get_msg_dialog(msg); } if(dlg==NULL) { LM_DBG("no dialog found\n"); return -1; } if(update_dlg_timeout(dlg, to) != 0) return -1; return 1; }
/*! * \brief Function that is registered as RR callback for dialog tracking * * Function that is registered as RR callback for dialog tracking. It * sets the appropriate events after the SIP method and run the state * machine to update the dialog state. It updates then the saved * dialogs and also the statistics. * \param req SIP request * \param route_params record-route parameter * \param param unused */ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) { dlg_cell_t *dlg; dlg_iuid_t *iuid; str val, callid, ftag, ttag; int h_entry, h_id, new_state, old_state, unref, event, timeout, reset; unsigned int dir; int ret = 0; dlg = dlg_get_ctx_dialog(); if (dlg!=NULL) { dlg_release(dlg); return; } /* skip initial requests - they may end up here because of the * preloaded route */ if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) { LM_ERR("bad request or missing TO hdr :-/\n"); return; } if ( get_to(req)->tag_value.len==0 ) return; dlg = 0; dir = DLG_DIR_NONE; if ( seq_match_mode!=SEQ_MATCH_NO_ID ) { if( d_rrb.get_route_param( req, &rr_param, &val)!=0) { LM_DBG("Route param '%.*s' not found\n", rr_param.len,rr_param.s); if (seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } else { LM_DBG("route param is '%.*s' (len=%d)\n",val.len,val.s,val.len); if ( parse_dlg_rr_param( val.s, val.s+val.len, &h_entry, &h_id)<0 ) return; dlg = dlg_lookup(h_entry, h_id); if (dlg==0) { LM_WARN("unable to find dialog for %.*s " "with route param '%.*s' [%u:%u]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, val.len,val.s, h_entry, h_id); if (seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } else { if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) { // lookup_dlg has incremented the ref count by 1 dlg_release(dlg); return; } if (match_dialog( dlg, &callid, &ftag, &ttag, &dir )==0) { LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, " "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, callid.len, callid.s, callid.len, ftag.len, ftag.s, ftag.len, ttag.len, ttag.s, ttag.len, dir); LM_WARN("dialog identification elements are callid='%.*s'/%d, " "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n", dlg->callid.len, dlg->callid.s, dlg->callid.len, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len); // lookup_dlg has incremented the ref count by 1 dlg_release(dlg); // Reset variables in order to do a lookup based on SIP-Elements. dlg = 0; dir = DLG_DIR_NONE; if (seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } } } } if (dlg==0) { if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) return; /* TODO - try to use the RR dir detection to speed up here the * search -bogdan */ dlg = get_dlg(&callid, &ftag, &ttag, &dir); if (dlg==0){ LM_DBG("Callid '%.*s' not found\n", req->callid->body.len, req->callid->body.s); return; } } /* set current dialog - re-use ref increment from dlg_get() above */ set_current_dialog( req, dlg); _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; if (req->first_line.u.request.method_value != METHOD_ACK) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { /* register callback for the replies of this request */ if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_IN|TMCB_ON_FAILURE, dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register TMCB (3)\n"); shm_free(iuid); } iuid = NULL; } } /* run state machine */ switch ( req->first_line.u.request.method_value ) { case METHOD_PRACK: event = DLG_EVENT_REQPRACK; break; case METHOD_ACK: event = DLG_EVENT_REQACK; break; case METHOD_BYE: event = DLG_EVENT_REQBYE; break; default: event = DLG_EVENT_REQ; } next_state_dlg( dlg, event, &old_state, &new_state, &unref); CURR_DLG_ID = req->id; CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts; CURR_DLG_STATUS = new_state; dlg_run_event_route(dlg, req, old_state, new_state); /* delay deletion of dialog until transaction has died off in order * to absorb in-air messages */ if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { if ( d_tmb.register_tmcb(req, NULL, TMCB_DESTROY, unref_dlg_from_cb, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register deletion delay function\n"); shm_free(iuid); } else { dlg_ref(dlg, 1); } } } if (new_state==DLG_STATE_CONFIRMED && old_state!=DLG_STATE_CONFIRMED) dlg_ka_add(dlg); /* run actions for the transition */ if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { LM_DBG("BYE successfully processed\n"); /* 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 { /* one extra unref due to removal from timer list */ unref++; } /* dialog terminated (BYE) */ dlg_terminated( req, dlg, dir); dlg_unref(dlg, unref); _dlg_ctx.cpid = my_pid(); _dlg_ctx.expect_t = 1; dlg_set_ctx_iuid(dlg); if_update_stat( dlg_enable_stats, active_dlgs, -1); goto done; } if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK) && (new_state==DLG_STATE_CONFIRMED || new_state==DLG_STATE_EARLY)) { timeout = get_dlg_timeout(req); if (timeout!=default_timeout) { dlg->lifetime = timeout; } reset = !((dlg->iflags & DLG_IFLAG_TIMER_NORESET) || dlg_timeout_noreset); if ((new_state!=DLG_STATE_EARLY) && (old_state!=DLG_STATE_CONFIRMED || reset)) { if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) { LM_ERR("failed to update dialog lifetime\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } } if(event != DLG_EVENT_REQACK) { if(dlg_refresh_contacts(dlg, req, dir)!=0) { LM_ERR("contacts update failed\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } if(update_cseqs(dlg, req, dir)!=0) { LM_ERR("cseqs update failed\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } } if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) { update_dialog_dbinfo(dlg); } if (old_state==DLG_STATE_CONFIRMED_NA) { LM_DBG("confirming ACK successfully processed\n"); /* confirming ACK request */ run_dlg_callbacks( DLGCB_CONFIRMED, dlg, req, NULL, dir, 0); } else { LM_DBG("sequential request successfully processed\n"); /* within dialog request */ run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0); if ( (event!=DLG_EVENT_REQACK) && (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { /* register callback for the replies of this request */ if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply: dlg_seq_up_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register TMCB (2)\n"); shm_free(iuid); } } } } } if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){ dlg->dflags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); } done: dlg_release(dlg); return; }
int dlg_set_timeout_by_profile(struct dlg_profile_table *profile, str *value, int timeout) { unsigned int i = 0; dlg_cell_t *this_dlg = NULL; struct dlg_profile_hash *ph = NULL; /* Private structure necessary for manipulating dialog * timeouts outside of profile locks. Admittedly, an * ugly hack, but avoids some concurrency issues. */ struct dlg_map_list { unsigned int h_id; unsigned int h_entry; struct dlg_map_list *next; } *map_head, *map_scan, *map_scan_next; map_head = NULL; /* If the profile has no value, iterate through every * node and set its timeout. */ if(profile->has_value == 0 || value == NULL) { lock_get(&profile->lock); for(i = 0; i < profile->size; i ++) { ph = profile->entries[i].first; if(!ph) continue; do { struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list)); if(!d) return -1; memset(d, 0, sizeof(struct dlg_map_list)); d->h_id = ph->dlg->h_id; d->h_entry = ph->dlg->h_entry; if(map_head == NULL) map_head = d; else { d->next = map_head; map_head = d; } ph = ph->next; } while(ph != profile->entries[i].first); } lock_release(&profile->lock); } else { i = calc_hash_profile(value, NULL, profile); lock_get(&profile->lock); ph = profile->entries[i].first; if(ph) { do { if(ph && value->len == ph->value.len && memcmp(value->s, ph->value.s, value->len) == 0) { struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list)); if(!d) return -1; memset(d, 0, sizeof(struct dlg_map_list)); d->h_id = ph->dlg->h_id; d->h_entry = ph->dlg->h_entry; if(map_head == NULL) map_head = d; else { d->next = map_head; map_head = d; } } ph = ph->next; } while(ph && ph != profile->entries[i].first); } lock_release(&profile->lock); } /* Walk the list and bulk-set the timeout */ for(map_scan = map_head; map_scan != NULL; map_scan = map_scan_next) { map_scan_next = map_scan->next; this_dlg = dlg_lookup(map_scan->h_entry, map_scan->h_id); if(!this_dlg) { LM_CRIT("Unable to find dialog %d:%d\n", map_scan->h_entry, map_scan->h_id); } else if(this_dlg->state >= DLG_STATE_EARLY) { if(update_dlg_timeout(this_dlg, timeout) < 0) { LM_ERR("Unable to set timeout on %d:%d\n", map_scan->h_entry, map_scan->h_id); } dlg_release(this_dlg); } free(map_scan); } return 0; }
/*parameters from MI: h_entry, h_id of the requested dialog*/ struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param ){ struct mi_node* node; unsigned int h_entry, h_id; struct dlg_cell * dlg = NULL; str mi_extra_hdrs = {NULL,0}; int status, msg_len; char *msg; if( d_table ==NULL) goto end; node = cmd_tree->node.kids; h_entry = h_id = 0; if (node==NULL || node->next==NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); if (!node->value.s|| !node->value.len|| strno2int(&node->value,&h_entry)<0) goto error; node = node->next; if ( !node->value.s || !node->value.len || strno2int(&node->value,&h_id)<0) goto error; if (node->next) { node = node->next; if (node->value.len && node->value.s) mi_extra_hdrs = node->value; } LM_DBG("h_entry %u h_id %u\n", h_entry, h_id); dlg = dlg_lookup(h_entry, h_id); // lookup_dlg has incremented the reference count if(dlg){ if(dlg_bye_all(dlg,(mi_extra_hdrs.len>0)?&mi_extra_hdrs:NULL)<0) { status = 500; msg = MI_DLG_OPERATION_ERR; msg_len = MI_DLG_OPERATION_ERR_LEN; } else { status = 200; msg = MI_OK_S; msg_len = MI_OK_LEN; } dlg_release(dlg); return init_mi_tree(status, msg, msg_len); } end: return init_mi_tree(404, MI_DIALOG_NOT_FOUND, MI_DIALOG_NOT_FOUND_LEN); error: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); }