Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
/*!
 * \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:
					dlg->iflags |= DLG_IFLAG_PRACK;
					break;
				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);
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
/**
 * 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;
}
Exemplo n.º 5
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;
}