/* removes expired dlgs from main ping_timer list * and links them back into a new list */ struct dlg_ping_list* get_timeout_dlgs(void) { struct dlg_ping_list *ret = NULL,*it=NULL,*next=NULL; struct dlg_cell *current; int detached; lock_get(ping_timer->lock); for (it=ping_timer->first;it;it=next) { current = it->dlg; next = it->next; detached = 0; if (current->flags & DLG_FLAG_PING_CALLER) { dlg_lock_dlg(current); if (current->legs[DLG_CALLER_LEG].reply_received == 0) { dlg_unlock_dlg(current); detach_node_unsafe(it); detached=1; if (ret == NULL) ret = it; else { it->next = ret; ret = it; } } else dlg_unlock_dlg(current); } if (detached == 0) { if (current->flags & DLG_FLAG_PING_CALLEE) { dlg_lock_dlg(current); if (current->legs[callee_idx(current)].reply_received == 0) { dlg_unlock_dlg(current); detach_node_unsafe(it); if (ret == NULL) ret = it; else { it->next = ret; ret = it; } } else dlg_unlock_dlg(current); } } } lock_release(ping_timer->lock); return ret; }
int pv_set_dlg_timeout(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) { struct dlg_cell *dlg; int timeout, db_update = 0, timer_update = 0; if (val==NULL || val->flags & PV_VAL_NULL) { LM_ERR("cannot assign dialog timeout to NULL\n"); return -1; } if (!(val->flags&PV_VAL_INT)){ /* try parsing the string */ if (str2sint(&val->rs, &timeout) < 0) { LM_ERR("assigning non-int value to dialog flags\n"); return -1; } } else { timeout = val->ri; } if (timeout < 0) { LM_ERR("cannot set a negative timeout\n"); return -1; } if ((dlg = get_current_dialog()) != NULL) { dlg_lock_dlg(dlg); dlg->lifetime = timeout; /* update now only if realtime and the dialog is confirmed */ if (dlg->state >= DLG_STATE_CONFIRMED && dlg_db_mode == DB_MODE_REALTIME) db_update = 1; else dlg->flags |= DLG_FLAG_CHANGED; if (dlg->state == DLG_STATE_CONFIRMED_NA || dlg->state == DLG_STATE_CONFIRMED) timer_update = 1; dlg_unlock_dlg(dlg); if (db_update) update_dialog_timeout_info(dlg); if (replication_dests) replicate_dialog_updated(dlg); if (timer_update && update_dlg_timer(&dlg->tl, timeout) < 0) { LM_ERR("failed to update timer\n"); return -1; } } else if (current_processing_ctx) { /* store it until we match the dialog */ ctx_timeout_set( timeout ); } else { LM_CRIT("BUG - no proicessing context found !\n"); return -1; } return 0; }
/** * fetch_dlg_value - search for @name in @dlg, write results to @out_val * * If @val_has_buf is true, @out_val may contain a user-supplied pkg buffer * which will be realloc'ed as necessary in order to hold the value. * * If @val_has_buf is false, the returned @out_val string must not be freed! * * @return: * 0 - success * -1 - error * -2 - not found */ int fetch_dlg_value(struct dlg_cell *dlg, const str *name, str *out_val, int val_has_buf) { struct dlg_val *dv; unsigned int id; str *val; LM_DBG("looking for <%.*s>\n",name->len,name->s); id = _get_name_id(name); if (!val_has_buf) { val = &val_buf; val->len = val_buf_size; } else val = out_val; /* lock dialog (if not already locked via a callback triggering)*/ if (dlg->locked_by!=process_no) dlg_lock_dlg( dlg ); /* iterate the list */ for( dv=dlg->vals ; dv ; dv=dv->next) { if (id==dv->id && name->len==dv->name.len && memcmp(name->s,dv->name.s,name->len)==0 ) { LM_DBG("var found-> <%.*s>!\n",dv->val.len,dv->val.s); /* found -> make a copy of the value under lock */ if (dv->val.len > val->len) { val->s = (char*)pkg_realloc(val->s,dv->val.len); if (val->s==NULL) { if (!val_has_buf) val_buf_size = 0; if (dlg->locked_by!=process_no) dlg_unlock_dlg( dlg ); LM_ERR("failed to do realloc for %d\n",dv->val.len); return -1; } if (!val_has_buf) val_buf_size = dv->val.len; } memcpy( val->s, dv->val.s, dv->val.len ); val->len = dv->val.len; *out_val = *val; /* unlock dialog */ if (dlg->locked_by!=process_no) dlg_unlock_dlg( dlg ); return 0; } } /* unlock dialog */ if (dlg->locked_by!=process_no) dlg_unlock_dlg( dlg ); LM_DBG("var NOT found!\n"); return -2; }
/** * replicates a locally created dialog to all the destinations * specified with the 'replicate_dialogs' modparam */ void replicate_dialog_created(struct dlg_cell *dlg) { int rc; bin_packet_t packet; dlg_lock_dlg(dlg); if (dlg->state != DLG_STATE_CONFIRMED_NA && dlg->state != DLG_STATE_CONFIRMED) { /* we don't need to replicate when in deleted state */ LM_WARN("not replicating dlg create message due to bad state %d (%.*s)\n", dlg->state, dlg->callid.len, dlg->callid.s); goto no_send; } if (dlg->replicated) { /* already created - must be a retransmission */ LM_DBG("not replicating retransmission for %p (%.*s)\n", dlg, dlg->callid.len, dlg->callid.s); goto no_send; } if (bin_init(&packet, &dlg_repl_cap, REPLICATION_DLG_CREATED, BIN_VERSION, 0) != 0) goto init_error; bin_push_dlg(&packet, dlg); dlg->replicated = 1; dlg_unlock_dlg(dlg); rc = clusterer_api.send_all(&packet, dialog_repl_cluster); switch (rc) { case CLUSTERER_CURR_DISABLED: LM_INFO("Current node is disabled in cluster: %d\n", dialog_repl_cluster); goto error; case CLUSTERER_DEST_DOWN: LM_INFO("All destinations in cluster: %d are down or probing\n", dialog_repl_cluster); goto error; case CLUSTERER_SEND_ERR: LM_ERR("Error sending in cluster: %d\n", dialog_repl_cluster); goto error; } if_update_stat(dlg_enable_stats,create_sent,1); bin_free_packet(&packet); return; error: bin_free_packet(&packet); LM_ERR("Failed to replicate created dialog\n"); return; init_error: LM_ERR("Failed to replicate created dialog\n"); no_send: dlg_unlock_dlg(dlg); return; }
int store_dlg_value(struct dlg_cell *dlg, str *name, str *val) { int ret; /* lock dialog */ dlg_lock_dlg( dlg ); ret = store_dlg_value_unsafe(dlg,name,val); /* unlock dialog */ dlg_unlock_dlg( dlg ); return ret; }
/** * replicates a local dialog update in the cluster */ void replicate_dialog_updated(struct dlg_cell *dlg) { int rc; bin_packet_t packet; dlg_lock_dlg(dlg); if (dlg->state == DLG_STATE_DELETED) { /* we no longer need to update anything */ LM_WARN("not replicating dlg update message due to bad state %d (%.*s)\n", dlg->state, dlg->callid.len, dlg->callid.s); goto end; } if (bin_init(&packet, &dlg_repl_cap, REPLICATION_DLG_UPDATED, BIN_VERSION, 0) != 0) goto init_error; bin_push_dlg(&packet, dlg); dlg->replicated = 1; dlg_unlock_dlg(dlg); rc = clusterer_api.send_all(&packet, dialog_repl_cluster); switch (rc) { case CLUSTERER_CURR_DISABLED: LM_INFO("Current node is disabled in cluster: %d\n", dialog_repl_cluster); goto error; case CLUSTERER_DEST_DOWN: LM_ERR("All destinations in cluster: %d are down or probing\n", dialog_repl_cluster); goto error; case CLUSTERER_SEND_ERR: LM_ERR("Error sending in cluster: %d\n", dialog_repl_cluster); goto error; } if_update_stat(dlg_enable_stats,update_sent,1); bin_free_packet(&packet); return; error: LM_ERR("Failed to replicate updated dialog\n"); bin_free_packet(&packet); return; init_error: LM_ERR("Failed to replicate updated dialog\n"); end: dlg_unlock_dlg(dlg); return; }
int store_dlg_value(struct dlg_cell *dlg, str *name, str *val) { int ret; /* lock dialog (if not already locked via a callback triggering)*/ if (dlg->locked_by!=process_no) dlg_lock_dlg( dlg ); ret = store_dlg_value_unsafe(dlg,name,val); /* unlock dialog */ if (dlg->locked_by!=process_no) dlg_unlock_dlg( dlg ); return ret; }
void reply_from_caller(struct cell* t, int type, struct tmcb_params* ps) { struct sip_msg *rpl; int statuscode; struct dlg_cell *dlg; if(ps == NULL || ps->rpl == NULL) { LM_ERR("Wrong tmcb params\n"); return; } if( ps->param== NULL ) { LM_ERR("Null callback parameter\n"); return; } rpl = ps->rpl; statuscode = ps->code; dlg = *(ps->param); LM_DBG("Status Code received = [%d]\n", statuscode); if (rpl == FAKED_REPLY || statuscode == 408) { /* timeout occured, nothing else to do now * next time timer fires, it will detect ping reply was not received */ LM_INFO("terminating dialog ( due to timeout ) " "with callid = [%.*s] \n",dlg->callid.len,dlg->callid.s); return; } if (statuscode == 481) { /* call/transaction does not exist * terminate the dialog */ LM_INFO("terminating dialog ( due to 481 ) " "with callid = [%.*s] \n",dlg->callid.len,dlg->callid.s); return; } dlg_lock_dlg(dlg); dlg->legs[DLG_CALLER_LEG].reply_received = 1; dlg_unlock_dlg(dlg); }
int pv_get_dlg_timeout(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { int l = 0; char *ch = NULL; struct dlg_cell *dlg; if(res==NULL) return -1; if ( (dlg=get_current_dialog())!=NULL ) { dlg_lock_dlg(dlg); if (dlg->state == DLG_STATE_DELETED) l = 0; else if (dlg->state < DLG_STATE_CONFIRMED_NA) l = dlg->lifetime; else l = dlg->tl.timeout - get_ticks(); dlg_unlock_dlg(dlg); } else if (current_processing_ctx) { if ((l=ctx_timeout_get())==0) return pv_get_null( msg, param, res); } else { return pv_get_null( msg, param, res); } res->ri = l; ch = int2str( (unsigned long)res->ri, &l); res->rs.s = ch; res->rs.len = l; res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT; return 0; }
dlg_t * build_dlg_t(struct dlg_cell * cell, int dst_leg, int src_leg) { dlg_t* td = NULL; str cseq; unsigned int loc_seq; td = (dlg_t*)pkg_malloc(sizeof(dlg_t)); if(!td){ LM_ERR("out of pkg memory\n"); return NULL; } memset(td, 0, sizeof(dlg_t)); if ((dst_leg == DLG_CALLER_LEG && (cell->flags & DLG_FLAG_PING_CALLER)) || (dst_leg == callee_idx(cell) && (cell->flags & DLG_FLAG_PING_CALLEE))) { dlg_lock_dlg(cell); if (cell->legs[dst_leg].last_gen_cseq == 0) { /* no OPTIONS pings for this dlg yet */ dlg_unlock_dlg(cell); goto before_strcseq; } else { /* OPTIONS pings sent, use new cseq */ td->loc_seq.value = ++(cell->legs[dst_leg].last_gen_cseq); td->loc_seq.is_set=1; dlg_unlock_dlg(cell); goto after_strcseq; } } before_strcseq: /*local sequence number*/ cseq = cell->legs[dst_leg].r_cseq; if( !cseq.s || !cseq.len || str2int(&cseq, &loc_seq) != 0){ LM_ERR("invalid cseq\n"); goto error; } /*we don not increase here the cseq as this will be done by TM*/ td->loc_seq.value = loc_seq; td->loc_seq.is_set = 1; after_strcseq: /*route set*/ if( cell->legs[dst_leg].route_set.s && cell->legs[dst_leg].route_set.len){ if( parse_rr_body(cell->legs[dst_leg].route_set.s, cell->legs[dst_leg].route_set.len, &td->route_set) !=0){ LM_ERR("failed to parse route set\n"); goto error; } } /*remote target--- Request URI*/ if (cell->legs[dst_leg].contact.s==0 || cell->legs[dst_leg].contact.len==0){ LM_ERR("no contact available\n"); goto error; } td->rem_target = cell->legs[dst_leg].contact; td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): *dlg_leg_to_uri(cell,dst_leg); td->loc_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_to_uri(cell,dst_leg): *dlg_leg_from_uri(cell,dst_leg); td->id.call_id = cell->callid; td->id.rem_tag = cell->legs[dst_leg].tag; td->id.loc_tag = cell->legs[src_leg].tag; td->state= DLG_CONFIRMED; td->send_sock = cell->legs[dst_leg].bind_addr; return td; error: free_tm_dlg(td); return NULL; }
static void dual_bye_event(struct dlg_cell* dlg, struct sip_msg *req, int extra_unref) { int event, old_state, new_state, unref, ret; struct dlg_cell *curr; event = DLG_EVENT_REQBYE; last_dst_leg = dlg->legs_no[DLG_LEG_200OK]; next_state_dlg(dlg, event, DLG_DIR_DOWNSTREAM, &old_state, &new_state, &unref, 0); unref += extra_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); /*destroy linkers */ dlg_lock_dlg(dlg); destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; dlg_unlock_dlg(dlg); /* 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_leg_print_info( dlg, DLG_CALLER_LEG, tag), dlg_leg_print_info( dlg, callee_idx(dlg), tag)); } else if (ret > 0) { LM_DBG("dlg already expired (not in timer list) %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 { /* successfully removed from timer list */ unref++; } curr = current_dlg_pointer; current_dlg_pointer = dlg; /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, DLG_DIR_NONE, 0); current_dlg_pointer = curr; LM_DBG("first final reply\n"); /* derefering the dialog */ unref_dlg(dlg, unref); 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 (should_remove_dlg_db()) remove_dialog_from_db(dlg); /* force delete from mem */ unref_dlg(dlg, unref); } }
/** * replicates the remote deletion of a dialog locally * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_delete(bin_packet_t *packet) { str call_id, from_tag, to_tag; unsigned int dir, dst_leg; struct dlg_cell *dlg; int old_state, new_state, unref, ret; DLG_BIN_POP(str, packet, call_id, malformed); DLG_BIN_POP(str, packet, from_tag, malformed); DLG_BIN_POP(str, packet, to_tag, malformed); LM_DBG("Deleting dialog with callid: %.*s\n", call_id.len, call_id.s); dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); if (!dlg) { /* may be already deleted due to timeout */ LM_DBG("dialog not found (callid: |%.*s| ftag: |%.*s|\n", call_id.len, call_id.s, from_tag.len, from_tag.s); return 0; } dlg_lock_dlg(dlg); destroy_linkers(dlg->profile_links, 1); dlg->profile_links = NULL; dlg_unlock_dlg(dlg); /* simulate BYE received from caller */ next_state_dlg(dlg, DLG_EVENT_REQBYE, DLG_DIR_DOWNSTREAM, &old_state, &new_state, &unref, dlg->legs_no[DLG_LEG_200OK], 0); if (old_state == new_state) { LM_ERR("duplicate dialog delete request (callid: |%.*s|" "ftag: |%.*s|\n", call_id.len, call_id.s, from_tag.len, from_tag.s); return -1; } 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 successfully removed from timer -> unref */ unref++; } unref_dlg(dlg, 1 + unref); if_update_stat(dlg_enable_stats, active_dlgs, -1); return 0; malformed: return -1; }
/** * replicates a local dialog update to all the destinations * specified with the 'replicate_dialogs' modparam */ void replicate_dialog_updated(struct dlg_cell *dlg) { struct replication_dest *d; static str module_name = str_init("dialog"); int callee_leg; str *vars, *profiles; str send_buffer; if (bin_init(&module_name, REPLICATION_DLG_UPDATED, BIN_VERSION) != 0) goto error; callee_leg = callee_idx(dlg); bin_push_str(&dlg->callid); bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag); bin_push_str(&dlg->legs[callee_leg].tag); bin_push_str(&dlg->from_uri); bin_push_str(&dlg->to_uri); bin_push_int(dlg->h_id); bin_push_int(dlg->start_ts); bin_push_int(dlg->state); bin_push_str(&dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str); if (dlg->legs[callee_leg].bind_addr) bin_push_str(&dlg->legs[callee_leg].bind_addr->sock_str); else bin_push_str(NULL); bin_push_str(&dlg->legs[DLG_CALLER_LEG].r_cseq); bin_push_str(&dlg->legs[callee_leg].r_cseq); bin_push_str(&dlg->legs[DLG_CALLER_LEG].route_set); bin_push_str(&dlg->legs[callee_leg].route_set); bin_push_str(&dlg->legs[DLG_CALLER_LEG].contact); bin_push_str(&dlg->legs[callee_leg].contact); bin_push_str(&dlg->legs[callee_leg].from_uri); bin_push_str(&dlg->legs[callee_leg].to_uri); /* XXX: on shutdown only? */ vars = write_dialog_vars(dlg->vals); dlg_lock_dlg(dlg); profiles = write_dialog_profiles(dlg->profile_links); dlg_unlock_dlg(dlg); bin_push_str(vars); bin_push_str(profiles); bin_push_int(dlg->user_flags); bin_push_int(dlg->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); bin_push_int((unsigned int)time(0) + dlg->tl.timeout - get_ticks()); bin_push_int(dlg->legs[DLG_CALLER_LEG].last_gen_cseq); bin_push_int(dlg->legs[callee_leg].last_gen_cseq); bin_get_buffer(&send_buffer); for (d = replication_dests; d; d = d->next) msg_send(0,PROTO_BIN,&d->to,0,send_buffer.s,send_buffer.len,0); if_update_stat(dlg_enable_stats,update_sent,1); return; error: LM_ERR("Failed to replicate updated dialog\n"); }
static void dual_bye_event(struct dlg_cell* dlg, struct sip_msg *req, int extra_unref) { int event, old_state, new_state, unref, ret; struct sip_msg *fake_msg=NULL; context_p old_ctx; context_p *new_ctx; event = DLG_EVENT_REQBYE; next_state_dlg(dlg, event, DLG_DIR_DOWNSTREAM, &old_state, &new_state, &unref, dlg->legs_no[DLG_LEG_200OK], 0); unref += extra_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); /*destroy linkers */ dlg_lock_dlg(dlg); destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; dlg_unlock_dlg(dlg); /* 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_leg_print_info( dlg, DLG_CALLER_LEG, tag), dlg_leg_print_info( dlg, callee_idx(dlg), tag)); } else if (ret > 0) { LM_DBG("dlg already expired (not in timer list) %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 { /* successfully removed from timer list */ unref++; } if (req==NULL) { /* set new msg & processing context */ if (push_new_processing_context( dlg, &old_ctx, &new_ctx, &fake_msg)==0) { /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, fake_msg, DLG_DIR_NONE, NULL, 0); /* reset the processing context */ if (current_processing_ctx == NULL) *new_ctx = NULL; else context_destroy(CONTEXT_GLOBAL, *new_ctx); current_processing_ctx = old_ctx; } /* no CB run in case of failure FIXME */ } else { /* we should have the msg and context from upper levels */ /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, DLG_DIR_NONE, NULL, 0); } LM_DBG("first final reply\n"); /* derefering the dialog */ unref_dlg(dlg, unref); 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 (should_remove_dlg_db()) remove_dialog_from_db(dlg); /* force delete from mem */ unref_dlg(dlg, unref); } }
/** * replicates a locally created dialog to all the destinations * specified with the 'replicate_dialogs' modparam */ void replicate_dialog_created(struct dlg_cell *dlg) { static str module_name = str_init("dialog"); int callee_leg; str *vars, *profiles; if (bin_init(&module_name, REPLICATION_DLG_CREATED, BIN_VERSION) != 0) goto error; bin_push_int(clusterer_api.get_my_id()); callee_leg = callee_idx(dlg); bin_push_str(&dlg->callid); bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag); bin_push_str(&dlg->legs[callee_leg].tag); bin_push_str(&dlg->from_uri); bin_push_str(&dlg->to_uri); bin_push_int(dlg->h_id); bin_push_int(dlg->start_ts); bin_push_int(dlg->state); bin_push_str(&dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str); if (dlg->legs[callee_leg].bind_addr) bin_push_str(&dlg->legs[callee_leg].bind_addr->sock_str); else bin_push_str(NULL); bin_push_str(&dlg->legs[DLG_CALLER_LEG].r_cseq); bin_push_str(&dlg->legs[callee_leg].r_cseq); bin_push_str(&dlg->legs[DLG_CALLER_LEG].route_set); bin_push_str(&dlg->legs[callee_leg].route_set); bin_push_str(&dlg->legs[DLG_CALLER_LEG].contact); bin_push_str(&dlg->legs[callee_leg].contact); bin_push_str(&dlg->legs[callee_leg].from_uri); bin_push_str(&dlg->legs[callee_leg].to_uri); /* XXX: on shutdown only? */ vars = write_dialog_vars(dlg->vals); dlg_lock_dlg(dlg); profiles = write_dialog_profiles(dlg->profile_links); dlg_unlock_dlg(dlg); bin_push_str(vars); bin_push_str(profiles); bin_push_int(dlg->user_flags); bin_push_int(dlg->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); bin_push_int((unsigned int)time(0) + dlg->tl.timeout - get_ticks()); bin_push_int(dlg->legs[DLG_CALLER_LEG].last_gen_cseq); bin_push_int(dlg->legs[callee_leg].last_gen_cseq); if (clusterer_api.send_to(dialog_replicate_cluster, PROTO_BIN) < 0) goto error; if_update_stat(dlg_enable_stats,create_sent,1); return; error: LM_ERR("Failed to replicate created dialog\n"); }