/*! * \brief Helper function that output all dialogs via the MI interface * \see mi_print_dlgs * \param rpl MI node that should be filled * \param with_context if 1 then the dialog context will be also printed * \return 0 on success, -1 on failure */ static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context) { struct dlg_cell *dlg; unsigned int i; LM_DBG("printing %i dialogs\n", d_table->size); for( i=0 ; i<d_table->size ; i++ ) { dlg_lock( d_table, &(d_table->entries[i]) ); for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) { if (internal_mi_print_dlg(rpl, dlg, with_context)!=0) goto error; } dlg_unlock( d_table, &(d_table->entries[i]) ); } return 0; error: dlg_unlock( d_table, &(d_table->entries[i]) ); LM_ERR("failed to print dialog\n"); return -1; }
/*! * \brief Link a dialog profile * \param linker dialog linker * \param dlg dialog cell */ static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg) { struct dlg_entry *d_entry; /* add the linker to the dialog */ /* FIXME zero h_id is not 100% for testing if the dialog is inserted * into the hash table -> we need circular lists -bogdan */ if (dlg->h_id) { d_entry = &d_table->entries[dlg->h_entry]; dlg_lock( d_table, d_entry); linker->next = dlg->profile_links; dlg->profile_links =linker; linker->hash_linker.dlg = dlg; dlg_unlock( d_table, d_entry); } else { linker->next = dlg->profile_links; dlg->profile_links =linker; linker->hash_linker.dlg = dlg; } atomic_or_int((volatile int*)&dlg->dflags, DLG_FLAG_CHANGED_PROF); link_profile(linker, &dlg->callid); }
int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val) { if( !dlg || !key || key->len > strlen(key->s) || (val && val->len > strlen(val->s))) { LM_ERR("BUG - bad parameters\n"); return -1; } dlg_lock(d_table, &(d_table->entries[dlg->h_entry])); if( !val) { if (set_dlg_variable_unsafe(dlg, key, NULL)!=0) { LM_ERR("failed to delete dialog variable <%.*s>\n", key->len,key->s); goto error; } } else { if (set_dlg_variable_unsafe(dlg, key, val)!=0) { LM_ERR("failed to store dialog values <%.*s>\n",key->len,key->s); goto error; } } dlg->dflags &= DLG_FLAG_CHANGED_VARS; dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); print_lists(dlg); return 0; error: dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); return -1; }
int dlg_dmq_replicate_action(dlg_dmq_action_t action, dlg_cell_t* dlg, int needlock, dmq_node_t *node ) { srjson_doc_t jdoc, prof_jdoc; dlg_var_t *var; LM_DBG("replicating action [%d] on [%u:%u] to dmq peers\n", action, dlg->h_entry, dlg->h_id); if (action == DLG_DMQ_UPDATE) { if (!node && (dlg->iflags & DLG_IFLAG_DMQ_SYNC) && ((dlg->dflags & DLG_FLAG_CHANGED_PROF) == 0)) { LM_DBG("dlg not changed, no sync\n"); return 1; } } else if ( (dlg->iflags & DLG_IFLAG_DMQ_SYNC) == 0 ) { LM_DBG("dlg not synced, no sync\n"); return 1; } if (action == DLG_DMQ_STATE && (dlg->state != DLG_STATE_CONFIRMED && dlg->state != DLG_STATE_DELETED && dlg->state != DLG_STATE_EARLY)) { LM_DBG("not syncing state %u\n", dlg->state); return 1; } srjson_InitDoc(&jdoc, NULL); jdoc.root = srjson_CreateObject(&jdoc); if(jdoc.root==NULL) { LM_ERR("cannot create json root\n"); goto error; } if (needlock) dlg_lock(d_table, &(d_table->entries[dlg->h_entry])); srjson_AddNumberToObject(&jdoc, jdoc.root, "action", action); srjson_AddNumberToObject(&jdoc, jdoc.root, "h_entry", dlg->h_entry); srjson_AddNumberToObject(&jdoc, jdoc.root, "h_id", dlg->h_id); switch(action) { case DLG_DMQ_UPDATE: dlg->iflags |= DLG_IFLAG_DMQ_SYNC; dlg->dflags &= ~DLG_FLAG_CHANGED_PROF; srjson_AddNumberToObject(&jdoc, jdoc.root, "init_ts", dlg->init_ts); srjson_AddStrToObject(&jdoc, jdoc.root, "callid", dlg->callid.s, dlg->callid.len); srjson_AddStrToObject(&jdoc, jdoc.root, "from_uri", dlg->from_uri.s, dlg->from_uri.len); srjson_AddStrToObject(&jdoc, jdoc.root, "to_uri", dlg->to_uri.s, dlg->to_uri.len); srjson_AddStrToObject(&jdoc, jdoc.root, "req_uri", dlg->req_uri.s, dlg->req_uri.len); srjson_AddStrToObject(&jdoc, jdoc.root, "tag1", dlg->tag[0].s, dlg->tag[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "cseq1", dlg->cseq[0].s, dlg->cseq[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "route_set1", dlg->route_set[0].s, dlg->route_set[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "contact1", dlg->contact[0].s, dlg->contact[0].len); if (dlg->vars != NULL) { srjson_t *pj = NULL; pj = srjson_CreateObject(&jdoc); for(var=dlg->vars ; var ; var=var->next) { srjson_AddStrToObject(&jdoc, pj, var->key.s, var->value.s, var->value.len); } srjson_AddItemToObject(&jdoc, jdoc.root, "vars", pj); } if (dlg->profile_links) { srjson_InitDoc(&prof_jdoc, NULL); dlg_profiles_to_json(dlg, &prof_jdoc); if(prof_jdoc.buf.s!=NULL) { LM_DBG("adding profiles: [%.*s]\n", prof_jdoc.buf.len, prof_jdoc.buf.s); srjson_AddStrToObject(&jdoc, jdoc.root, "profiles", prof_jdoc.buf.s, prof_jdoc.buf.len); prof_jdoc.free_fn(prof_jdoc.buf.s); prof_jdoc.buf.s = NULL; } srjson_DestroyDoc(&prof_jdoc); } /* intentional fallthrough */ case DLG_DMQ_STATE: srjson_AddNumberToObject(&jdoc, jdoc.root, "state", dlg->state); switch (dlg->state) { case DLG_STATE_EARLY: srjson_AddNumberToObject(&jdoc, jdoc.root, "start_ts", dlg->start_ts); srjson_AddNumberToObject(&jdoc, jdoc.root, "lifetime", dlg->lifetime); srjson_AddStrToObject(&jdoc, jdoc.root, "tag1", dlg->tag[0].s, dlg->tag[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "cseq1", dlg->cseq[0].s, dlg->cseq[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "route_set1", dlg->route_set[0].s, dlg->route_set[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "contact1", dlg->contact[0].s, dlg->contact[0].len); break; case DLG_STATE_CONFIRMED: srjson_AddNumberToObject(&jdoc, jdoc.root, "start_ts", dlg->start_ts); srjson_AddNumberToObject(&jdoc, jdoc.root, "lifetime", dlg->lifetime); srjson_AddStrToObject(&jdoc, jdoc.root, "tag1", dlg->tag[0].s, dlg->tag[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "tag2", dlg->tag[1].s, dlg->tag[1].len); srjson_AddStrToObject(&jdoc, jdoc.root, "cseq1", dlg->cseq[0].s, dlg->cseq[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "cseq2", dlg->cseq[1].s, dlg->cseq[1].len); srjson_AddStrToObject(&jdoc, jdoc.root, "route_set1", dlg->route_set[0].s, dlg->route_set[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "route_set2", dlg->route_set[1].s, dlg->route_set[1].len); srjson_AddStrToObject(&jdoc, jdoc.root, "contact1", dlg->contact[0].s, dlg->contact[0].len); srjson_AddStrToObject(&jdoc, jdoc.root, "contact2", dlg->contact[1].s, dlg->contact[1].len); break; case DLG_STATE_DELETED: //dlg->iflags &= ~DLG_IFLAG_DMQ_SYNC; break; default: LM_DBG("not syncing state %u\n", dlg->state); } break; case DLG_DMQ_RM: srjson_AddNumberToObject(&jdoc, jdoc.root, "state", dlg->state); dlg->iflags &= ~DLG_IFLAG_DMQ_SYNC; break; case DLG_DMQ_NONE: case DLG_DMQ_SYNC: break; } if (needlock) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); jdoc.buf.s = srjson_PrintUnformatted(&jdoc, jdoc.root); if(jdoc.buf.s==NULL) { LM_ERR("unable to serialize data\n"); goto error; } jdoc.buf.len = strlen(jdoc.buf.s); LM_DBG("sending serialized data %.*s\n", jdoc.buf.len, jdoc.buf.s); if (dlg_dmq_send(&jdoc.buf, node)!=0) { goto error; } jdoc.free_fn(jdoc.buf.s); jdoc.buf.s = NULL; srjson_DestroyDoc(&jdoc); return 0; error: if(jdoc.buf.s!=NULL) { jdoc.free_fn(jdoc.buf.s); jdoc.buf.s = NULL; } srjson_DestroyDoc(&jdoc); return -1; }
/** * replicates a confirmed dialog from another OpenSIPS instance * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_create(struct dlg_cell *cell, str *ftag, str *ttag, int safe) { int next_id, h_entry; unsigned int dir, dst_leg; str callid, from_uri, to_uri, from_tag, to_tag; str cseq1,cseq2,contact1,contact2,rroute1,rroute2,mangled_fu,mangled_tu; str sock, vars, profiles; struct dlg_cell *dlg = NULL; struct socket_info *caller_sock, *callee_sock; struct dlg_entry *d_entry; if_update_stat(dlg_enable_stats, processed_dlgs, 1); LM_DBG("Received replicated dialog!\n"); if (!cell) { bin_pop_str(&callid); bin_pop_str(&from_tag); bin_pop_str(&to_tag); bin_pop_str(&from_uri); bin_pop_str(&to_uri); dlg = get_dlg(&callid, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&callid); d_entry = &d_table->entries[h_entry]; if (safe) dlg_lock(d_table, d_entry); if (dlg) { LM_DBG("Dialog with ci '%.*s' is already created\n", callid.len, callid.s); unref_dlg_unsafe(dlg, 1, d_entry); dlg_unlock(d_table, d_entry); return 0; } dlg = build_new_dlg(&callid, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto pre_linking_error; } } else { h_entry = dlg_hash(&cell->callid); d_entry = &d_table->entries[h_entry]; if (safe) dlg_lock(d_table, d_entry); from_tag = *ftag; to_tag = *ttag; dlg = cell; } bin_pop_int(&dlg->h_id); bin_pop_int(&dlg->start_ts); bin_pop_int(&dlg->state); next_id = d_table->entries[dlg->h_entry].next_id; d_table->entries[dlg->h_entry].next_id = (next_id <= dlg->h_id) ? (dlg->h_id + 1) : next_id; if (bin_pop_str(&sock)) goto pre_linking_error; caller_sock = fetch_socket_info(&sock); if (bin_pop_str(&sock)) goto pre_linking_error; callee_sock = fetch_socket_info(&sock); if (!caller_sock || !callee_sock) { LM_ERR("Dialog in DB doesn't match any listening sockets\n"); goto pre_linking_error; } bin_pop_str(&cseq1); bin_pop_str(&cseq2); bin_pop_str(&rroute1); bin_pop_str(&rroute2); bin_pop_str(&contact1); bin_pop_str(&contact2); bin_pop_str(&mangled_fu); bin_pop_str(&mangled_tu); /* add the 2 legs */ if (dlg_add_leg_info(dlg, &from_tag, &rroute1, &contact1, &cseq1, caller_sock, 0, 0) != 0 || dlg_add_leg_info(dlg, &to_tag, &rroute2, &contact2, &cseq2, callee_sock, &mangled_fu, &mangled_tu) != 0) { LM_ERR("dlg_set_leg_info failed\n"); goto pre_linking_error; } dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG; /* link the dialog into the hash */ dlg->h_id = d_entry->next_id++; if (!d_entry->first) d_entry->first = d_entry->last = dlg; else { d_entry->last->next = dlg; dlg->prev = d_entry->last; d_entry->last = dlg; } dlg->ref++; d_entry->cnt++; bin_pop_str(&vars); bin_pop_str(&profiles); bin_pop_int(&dlg->user_flags); bin_pop_int(&dlg->flags); bin_pop_int((void *)&dlg->tl.timeout); bin_pop_int(&dlg->legs[DLG_CALLER_LEG].last_gen_cseq); bin_pop_int(&dlg->legs[callee_idx(dlg)].last_gen_cseq); if (dlg->tl.timeout <= (unsigned int)time(0)) dlg->tl.timeout = 0; else dlg->tl.timeout -= (unsigned int)time(0); /* restore the timer values */ if (insert_dlg_timer(&dlg->tl, (int)dlg->tl.timeout) != 0) { LM_CRIT("Unable to insert 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->legs[DLG_CALLER_LEG].tag.len, dlg->legs[DLG_CALLER_LEG].tag.s, dlg->legs[callee_idx(dlg)].tag.len, ZSW(dlg->legs[callee_idx(dlg)].tag.s)); goto error; } if (dlg->state == DLG_STATE_CONFIRMED_NA || dlg->state == DLG_STATE_CONFIRMED) active_dlgs_cnt++; /* reference the dialog as kept in the timer list */ ref_dlg_unsafe(dlg, 1); LM_DBG("Received initial timeout of %d for dialog %.*s, safe = %d\n",dlg->tl.timeout,callid.len,callid.s,safe); dlg->lifetime = 0; /* Do not replicate the pinging - we might terminate dialogs badly when running as backup if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { if (insert_ping_timer(dlg) != 0) LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); else { ref_dlg_unsafe(dlg, 1); } } */ if (dlg_db_mode == DB_MODE_DELAYED) { /* to be later removed by timer */ ref_dlg_unsafe(dlg, 1); } if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 0, 1); if_update_stat(dlg_enable_stats, active_dlgs, 1); run_load_callback_per_dlg(dlg); return 0; pre_linking_error: dlg_unlock(d_table, d_entry); if (dlg) destroy_dlg(dlg); return -1; error: dlg_unlock(d_table, d_entry); if (dlg) unref_dlg(dlg, 1); return -1; }
/** * replicates the remote update of an ongoing dialog locally * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_update(void) { struct dlg_cell *dlg; str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles; unsigned int dir, dst_leg; int timeout, h_entry; str st; struct dlg_entry *d_entry; bin_pop_str(&call_id); bin_pop_str(&from_tag); bin_pop_str(&to_tag); bin_pop_str(&from_uri); bin_pop_str(&to_uri); LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n", call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s, from_uri.len, from_uri.s, to_uri.len, to_uri.s); dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&call_id); d_entry = &d_table->entries[h_entry]; dlg_lock(d_table, d_entry); if (!dlg) { /* TODO: change to LM_DBG */ LM_ERR("dialog not found, building new\n"); dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto error; } return dlg_replicated_create(dlg, &from_tag, &to_tag, 0); } bin_skip_int(2); bin_pop_int(&dlg->state); bin_skip_str(2); bin_pop_str(&st); if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) { LM_ERR("failed to update caller cseq\n"); goto error; } bin_pop_str(&st); if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) { LM_ERR("failed to update callee cseq\n"); goto error; } bin_skip_str(6); bin_pop_str(&vars); bin_pop_str(&profiles); bin_pop_int(&dlg->user_flags); bin_pop_int(&dlg->flags); bin_pop_int(&timeout); bin_skip_int(2); timeout -= time(0); LM_DBG("Received updated timeout of %d for dialog %.*s\n",timeout,call_id.len,call_id.s); if (dlg->lifetime != timeout) { dlg->lifetime = timeout; if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) LM_ERR("failed to update dialog lifetime!\n"); } unref_dlg_unsafe(dlg, 1, d_entry); if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 1, 1); return 0; error: dlg_unlock(d_table, d_entry); return -1; }
/** * replicates a confirmed dialog from another OpenSIPS instance * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_create(bin_packet_t *packet, struct dlg_cell *cell, str *ftag, str *ttag, int safe) { int h_entry; unsigned int dir, dst_leg; str callid = { NULL, 0 }, from_uri, to_uri, from_tag, to_tag; str cseq1, cseq2, contact1, contact2, rroute1, rroute2, mangled_fu, mangled_tu; str sock, vars, profiles; struct dlg_cell *dlg = NULL; struct socket_info *caller_sock, *callee_sock; struct dlg_entry *d_entry; LM_DBG("Received replicated dialog!\n"); if (!cell) { DLG_BIN_POP(str, packet, callid, malformed); DLG_BIN_POP(str, packet, from_tag, malformed); DLG_BIN_POP(str, packet, to_tag, malformed); DLG_BIN_POP(str, packet, from_uri, malformed); DLG_BIN_POP(str, packet, to_uri, malformed); dlg = get_dlg(&callid, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&callid); d_entry = &d_table->entries[h_entry]; if (safe) dlg_lock(d_table, d_entry); if (dlg) { LM_DBG("Dialog with ci '%.*s' is already created\n", callid.len, callid.s); unref_dlg_unsafe(dlg, 1, d_entry); /* unmark dlg as loaded from DB (otherwise it would have been * dropped later when syncing from cluster is done) */ dlg->flags &= ~DLG_FLAG_FROM_DB; dlg_unlock(d_table, d_entry); return 0; } dlg = build_new_dlg(&callid, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto pre_linking_error; } } else { h_entry = dlg_hash(&cell->callid); d_entry = &d_table->entries[h_entry]; if (safe) dlg_lock(d_table, d_entry); from_tag = *ftag; to_tag = *ttag; dlg = cell; } if_update_stat(dlg_enable_stats, processed_dlgs, 1); DLG_BIN_POP(int, packet, dlg->h_id, pre_linking_error); DLG_BIN_POP(int, packet, dlg->start_ts, pre_linking_error); DLG_BIN_POP(int, packet, dlg->state, pre_linking_error); /* next_id follows the max value of all replicated ids */ if (d_table->entries[dlg->h_entry].next_id <= dlg->h_id) d_table->entries[dlg->h_entry].next_id = dlg->h_id + 1; DLG_BIN_POP(str, packet, sock, pre_linking_error); caller_sock = fetch_socket_info(&sock); DLG_BIN_POP(str, packet, sock, pre_linking_error); callee_sock = fetch_socket_info(&sock); if (!caller_sock || !callee_sock) { LM_ERR("Replicated dialog doesn't match any listening sockets\n"); goto pre_linking_error; } DLG_BIN_POP(str, packet, cseq1, pre_linking_error); DLG_BIN_POP(str, packet, cseq2, pre_linking_error); DLG_BIN_POP(str, packet, rroute1, pre_linking_error); DLG_BIN_POP(str, packet, rroute2, pre_linking_error); DLG_BIN_POP(str, packet, contact1, pre_linking_error); DLG_BIN_POP(str, packet, contact2, pre_linking_error); DLG_BIN_POP(str, packet, mangled_fu, pre_linking_error); DLG_BIN_POP(str, packet, mangled_tu, pre_linking_error); /* add the 2 legs */ /* TODO - sdp here */ if (dlg_update_leg_info(0, dlg, &from_tag, &rroute1, &contact1, &cseq1, caller_sock, 0, 0,0) != 0 || dlg_update_leg_info(1, dlg, &to_tag, &rroute2, &contact2, &cseq2, callee_sock, &mangled_fu, &mangled_tu,0) != 0) { LM_ERR("dlg_set_leg_info failed\n"); goto pre_linking_error; } dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG; /* link the dialog into the hash */ if (!d_entry->first) d_entry->first = d_entry->last = dlg; else { d_entry->last->next = dlg; dlg->prev = d_entry->last; d_entry->last = dlg; } dlg->ref++; d_entry->cnt++; DLG_BIN_POP(str, packet, vars, pre_linking_error); DLG_BIN_POP(str, packet, profiles, pre_linking_error); DLG_BIN_POP(int, packet, dlg->user_flags, pre_linking_error); DLG_BIN_POP(int, packet, dlg->mod_flags, pre_linking_error); DLG_BIN_POP(int, packet, dlg->flags, pre_linking_error); /* also save the dialog into the DB on this instance */ dlg->flags |= DLG_FLAG_NEW; DLG_BIN_POP(int, packet, dlg->tl.timeout, pre_linking_error); DLG_BIN_POP(int, packet, dlg->legs[DLG_CALLER_LEG].last_gen_cseq, pre_linking_error); DLG_BIN_POP(int, packet, dlg->legs[callee_idx(dlg)].last_gen_cseq, pre_linking_error); if (dlg->tl.timeout <= (unsigned int) time(0)) dlg->tl.timeout = 0; else dlg->tl.timeout -= (unsigned int) time(0); /* restore the timer values */ if (insert_dlg_timer(&dlg->tl, (int) dlg->tl.timeout) != 0) { LM_CRIT("Unable to insert 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->legs[DLG_CALLER_LEG].tag.len, dlg->legs[DLG_CALLER_LEG].tag.s, dlg->legs[callee_idx(dlg)].tag.len, ZSW(dlg->legs[callee_idx(dlg)].tag.s)); goto error; } if (dlg->state == DLG_STATE_CONFIRMED_NA || dlg->state == DLG_STATE_CONFIRMED) active_dlgs_cnt++; /* reference the dialog as kept in the timer list */ ref_dlg_unsafe(dlg, 1); LM_DBG("Received initial timeout of %d for dialog %.*s, safe = %d\n", dlg->tl.timeout, callid.len, callid.s, safe); dlg->lifetime = 0; if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { if (insert_ping_timer(dlg) != 0) LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); else { ref_dlg_unsafe(dlg, 1); } } if (dlg_db_mode == DB_MODE_DELAYED) { /* to be later removed by timer */ ref_dlg_unsafe(dlg, 1); } if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 0, 1); if_update_stat(dlg_enable_stats, active_dlgs, 1); run_load_callback_per_dlg(dlg); return 0; pre_linking_error: dlg_unlock(d_table, d_entry); if (dlg) destroy_dlg(dlg); return -1; error: dlg_unlock(d_table, d_entry); if (dlg) unref_dlg(dlg, 1); malformed: return -1; }
void rcv_cluster_event(enum clusterer_event ev, int node_id) { struct dlg_sharing_tag *tag; struct n_send_info *ni; int lock_old_flag; struct dlg_cell *dlg, *next_dlg; int i; int ret; int unref; if (ev == SYNC_REQ_RCV && receive_sync_request(node_id) < 0) LM_ERR("Failed to reply to sync request from node: %d\n", node_id); else if (ev == SYNC_DONE) { if (dlg_db_mode == DB_MODE_NONE) return; /* drop dialogs loaded from DB which have not been reconfirmed * through syncing or SIP(updates) */ for (i = 0; i < d_table->size; i++) { dlg_lock(d_table, &d_table->entries[i]); dlg = d_table->entries[i].first; while (dlg) { if (!(dlg->flags & DLG_FLAG_FROM_DB)) { dlg = dlg->next; continue; } LM_DBG("Drop DB loaded dialog ID=%lld\n", ((long long)dlg->h_entry << 32) | (dlg->h_id)); unref = 1; /* unref from hash */ dlg->state = DLG_STATE_DELETED; destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; /* remove from timer */ ret = remove_dlg_timer(&dlg->tl); if (ret < 0) { LM_ERR("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) /* successfully removed from timer list */ unref++; if (dlg_db_mode != DB_MODE_SHUTDOWN) { dlg->flags &= ~DLG_FLAG_NEW; remove_dialog_from_db(dlg); dlg->flags |= DLG_FLAG_DB_DELETED; } if (dlg_db_mode == DB_MODE_DELAYED) unref++; next_dlg = dlg->next; unref_dlg_unsafe(dlg, unref, &d_table->entries[i]); dlg = next_dlg; } dlg_unlock(d_table, &d_table->entries[i]); } } else if (ev == CLUSTER_NODE_UP) { lock_start_sw_read(shtags_lock); for (tag = *shtags_list; tag; tag = tag->next) { if (!tag->send_active_msg) continue; /* send sharing tag active msg to nodes to which we didn't already */ for (ni = tag->active_msgs_sent; ni && ni->node_id != node_id; ni = ni->next) ; if (!ni) { if (send_shtag_active_info(&tag->name, node_id) < 0) { LM_ERR("Failed to send info about sharing tag\n"); continue; } ni = shm_malloc(sizeof *ni); if (!ni) { LM_ERR("No more shm memory!\n"); return; } ni->node_id = node_id; ni->next = tag->active_msgs_sent; lock_switch_write(shtags_lock, lock_old_flag); tag->active_msgs_sent = ni; lock_switch_read(shtags_lock, lock_old_flag); } } lock_stop_sw_read(shtags_lock); } }
void next_state_dlg(struct dlg_cell *dlg, int event, int *old_state, int *new_state, int *unref) { struct dlg_entry *d_entry; d_entry = &(d_table->entries[dlg->h_entry]); *unref = 0; dlg_lock( d_table, d_entry); *old_state = dlg->state; switch (event) { case DLG_EVENT_TDEL: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_DELETED; unref_dlg_unsafe(dlg,1,d_entry); /* unref from TM CBs*/ *unref = 1; /* unref from hash -> t failed */ break; case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: unref_dlg_unsafe(dlg,1,d_entry); /* unref from TM CBs*/ break; case DLG_STATE_DELETED: /* as the dialog aleady is in DELETE state, it is dangerous to directly unref it from here as it might be last ref -> dialog will be destroied and we will end up with a dangling pointer :D - bogdan */ *unref = 1; /* unref from TM CBs*/ break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL1xx: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_EARLY; break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL3xx: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_DELETED; *unref = 1; /* unref from hash -> t failed */ break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL2xx: switch (dlg->state) { case DLG_STATE_DELETED: if (dlg->flags&DLG_FLAG_HASBYE) { log_next_state_dlg(event, dlg); break; } ref_dlg_unsafe(dlg,1); /* back in hash */ case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_CONFIRMED_NA; break; case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQACK: switch (dlg->state) { case DLG_STATE_CONFIRMED_NA: dlg->state = DLG_STATE_CONFIRMED; break; case DLG_STATE_CONFIRMED: break; case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQBYE: switch (dlg->state) { case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: dlg->flags |= DLG_FLAG_HASBYE; dlg->state = DLG_STATE_DELETED; *unref = 1; /* unref from hash -> dialog ended */ break; case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQPRACK: switch (dlg->state) { case DLG_STATE_EARLY: case DLG_STATE_CONFIRMED_NA: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQ: switch (dlg->state) { case DLG_STATE_EARLY: case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: break; default: log_next_state_dlg(event, dlg); } break; default: LM_CRIT("unknown event %d in state %d " "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n", event, 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)); } *new_state = dlg->state; dlg_unlock( d_table, d_entry); LM_DBG("dialog %p changed from state %d to " "state %d, due event %d\n",dlg,*old_state,*new_state,event); }
int update_dialog_dbinfo(struct dlg_cell * cell) { static db_ps_t my_ps_insert = NULL; static db_ps_t my_ps_update = NULL; static db_ps_t my_ps_update_vp = NULL; struct dlg_entry entry; db_val_t values[DIALOG_TABLE_TOTAL_COL_NO]; int callee_leg; db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { &h_entry_column, &h_id_column, &call_id_column, &from_uri_column, &from_tag_column, &to_uri_column, &to_tag_column, &from_sock_column, &to_sock_column, &start_time_column, &mangled_fu_column, &mangled_tu_column, &state_column, &timeout_column, &from_cseq_column, &to_cseq_column, &from_ping_cseq_column, &to_ping_cseq_column,&flags_column, &vars_column, &profiles_column, &sflags_column, &from_route_column, &to_route_column, &from_contact_column,&to_contact_column}; if(use_dialog_table()!=0) return -1; callee_leg= callee_idx(cell); if((cell->flags & DLG_FLAG_NEW) != 0){ /* save all the current dialogs information*/ VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = VAL_TYPE(values+16) = VAL_TYPE(values+17) = VAL_TYPE(values+18) = VAL_TYPE(values+21) = DB_INT; VAL_TYPE(values+2) = VAL_TYPE(values+3) = VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = VAL_TYPE(values+8) = VAL_TYPE(values+10) = VAL_TYPE(values+11) = VAL_TYPE(values+14) = VAL_TYPE(values+15) = VAL_TYPE(values+19) = VAL_TYPE(values+20) = VAL_TYPE(values+22) = VAL_TYPE(values+23) = VAL_TYPE(values+24) = VAL_TYPE(values+25) = DB_STR; /* lock the entry */ entry = (d_table->entries)[cell->h_entry]; dlg_lock( d_table, &entry); SET_INT_VALUE(values, cell->h_entry); SET_INT_VALUE(values+1, cell->h_id); SET_STR_VALUE(values+2, cell->callid); SET_STR_VALUE(values+3, cell->from_uri); SET_STR_VALUE(values+4, cell->legs[DLG_CALLER_LEG].tag); SET_STR_VALUE(values+5, cell->to_uri); SET_STR_VALUE(values+6, cell->legs[callee_leg].tag); SET_STR_VALUE(values+7, cell->legs[DLG_CALLER_LEG].bind_addr->sock_str); if (cell->legs[callee_leg].bind_addr) { SET_STR_VALUE(values+8, cell->legs[callee_leg].bind_addr->sock_str); } else { VAL_NULL(values+8) = 1; } SET_INT_VALUE(values+9, cell->start_ts); SET_STR_VALUE(values+10,cell->legs[callee_leg].from_uri); SET_STR_VALUE(values+11,cell->legs[callee_leg].to_uri); SET_INT_VALUE(values+12, cell->state); SET_INT_VALUE(values+13, (unsigned int)( (unsigned int)time(0) + cell->tl.timeout - get_ticks()) ); SET_STR_VALUE(values+14, cell->legs[DLG_CALLER_LEG].r_cseq); SET_STR_VALUE(values+15, cell->legs[callee_leg].r_cseq); SET_INT_VALUE(values+16,cell->legs[DLG_CALLER_LEG].last_gen_cseq); SET_INT_VALUE(values+17,cell->legs[callee_leg].last_gen_cseq); SET_INT_VALUE(values+18, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); set_final_update_cols(values+19, cell, 0); SET_STR_VALUE(values+22, cell->legs[DLG_CALLER_LEG].route_set); SET_STR_VALUE(values+23, cell->legs[callee_leg].route_set); SET_STR_VALUE(values+24, cell->legs[DLG_CALLER_LEG].contact); SET_STR_VALUE(values+25, cell->legs[callee_leg].contact); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert; if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, DIALOG_TABLE_TOTAL_COL_NO)) !=0){ LM_ERR("could not add another dialog to db\n"); goto error; } /* dialog saved */ run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); cell->flags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED); } else if((cell->flags & DLG_FLAG_CHANGED) != 0) { /* save only dialog's state and timeout */ VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = VAL_TYPE(values+16) = VAL_TYPE(values+17) = VAL_TYPE(values+18) = VAL_TYPE(values+21) =DB_INT; VAL_TYPE(values+14) = VAL_TYPE(values+15) = VAL_TYPE(values+19) = VAL_TYPE(values+20) = DB_STR; /* lock the entry */ entry = (d_table->entries)[cell->h_entry]; dlg_lock( d_table, &entry); SET_INT_VALUE(values, cell->h_entry); SET_INT_VALUE(values+1, cell->h_id); SET_INT_VALUE(values+12, cell->state); SET_INT_VALUE(values+13, (unsigned int)( (unsigned int)time(0) + cell->tl.timeout - get_ticks()) ); SET_STR_VALUE(values+14, cell->legs[DLG_CALLER_LEG].r_cseq); SET_STR_VALUE(values+15, cell->legs[callee_leg].r_cseq); SET_INT_VALUE(values+16,cell->legs[DLG_CALLER_LEG].last_gen_cseq); SET_INT_VALUE(values+17,cell->legs[callee_leg].last_gen_cseq); SET_INT_VALUE(values+18, cell->flags); set_final_update_cols(values+19, cell, 1); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update; if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, (values), (insert_keys+12), (values+12), 2, 10)) !=0){ LM_ERR("could not update database info\n"); goto error; } /* dialog saved */ run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); cell->flags &= ~(DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED); } else if (cell->flags & DLG_FLAG_VP_CHANGED) { cell->flags |= DLG_FLAG_VP_CHANGED; VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+21) = DB_INT; VAL_TYPE(values+19) = VAL_TYPE(values+20) = DB_STR; /* lock the entry */ entry = (d_table->entries)[cell->h_entry]; dlg_lock( d_table, &entry); SET_INT_VALUE(values, cell->h_entry); SET_INT_VALUE(values+1, cell->h_id); set_final_update_cols(values+19, cell, 0); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update_vp; if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, (values), (insert_keys+19), (values+19), 2, 3)) !=0){ LM_ERR("could not update database info\n"); goto error; } run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); cell->flags &= ~DLG_FLAG_VP_CHANGED; } else { return 0; } dlg_unlock( d_table, &entry); return 0; error: dlg_unlock( d_table, &entry); return -1; }
void dialog_update_db(unsigned int ticks, void * param) { static db_ps_t my_ps_update = NULL; static db_ps_t my_ps_insert = NULL; static db_ps_t my_ps_update_vp = NULL; int index; db_val_t values[DIALOG_TABLE_TOTAL_COL_NO]; struct dlg_entry entry; struct dlg_cell * cell; unsigned char on_shutdown; int callee_leg,ins_done=0; static query_list_t *ins_list = NULL; db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { &h_entry_column, &h_id_column, &call_id_column, &from_uri_column, &from_tag_column, &to_uri_column, &to_tag_column, &from_sock_column, &to_sock_column, &start_time_column, &from_route_column, &to_route_column, &from_contact_column, &to_contact_column, &mangled_fu_column, &mangled_tu_column, /*update chunk */ &state_column, &timeout_column, &from_cseq_column, &to_cseq_column, &from_ping_cseq_column, &to_ping_cseq_column, &vars_column, &profiles_column, &sflags_column, &flags_column}; if (dialog_db_handle==0 || use_dialog_table()!=0) return; on_shutdown = (ticks==0); /*save the current dialogs information*/ VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = VAL_TYPE(values+16) = VAL_TYPE(values+17) = VAL_TYPE(values+20) = VAL_TYPE(values+21) = VAL_TYPE(values+24) = VAL_TYPE(values+25)= DB_INT; VAL_TYPE(values+2) = VAL_TYPE(values+3) = VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = VAL_TYPE(values+8) = VAL_TYPE(values+10) = VAL_TYPE(values+11) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = VAL_TYPE(values+14) = VAL_TYPE(values+15) = VAL_TYPE(values+18) = VAL_TYPE(values+19) = VAL_TYPE(values+22) = VAL_TYPE(values+23) = DB_STR; for(index = 0; index< d_table->size; index++){ /* lock the whole entry */ entry = (d_table->entries)[index]; dlg_lock( d_table, &entry); for(cell = entry.first; cell != NULL; cell = cell->next){ callee_leg = callee_idx(cell); if( (cell->flags & DLG_FLAG_NEW) != 0 ) { if ( cell->state == DLG_STATE_DELETED ) { /* don't need to insert dialogs already terminated */ continue; } LM_DBG("inserting new dialog %p\n",cell); SET_INT_VALUE(values, cell->h_entry); SET_INT_VALUE(values+1, cell->h_id); SET_STR_VALUE(values+2, cell->callid); SET_STR_VALUE(values+3, cell->from_uri); SET_STR_VALUE(values+4, cell->legs[DLG_CALLER_LEG].tag); SET_STR_VALUE(values+5, cell->to_uri); SET_STR_VALUE(values+6, cell->legs[callee_leg].tag); SET_STR_VALUE(values+7, cell->legs[DLG_CALLER_LEG].bind_addr->sock_str); if (cell->legs[callee_leg].bind_addr) { SET_STR_VALUE(values+8, cell->legs[callee_leg].bind_addr->sock_str); } else { VAL_NULL(values+8) = 1; } SET_INT_VALUE(values+9, cell->start_ts); SET_STR_VALUE(values+10, cell->legs[DLG_CALLER_LEG].route_set); SET_STR_VALUE(values+11, cell->legs[callee_leg].route_set); SET_STR_VALUE(values+12, cell->legs[DLG_CALLER_LEG].contact); SET_STR_VALUE(values+13, cell->legs[callee_leg].contact); SET_STR_VALUE(values+14,cell->legs[callee_leg].from_uri); SET_STR_VALUE(values+15,cell->legs[callee_leg].to_uri); SET_INT_VALUE(values+16, cell->state); SET_INT_VALUE(values+17, (unsigned int)((unsigned int)time(0) + cell->tl.timeout - get_ticks()) ); SET_STR_VALUE(values+18, cell->legs[DLG_CALLER_LEG].r_cseq); SET_STR_VALUE(values+19, cell->legs[callee_leg].r_cseq); SET_INT_VALUE(values+20, cell->legs[DLG_CALLER_LEG].last_gen_cseq); SET_INT_VALUE(values+21, cell->legs[callee_leg].last_gen_cseq); set_final_update_cols(values+22, cell, on_shutdown); SET_INT_VALUE(values+25, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert; if (con_set_inslist(&dialog_dbf,dialog_db_handle, &ins_list,insert_keys,DIALOG_TABLE_TOTAL_COL_NO) < 0 ) CON_RESET_INSLIST(dialog_db_handle); if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, DIALOG_TABLE_TOTAL_COL_NO)) !=0){ LM_ERR("could not add another dialog to db\n"); goto error; } if (ins_done==0) ins_done=1; /* dialog saved */ run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); cell->flags &= ~(DLG_FLAG_NEW |DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED); } else if ( (cell->flags & DLG_FLAG_CHANGED)!=0 || on_shutdown ){ LM_DBG("updating existing dialog %p\n",cell); SET_INT_VALUE(values, cell->h_entry); SET_INT_VALUE(values+1, cell->h_id); SET_INT_VALUE(values+16, cell->state); SET_INT_VALUE(values+17, (unsigned int)((unsigned int)time(0) + cell->tl.timeout - get_ticks()) ); SET_STR_VALUE(values+18, cell->legs[DLG_CALLER_LEG].r_cseq); SET_STR_VALUE(values+19, cell->legs[callee_leg].r_cseq); SET_INT_VALUE(values+20, cell->legs[DLG_CALLER_LEG].last_gen_cseq); SET_INT_VALUE(values+21, cell->legs[callee_leg].last_gen_cseq); set_final_update_cols(values+22, cell, 1); SET_INT_VALUE(values+25, cell->flags); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update; if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, (values), (insert_keys+16), (values+16), 2, 10)) !=0) { LM_ERR("could not update database info\n"); goto error; } /* dialog saved */ run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); cell->flags &= ~(DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED); } else if (cell->flags & DLG_FLAG_VP_CHANGED) { SET_INT_VALUE(values, cell->h_entry); SET_INT_VALUE(values+1, cell->h_id); set_final_update_cols(values+22, cell, 0); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update_vp; if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, (values), (insert_keys+22), (values+22), 2, 3)) !=0) { LM_ERR("could not update database info\n"); goto error; } run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); cell->flags &= ~DLG_FLAG_VP_CHANGED; } } dlg_unlock( d_table, &entry); } if (ins_done) { LM_DBG("dlg timer attempting to flush rows to DB\n"); /* flush everything to DB * so that next-time timer fires * we are sure that DB updates will be succesful */ if (ql_flush_rows(&dialog_dbf,dialog_db_handle,ins_list) < 0) LM_ERR("failed to flush rows to DB\n"); } return; error: dlg_unlock( d_table, &entry); }
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 dlg_entry *d_entry; d_entry = &(d_table->entries[dlg->h_entry]); *unref = 0; dlg_lock( d_table, d_entry); *old_state = dlg->state; switch (event) { case DLG_EVENT_TDEL: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_DELETED; unref_dlg_unsafe(dlg,1,d_entry); /* unref from TM CBs*/ *unref = 1; /* unref from hash -> t failed */ break; case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: unref_dlg_unsafe(dlg,1,d_entry); /* unref from TM CBs*/ break; case DLG_STATE_DELETED: /* as the dialog aleady is in DELETE state, it is dangerous to directly unref it from here as it might be last ref -> dialog will be destroied and we will end up with a dangling pointer :D - bogdan */ *unref = 1; /* unref from TM CBs*/ break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL1xx: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_EARLY; break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL3xx: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_DELETED; *unref = 1; /* unref from hash -> t failed */ break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL2xx: switch (dlg->state) { case DLG_STATE_DELETED: if (dlg->flags&DLG_FLAG_HASBYE) { log_next_state_dlg(event, dlg); break; } ref_dlg_unsafe(dlg,1); /* back in hash */ case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_CONFIRMED_NA; break; case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQACK: switch (dlg->state) { case DLG_STATE_CONFIRMED_NA: dlg->state = DLG_STATE_CONFIRMED; break; case DLG_STATE_CONFIRMED: break; case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQBYE: 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] ) /* to end the call, the BYE must be received * on the same leg as the 200 OK for INVITE */ break; dlg->flags |= DLG_FLAG_HASBYE; dlg->state = DLG_STATE_DELETED; *unref = 1; /* unref from hash -> dialog ended */ break; case DLG_STATE_DELETED: break; default: /* only case for BYEs in early or unconfirmed states * is for requests generate by caller or callee. * We never internally generate BYEs for early dialogs * * RFC says caller may send BYEs for early dialogs, * while the callee side MUST not send such requests*/ if (last_dst_leg == 0) log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQPRACK: switch (dlg->state) { case DLG_STATE_EARLY: case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQ: switch (dlg->state) { case DLG_STATE_EARLY: case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: break; default: log_next_state_dlg(event, dlg); } break; default: LM_INFO("unknown event %d in state %d " "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n", event, 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)); } *new_state = dlg->state; dlg_unlock( d_table, d_entry); if (*old_state != *new_state) raise_state_changed_event( dlg->h_entry, dlg->h_id, (unsigned int)(*old_state), (unsigned int)(*new_state) ); if ( !is_replicated && dialog_replicate_cluster && (*old_state==DLG_STATE_CONFIRMED_NA || *old_state==DLG_STATE_CONFIRMED) && dlg->state==DLG_STATE_DELETED ) replicate_dialog_deleted(dlg); LM_DBG("dialog %p changed from state %d to " "state %d, due event %d\n",dlg,*old_state,*new_state,event); }
/* * IMPORTANT: if a dialog reference is returned, the dialog hash entry will be kept locked when this function returns NOTE: if a reply tree is returned, no dialog reference is returned. */ static inline struct mi_root* process_mi_params(struct mi_root *cmd_tree, struct dlg_cell **dlg_p, unsigned int *idx, unsigned int *cnt) { struct mi_node* node; struct dlg_entry *d_entry; struct dlg_cell *dlg; str *p1; str *p2; unsigned int h_entry; node = cmd_tree->node.kids; if (node == NULL) { /* no parameters at all */ *dlg_p = NULL; *idx = *cnt = 0; return NULL; } /* we have params -> get p1 and p2 */ p1 = &node->value; LM_DBG("p1='%.*s'\n", p1->len, p1->s); node = node->next; if ( !node || !node->value.s || !node->value.len) { p2 = NULL; } else { p2 = &node->value; LM_DBG("p2='%.*s'\n", p2->len, p2->s); if ( node->next!=NULL ) return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM)); } /* check the params */ if (p2 && str2int(p1,idx)==0 && str2int(p2,cnt)==0) { /* 2 numerical params -> index and counter */ *dlg_p = NULL; return NULL; } *idx = *cnt = 0; if (!p1->s) return init_mi_tree( 400, "Invalid Call-ID specified", 25); h_entry = dlg_hash( p1/*callid*/ ); d_entry = &(d_table->entries[h_entry]); dlg_lock( d_table, d_entry); for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) { if (match_downstream_dialog( dlg, p1/*callid*/, p2/*from_tag*/)==1) { if (dlg->state==DLG_STATE_DELETED) { *dlg_p = NULL; break; } else { *dlg_p = dlg; return 0; } } } dlg_unlock( d_table, d_entry); return init_mi_tree( 404, MI_SSTR("No such dialog")); }
int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) { dlg_cell_t *dlg = NULL; int ret = -1; if (param==NULL || param->pvn.type!=PV_NAME_INTSTR || param->pvn.u.isname.type!=AVP_NAME_STR || param->pvn.u.isname.name.s.s==NULL ) { LM_CRIT("BUG - bad parameters\n"); goto error; } /* Retrieve the dialog for current message */ dlg=dlg_get_msg_dialog( msg); if (dlg) { /* Lock the dialog */ dlg_lock(d_table, &(d_table->entries[dlg->h_entry])); } else { /* Verify the local list */ get_local_varlist_pointer(msg, 0); } if (val==NULL || val->flags&(PV_VAL_NONE|PV_VAL_NULL|PV_VAL_EMPTY)) { /* if NULL, remove the value */ ret = set_dlg_variable_unsafe(dlg, ¶m->pvn.u.isname.name.s, NULL); if(ret!= 0) { /* unlock dialog */ if (dlg) { dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); dlg_release(dlg); } return ret; } } else { /* if value, must be string */ if ( !(val->flags&PV_VAL_STR)) { LM_ERR("non-string values are not supported\n"); /* unlock dialog */ if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); goto error; } ret = set_dlg_variable_unsafe(dlg, ¶m->pvn.u.isname.name.s, &val->rs); if(ret!= 0) { /* unlock dialog */ if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); goto error; } } /* unlock dialog */ if (dlg) { dlg->dflags |= DLG_FLAG_CHANGED_VARS; dlg_unlock(d_table, &(d_table->entries[dlg->h_entry])); if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); } print_lists(dlg); dlg_release(dlg); return 0; error: dlg_release(dlg); return -1; }
/** * replicates the remote update of an ongoing dialog locally * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_update(bin_packet_t *packet) { struct dlg_cell *dlg; str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles; unsigned int dir, dst_leg; int timeout, h_entry; str st; struct dlg_entry *d_entry; int rcv_flags, save_new_flag; bin_pop_str(packet, &call_id); bin_pop_str(packet, &from_tag); bin_pop_str(packet, &to_tag); bin_pop_str(packet, &from_uri); bin_pop_str(packet, &to_uri); LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n", call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s, from_uri.len, from_uri.s, to_uri.len, to_uri.s); dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&call_id); d_entry = &d_table->entries[h_entry]; dlg_lock(d_table, d_entry); if (!dlg) { LM_DBG("dialog not found, building new\n"); dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto error; } return dlg_replicated_create(packet ,dlg, &from_tag, &to_tag, 0); } bin_skip_int(packet, 2); bin_pop_int(packet, &dlg->state); bin_skip_str(packet, 2); bin_pop_str(packet, &st); if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) { LM_ERR("failed to update caller cseq\n"); goto error; } bin_pop_str(packet, &st); if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) { LM_ERR("failed to update callee cseq\n"); goto error; } bin_skip_str(packet, 6); bin_pop_str(packet, &vars); bin_pop_str(packet, &profiles); bin_pop_int(packet, &dlg->user_flags); bin_pop_int(packet, &dlg->mod_flags); bin_pop_int(packet, &rcv_flags); /* make sure an update received immediately after a create can't * incorrectly erase the DLG_FLAG_NEW before locally writing to DB */ save_new_flag = dlg->flags & DLG_FLAG_NEW; dlg->flags = rcv_flags; dlg->flags |= ((save_new_flag ? DLG_FLAG_NEW : 0) | DLG_FLAG_CHANGED); bin_pop_int(packet, &timeout); bin_skip_int(packet, 2); timeout -= time(0); LM_DBG("Received updated timeout of %d for dialog %.*s\n", timeout, call_id.len, call_id.s); if (dlg->lifetime != timeout) { dlg->lifetime = timeout; switch (update_dlg_timer(&dlg->tl, dlg->lifetime) ) { case -1: LM_ERR("failed to update dialog lifetime!\n"); /* continue */ case 0: /* timeout value was updated */ break; case 1: /* dlg inserted in timer list with new expire (reference it)*/ ref_dlg(dlg,1); } } unref_dlg_unsafe(dlg, 1, d_entry); if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg->flags |= DLG_FLAG_VP_CHANGED; dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 1, 1); return 0; error: dlg_unlock(d_table, d_entry); return -1; }
/*! * \brief Update a dialog state according a event and the old state * * This functions implement the main state machine that update a dialog * state according a processed event and the current state. If necessary * it will delete the processed dialog. The old and new state are also * saved for reference. * \param dlg updated dialog * \param event current event * \param old_state old dialog state * \param new_state new dialog state * \param unref set to 1 when the dialog was deleted, 0 otherwise */ void next_state_dlg(dlg_cell_t *dlg, int event, int *old_state, int *new_state, int *unref) { dlg_entry_t *d_entry; d_entry = &(d_table->entries[dlg->h_entry]); *unref = 0; dlg_lock( d_table, d_entry); *old_state = dlg->state; switch (event) { case DLG_EVENT_TDEL: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_DELETED; unref_dlg_unsafe(dlg,1,d_entry); *unref = 1; break; case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: unref_dlg_unsafe(dlg,1,d_entry); break; case DLG_STATE_DELETED: *unref = 1; break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL1xx: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_EARLY; break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL3xx: switch (dlg->state) { case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_DELETED; *unref = 1; break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_RPL2xx: switch (dlg->state) { case DLG_STATE_DELETED: if (dlg->dflags&DLG_FLAG_HASBYE) { LM_CRIT("bogus event %d in state %d (with BYE) " "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n", event, dlg->state, 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); break; } ref_dlg_unsafe(dlg,1); case DLG_STATE_UNCONFIRMED: case DLG_STATE_EARLY: dlg->state = DLG_STATE_CONFIRMED_NA; break; case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQACK: switch (dlg->state) { case DLG_STATE_CONFIRMED_NA: dlg->state = DLG_STATE_CONFIRMED; break; case DLG_STATE_CONFIRMED: break; case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQBYE: switch (dlg->state) { case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: dlg->dflags |= DLG_FLAG_HASBYE; dlg->state = DLG_STATE_DELETED; *unref = 1; break; case DLG_STATE_EARLY: case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQPRACK: switch (dlg->state) { case DLG_STATE_EARLY: case DLG_STATE_CONFIRMED_NA: case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; case DLG_EVENT_REQ: switch (dlg->state) { case DLG_STATE_EARLY: case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: case DLG_STATE_DELETED: break; default: log_next_state_dlg(event, dlg); } break; default: LM_CRIT("unknown event %d in state %d " "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n", event, dlg->state, 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); } *new_state = dlg->state; /* remove the dialog from profiles when is not no longer active */ if(*new_state==DLG_STATE_DELETED && dlg->profile_links!=NULL && *old_state!=*new_state) { destroy_linkers(dlg->profile_links); dlg->profile_links = NULL; } dlg_unlock( d_table, d_entry); LM_DBG("dialog %p changed from state %d to " "state %d, due event %d (ref %d)\n", dlg, *old_state, *new_state, event, dlg->ref); }
void dlg_onroute(struct sip_msg* req, str *route_params, void *param) { struct dlg_cell *dlg; str val = {0,0}; str callid; str ftag; str ttag; int h_entry; int h_id; int new_state; int old_state; int unref; int event; int timeout; unsigned int update_val; unsigned int dir,dst_leg,src_leg; int ret = 0,ok = 1; struct dlg_entry *d_entry; str *msg_cseq; char *final_cseq; /* as this callback is triggered from loose_route, which can be accidentaly called more than once from script, we need to be sure we do this only once !*/ if (current_dlg_pointer) 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; dst_leg = -1; /* From RR callback, param will be NULL * From match_dialog, param might have a value, if we * are in the topology hiding case & we were able to extract the * DID from the R-URI */ if (param) val = *((str *)param); if ( seq_match_mode!=SEQ_MATCH_NO_ID ) { if( val.s == NULL && 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 = lookup_dlg( h_entry, h_id); if (dlg==0) { LM_DBG("unable to find dialog for %.*s " "with route param '%.*s'\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, val.len,val.s); } else { /* lookup_dlg has incremented the ref count by 1 */ if (pre_match_parse( req, &callid, &ftag, &ttag)<0) { unref_dlg(dlg, 1); return; } if (match_dialog(dlg,&callid,&ftag,&ttag,&dir, &dst_leg )==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->legs[DLG_CALLER_LEG].tag.len, dlg->legs[DLG_CALLER_LEG].tag.s, dlg->legs[DLG_CALLER_LEG].tag.len, dlg->legs[callee_idx(dlg)].tag.len, ZSW(dlg->legs[callee_idx(dlg)].tag.s), dlg->legs[callee_idx(dlg)].tag.len); unref_dlg(dlg, 1); dlg = NULL; } } if (dlg==NULL && seq_match_mode==SEQ_MATCH_STRICT_ID ) return; } } if (dlg==0) { if (pre_match_parse( req, &callid, &ftag, &ttag)<0) return; /* TODO - try to use the RR dir detection to speed up here the * search -bogdan */ dlg = get_dlg(&callid, &ftag, &ttag, &dir, &dst_leg); if (!dlg){ LM_DBG("Callid '%.*s' not found\n", req->callid->body.len, req->callid->body.s); return; } } /* 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; } /* 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, &old_state, &new_state, &unref); /* set current dialog - it will keep a ref! */ set_current_dialog(dlg); log_bogus_dst_leg(dlg); d_entry = &(d_table->entries[dlg->h_entry]); if(dlg->flags & DLG_FLAG_TOPHIDING) { dlg_th_onroute(dlg, req, dir); } /* run actions for the transition */ if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { /*destroy linkers */ destroy_linkers(dlg->profile_links); dlg->profile_links = NULL; if (!dlg->terminate_reason.s) { if (last_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); if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { dlg_lock (d_table,d_entry); if (dlg->legs[dst_leg].last_gen_cseq) { update_val = ++(dlg->legs[dst_leg].last_gen_cseq); dlg_unlock (d_table,d_entry); if (update_msg_cseq(req,0,update_val) != 0) LM_ERR("failed to update BYE msg cseq\n"); msg_cseq = &((struct cseq_body *)req->cseq->parsed)->number; final_cseq = shm_malloc(msg_cseq->len + 1); if (final_cseq == 0) { LM_ERR("no more shm mem\n"); goto after_unlock5; } memcpy(final_cseq,msg_cseq->s,msg_cseq->len); final_cseq[msg_cseq->len] = 0; if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, fix_final_cseq, (void*)final_cseq, 0)<0 ) { LM_ERR("failed to register TMCB (2)\n"); } } else dlg_unlock (d_table,d_entry); } after_unlock5: /* 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->legs[DLG_CALLER_LEG].tag.len, dlg->legs[DLG_CALLER_LEG].tag.s, dlg->legs[callee_idx(dlg)].tag.len, ZSW(dlg->legs[callee_idx(dlg)].tag.s)); } else if (ret > 0) { LM_DBG("dlg expired (not in timer list) 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->legs[DLG_CALLER_LEG].tag.len, dlg->legs[DLG_CALLER_LEG].tag.s, dlg->legs[callee_idx(dlg)].tag.len, ZSW(dlg->legs[callee_idx(dlg)].tag.s)); } else { /* dialog sucessfully removed from timer -> unref */ unref++; } /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, dir, 0); /* delete the dialog from DB */ if (should_remove_dlg_db()) remove_dialog_from_db(dlg); /* destroy dialog */ unref_dlg(dlg, unref); if_update_stat( dlg_enable_stats, active_dlgs, -1); return; } if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK) && new_state==DLG_STATE_CONFIRMED) { LM_DBG("sequential request successfully processed (dst_leg=%d)\n", dst_leg); /* within dialog request */ run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0); timeout = get_dlg_timeout_update(req); /* update timer during sequential request? */ if (timeout != 0) { dlg->lifetime = timeout; if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) LM_ERR("failed to update dialog lifetime\n"); } if ( event!=DLG_EVENT_REQACK ) { if (dst_leg==-1 || switch_cseqs(dlg, dst_leg) != 0 || update_cseqs(dlg,req,dst_leg,0)) { ok = 0; LM_ERR("cseqs update failed on leg=%d\n",dst_leg); } if (req->first_line.u.request.method_value == METHOD_INVITE) { if (dst_leg == DLG_CALLER_LEG) src_leg = callee_idx(dlg); else src_leg = DLG_CALLER_LEG; if (update_cseqs(dlg,req,src_leg,1) != 0) { ok=0; LM_ERR("failed to update inv cseq on leg %d\n",src_leg); } } if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { dlg_lock (d_table, d_entry); if (dlg->legs[dst_leg].last_gen_cseq) { update_val = ++(dlg->legs[dst_leg].last_gen_cseq); dlg_unlock( d_table, d_entry ); if (update_msg_cseq(req,0,update_val) != 0) { LM_ERR("failed to update sequential request msg cseq\n"); ok = 0; } } else dlg_unlock( d_table, d_entry ); } if (ok) { dlg->flags |= DLG_FLAG_CHANGED; if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); if (replication_dests) replicate_dialog_updated(dlg); } } else { if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { dlg_lock (d_table, d_entry); if (dlg->legs[dst_leg].last_gen_cseq) { update_val = dlg->legs[dst_leg].last_gen_cseq; dlg_unlock( d_table, d_entry ); if (update_msg_cseq(req,0,update_val) != 0) { LM_ERR("failed to update ACK msg cseq\n"); } } else dlg_unlock( d_table, d_entry ); } } if ( event!=DLG_EVENT_REQACK) { /* register callback for the replies of this request */ if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { dlg_lock( d_table, d_entry); if (dlg->legs[dst_leg].last_gen_cseq) { /* ref the dialog as registered into the transaction callback. * unref will be done when the callback will be destroyed */ ref_dlg_unsafe( dlg, 1); dlg_unlock( d_table,d_entry); if(parse_headers(req, HDR_CSEQ_F, 0) <0 ) { LM_ERR("failed to parse cseq header \n"); unref_dlg(dlg,1); goto early_check; } msg_cseq = &((struct cseq_body *)req->cseq->parsed)->number; dlg_cseq_wrapper *wrap = shm_malloc(sizeof(dlg_cseq_wrapper) + msg_cseq->len); if (wrap == 0){ LM_ERR("No more shm mem\n"); unref_dlg(dlg, 1); goto early_check; } wrap->dlg = dlg; wrap->cseq.s = (char *)(wrap + 1); wrap->cseq.len = msg_cseq->len; memcpy(wrap->cseq.s,msg_cseq->s,msg_cseq->len); if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply_mod_cseq:dlg_seq_up_onreply_mod_cseq, (void*)wrap, unreference_dialog_cseq)<0 ) { LM_ERR("failed to register TMCB (2)\n"); unref_dlg( dlg , 1); shm_free(wrap); } } else { /* dialog is in ping timer list * but no pings have been generated yet */ dlg_unlock ( d_table, d_entry ); goto regular_indlg_req; } } else { regular_indlg_req: if (dlg->cbs.types & DLGCB_RESPONSE_WITHIN) { ref_dlg( dlg , 1); if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, (dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply:dlg_seq_up_onreply, (void*)dlg, unreference_dialog)<0 ) { LM_ERR("failed to register TMCB (2)\n"); unref_dlg( dlg , 1); } } } } } early_check: if ( (event==DLG_EVENT_REQPRACK || event == DLG_EVENT_REQ) && new_state==DLG_STATE_EARLY) { /* within dialog request */ run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0); LM_DBG("EARLY event %d successfully processed (dst_leg=%d)\n",event,dst_leg); if (dst_leg==-1 || switch_cseqs(dlg, dst_leg) != 0 || update_cseqs(dlg,req,dst_leg,0)) LM_ERR("cseqs update failed on leg=%d\n",dst_leg); } if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){ dlg->flags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); if (replication_dests) replicate_dialog_updated(dlg); } return; }