void destroy_dlg(struct dlg_cell *dlg) { int ret = 0; LM_DBG("destroying dialog %p\n",dlg); 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 expired or not in list - 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)); } run_dlg_callbacks( DLGCB_DESTROY , dlg, 0, DLG_DIR_NONE, NULL, 0); free_dlg_dlg(dlg); }
/** * replicates the remote deletion of a dialog locally * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_delete(void) { str call_id, from_tag, to_tag; unsigned int dir, dst_leg; struct dlg_cell *dlg; int old_state, new_state, unref, ret; bin_pop_str(&call_id); bin_pop_str(&from_tag); bin_pop_str(&to_tag); 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) { LM_ERR("dialog not found (callid: |%.*s| ftag: |%.*s|\n", call_id.len, call_id.s, from_tag.len, from_tag.s); return -1; } destroy_linkers(dlg->profile_links); dlg->profile_links = NULL; next_state_dlg(dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref); 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 sucessfully removed from timer -> unref */ unref++; } unref_dlg(dlg, 1 + unref); if_update_stat(dlg_enable_stats, active_dlgs, -1); return 0; }
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); } }
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); } }
/** * 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; }
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); } }
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; }