/** * 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 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; }