Пример #1
0
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);
}
Пример #2
0
/**
 * 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;
}
Пример #3
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);
	}
}
Пример #4
0
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);
	}
}
Пример #5
0
/**
 * 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;
}
Пример #6
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 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);
	}
}
Пример #7
0
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;
}