Beispiel #1
0
/**
 * receive_binary_packet (callback) - receives a cmd_type, specifying the
 * purpose of the data encoded in the received UDP packet
 */
void receive_binary_packet(int info_type)
{
	int rc;

	LM_DBG("Received a binary packet!\n");

	switch (info_type) {
	case REPLICATION_DLG_CREATED:
		rc = dlg_replicated_create(NULL, NULL, NULL, 1);
		if_update_stat(dlg_enable_stats, create_recv, 1);
		break;

	case REPLICATION_DLG_UPDATED:
		rc = dlg_replicated_update();
		if_update_stat(dlg_enable_stats, update_recv, 1);
		break;

	case REPLICATION_DLG_DELETED:
		rc = dlg_replicated_delete();
		if_update_stat(dlg_enable_stats, delete_recv, 1);
		break;

	default:
		rc = -1;
		LM_ERR("Invalid dialog binary packet command: %d\n", info_type);
	}

	if (rc != 0)
		LM_ERR("Failed to process a binary packet!\n");
}
Beispiel #2
0
static int child_init(int rank)
{
	if (rank==1) {
		if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
		if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
	}

	if ( (dlg_db_mode==DB_MODE_REALTIME &&
		(rank>=0 || rank==PROC_TIMER || rank==PROC_MODULE)) ||
	(dlg_db_mode==DB_MODE_SHUTDOWN && (rank==(dont_fork?1:PROC_MAIN) ||
		rank==PROC_MODULE) ) ||
	(dlg_db_mode==DB_MODE_DELAYED && (rank==PROC_MAIN || rank==PROC_MODULE ||
		rank==PROC_TIMER || rank>0) )){
		if ( dlg_connect_db(&db_url) ) {
			LM_ERR("failed to connect to database (rank=%d)\n",rank);
			return -1;
		}
	}

	if (cdb_url.s && cdb_url.len && init_cachedb() < 0) {
		LM_ERR("cannot init cachedb feature\n");
		return -1;
	}

	return 0;
}
Beispiel #3
0
/* When done, this function also has the job to unref the dialog as removed
 * from timer list. This must be done in all cases!!
 */
void dlg_ontimeout( struct dlg_tl *tl)
{
	struct dlg_cell *dlg;
	int new_state;
	int old_state;
	int unref;

	dlg = get_dlg_tl_payload(tl);

	LM_DBG("byeontimeout ? %d , state = %d\n",dlg->flags,dlg->state);

	if ( (dlg->flags&DLG_FLAG_BYEONTIMEOUT) &&
	(dlg->state==DLG_STATE_CONFIRMED_NA || dlg->state==DLG_STATE_CONFIRMED)) {

		init_dlg_term_reason(dlg,"Lifetime Timeout",sizeof("Lifetime Timeout")-1);

		/* we just send the BYEs in both directions */
		dlg_end_dlg( dlg, NULL);
		/* dialog is no longer refed by timer; from now one it is refed
		   by the send_bye functions */
		unref_dlg( dlg, 1);
		/* is not 100% sure, but do it */
		if_update_stat( dlg_enable_stats, expired_dlgs, 1);
		return ;
	}

	next_state_dlg( dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref);

	if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
		LM_DBG("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
			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));

		/*destroy linkers */
		destroy_linkers(dlg->profile_links);
		dlg->profile_links = NULL;

		/* dialog timeout */
		run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0);

		/* delete the dialog from DB */
		if (should_remove_dlg_db())
			remove_dialog_from_db(dlg);

		unref_dlg(dlg, unref + 1 /*timer list*/);

		if_update_stat( dlg_enable_stats, expired_dlgs, 1);
		if_update_stat( dlg_enable_stats, active_dlgs, -1);
	} else {
		unref_dlg(dlg, 1 /*just timer list*/);
	}

	return;
}
Beispiel #4
0
void receive_dlg_binary_packet(int packet_type, struct receive_info *ri, void *att)
{
	int rc;
	char *ip;
	unsigned short port;
	int server_id;

	rc = bin_pop_int(&server_id);
	if (rc < 0)
		return;

	LM_DBG("Received a binary packet!\n");

	if(get_bin_pkg_version() != BIN_VERSION){
		LM_ERR("incompatible bin protocol version\n");
		return;
	}

	if (!accept_replicated_dlg) {
		get_su_info(&ri->src_su.s, ip, port);
		LM_WARN("Unwanted dialog packet received from %s:%hu (type=%d)\n",
				ip, port, packet_type);
		return;
	}

	if(!clusterer_api.check(accept_replicated_dlg, &ri->src_su, server_id, ri->proto))
		return;

	switch (packet_type) {
	case REPLICATION_DLG_CREATED:
		LM_DBG("AAAA dlg_replicated_create\n");
		rc = dlg_replicated_create(NULL, NULL, NULL, 1);
		if_update_stat(dlg_enable_stats, create_recv, 1);
		break;

	case REPLICATION_DLG_UPDATED:
		LM_DBG("AAAA dlg_replicated_update\n");
		rc = dlg_replicated_update();
		if_update_stat(dlg_enable_stats, update_recv, 1);
		break;

	case REPLICATION_DLG_DELETED:
		LM_DBG("AAAA dlg_replicated_deleted\n");
		rc = dlg_replicated_delete();
		if_update_stat(dlg_enable_stats, delete_recv, 1);
		break;

	default:
		rc = -1;
		get_su_info(&ri->src_su.s, ip, port);
		LM_WARN("Invalid dialog binary packet command: %d (from %s:%hu)\n",
			packet_type, ip, port);
	}

	if (rc != 0)
		LM_ERR("Failed to process a binary packet!\n");
}
Beispiel #5
0
static int child_init(int rank)
{
	dlg_db_mode = dlg_db_mode_param;

	if(rank==PROC_MAIN) {
		if(dlg_timer_procs>0) {
			if(fork_sync_timer(PROC_TIMER, "Dialog Main Timer", 1 /*socks flag*/,
					dlg_timer_routine, NULL, 1 /*every sec*/)<0) {
				LM_ERR("failed to start main timer routine as process\n");
				return -1; /* error */
			}
		}

		if(dlg_ka_timer>0 && dlg_ka_interval>0) {
			if(fork_sync_timer(PROC_TIMER, "Dialog KA Timer", 1 /*socks flag*/,
					dlg_ka_timer_exec, NULL, dlg_ka_timer /*sec*/)<0) {
				LM_ERR("failed to start ka timer routine as process\n");
				return -1; /* error */
			}
		}

		if(fork_sync_timer(PROC_TIMER, "Dialog Clean Timer", 1 /*socks flag*/,
					dlg_clean_timer_exec, NULL, dlg_clean_timer /*sec*/)<0) {
			LM_ERR("failed to start clean timer routine as process\n");
			return -1; /* error */
		}
	}

	if (rank==1) {
		if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
		if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
	}

	if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
	(rank>0 || rank==PROC_TIMER)) ||
	(dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
		if ( dlg_connect_db(&db_url) ) {
			LM_ERR("failed to connect to database (rank=%d)\n",rank);
			return -1;
		}
	}

	/* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
	 * for the rest of the processes will be the same as DB_MODE_NONE */
	if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
		dlg_db_mode = DB_MODE_NONE;
	/* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
	if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
			rank==PROC_MAIN)
		dlg_db_mode = DB_MODE_NONE;

	return 0;
}
/**
 * receive_binary_packet (callback) - receives a cmd_type, specifying the
 * purpose of the data encoded in the received UDP packet
 */
void receive_binary_packet(int packet_type, struct receive_info *ri)
{
	int rc;
	char *ip;
	unsigned short port;

	LM_DBG("Received a binary packet!\n");

	if(get_bin_pkg_version() != BIN_VERSION){
		LM_ERR("incompatible bin protocol version\n");
		return;
	}

	if (accept_repl_profiles && packet_type == REPLICATION_DLG_PROFILE) {
		/* TODO: handle this */
		dlg_replicated_profiles(ri);
		return;
	}
	if (!accept_replicated_dlg) {
		get_su_info(&ri->src_su.s, ip, port);
		LM_WARN("Unwanted dialog packet received from %s:%hu (type=%d)\n",
				ip, port, packet_type);
		return;
	}


	switch (packet_type) {
	case REPLICATION_DLG_CREATED:
		rc = dlg_replicated_create(NULL, NULL, NULL, 1);
		if_update_stat(dlg_enable_stats, create_recv, 1);
		break;

	case REPLICATION_DLG_UPDATED:
		rc = dlg_replicated_update();
		if_update_stat(dlg_enable_stats, update_recv, 1);
		break;

	case REPLICATION_DLG_DELETED:
		rc = dlg_replicated_delete();
		if_update_stat(dlg_enable_stats, delete_recv, 1);
		break;

	default:
		rc = -1;
		get_su_info(&ri->src_su.s, ip, port);
		LM_WARN("Invalid dialog binary packet command: %d (from %s:%hu)\n",
				packet_type, ip, port);
	}

	if (rc != 0)
		LM_ERR("Failed to process a binary packet!\n");
}
Beispiel #7
0
/**
 * replicates a local dialog delete event to all the destinations
 * specified with the 'replicate_dialogs' modparam
 */
void replicate_dialog_deleted(struct dlg_cell *dlg)
{
	int rc;
	bin_packet_t packet;

	if (bin_init(&packet, &dlg_repl_cap, REPLICATION_DLG_DELETED, BIN_VERSION, 1024) != 0)
		goto error;

	bin_push_str(&packet, &dlg->callid);
	bin_push_str(&packet, &dlg->legs[DLG_CALLER_LEG].tag);
	bin_push_str(&packet, &dlg->legs[callee_idx(dlg)].tag);

	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_free;
	case CLUSTERER_DEST_DOWN:
		LM_ERR("All destinations in cluster: %d are down or probing\n",
			dialog_repl_cluster);
		goto error_free;
	case CLUSTERER_SEND_ERR:
		LM_ERR("Error sending in cluster: %d\n", dialog_repl_cluster);
		goto error_free;
	}

	if_update_stat(dlg_enable_stats, delete_sent, 1);
	bin_free_packet(&packet);
	return;
error_free:
	bin_free_packet(&packet);
error:
	LM_ERR("Failed to replicate deleted dialog\n");
}
Beispiel #8
0
/**
 * 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;

	if (bin_init(&module_name, REPLICATION_DLG_UPDATED) != 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);
	profiles = write_dialog_profiles(dlg->profile_links);

	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);

	for (d = replication_dests; d; d = d->next)
		bin_send(&d->to);

	if_update_stat(dlg_enable_stats,update_sent,1);
	return;

error:
	LM_ERR("Failed to replicate updated dialog\n");
}
/**
 * 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;
}
Beispiel #10
0
/**
 * 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;
}
Beispiel #11
0
void receive_dlg_repl(bin_packet_t *packet)
{
	int rc = 0;
	bin_packet_t *pkt;

	for (pkt = packet; pkt; pkt = pkt->next) {
		switch (pkt->type) {
		case REPLICATION_DLG_CREATED:
			rc = dlg_replicated_create(pkt, NULL, NULL, NULL, 1);
			if_update_stat(dlg_enable_stats, create_recv, 1);
			break;
		case REPLICATION_DLG_UPDATED:
			rc = dlg_replicated_update(pkt);
			if_update_stat(dlg_enable_stats, update_recv, 1);
			break;
		case REPLICATION_DLG_DELETED:
			rc = dlg_replicated_delete(pkt);
			if_update_stat(dlg_enable_stats, delete_recv, 1);
			break;
		case DLG_SHARING_TAG_ACTIVE:
			rc = receive_shtag_active_msg(pkt);
			break;
		case SYNC_PACKET_TYPE:
			while (clusterer_api.sync_chunk_iter(pkt))
				if (dlg_replicated_create(pkt, NULL, NULL, NULL, 1) < 0) {
					LM_ERR("Failed to process sync packet\n");
					return;
				}
			break;
		default:
			rc = -1;
			LM_WARN("Invalid dialog binary packet command: %d "
				"(from node: %d in cluster: %d)\n", pkt->type, pkt->src_id,
				dialog_repl_cluster);
		}

		if (rc != 0)
			LM_ERR("Failed to process a binary packet!\n");
	}
}
Beispiel #12
0
/**
 * 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;
}
Beispiel #13
0
/*!
 * \brief Remove contact in memory from the list and delete it
 * \param _r record this contact belongs to
 * \param _c deleted contact
 */
void mem_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
    
    struct contact_dialog_data *dialog_data;
    //tear down dialogs in dialog data list
    for (dialog_data = _c->first_dialog_data; dialog_data;) {
        dlgb.lookup_terminate_dlg(dialog_data->h_entry, dialog_data->h_id, NULL );
        dialog_data = dialog_data->next;
    }
    
    mem_remove_ucontact(_r, _c);
    if_update_stat(_r->slot, _r->slot->d->contacts, -1);
    free_ucontact(_c);
}
Beispiel #14
0
/**
 * replicates a local dialog delete event to all the destinations
 * specified with the 'replicate_dialogs' modparam
 */
void replicate_dialog_deleted(struct dlg_cell *dlg)
{
	struct replication_dest *d;
	static str module_name = str_init("dialog");

	if (bin_init(&module_name, REPLICATION_DLG_DELETED) != 0)
		goto error;

	bin_push_str(&dlg->callid);
	bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag);
	bin_push_str(&dlg->legs[callee_idx(dlg)].tag);

	for (d = replication_dests; d; d = d->next)
		bin_send(&d->to);

	if_update_stat(dlg_enable_stats,delete_sent,1);
	return;
error:
	LM_ERR("Failed to replicate deleted dialog\n");
}
Beispiel #15
0
/*!
 * \brief Add a new contact in memory
 *
 * Add a new contact in memory, contacts are ordered by:
 * 1) q value, 2) descending modification time
 * \param _r record this contact belongs to
 * \param _c contact
 * \param _ci contact information
 * \return pointer to new created contact on success, 0 on failure
 */
ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci)
{
	ucontact_t* ptr, *prev = 0;
	ucontact_t* c;

	if ( (c=new_ucontact(_r->domain, &_r->aor, _c, _ci)) == 0) {
		LM_ERR("failed to create new contact\n");
		return 0;
	}
	if_update_stat( _r->slot, _r->slot->d->contacts, 1);

	ptr = _r->contacts;

	if (!desc_time_order) {
		while(ptr) {
			if (ptr->q < c->q) break;
			prev = ptr;
			ptr = ptr->next;
		}
	}

	if (ptr) {
		if (!ptr->prev) {
			ptr->prev = c;
			c->next = ptr;
			_r->contacts = c;
		} else {
			c->next = ptr;
			c->prev = ptr->prev;
			ptr->prev->next = c;
			ptr->prev = c;
		}
	} else if (prev) {
		prev->next = c;
		c->prev = prev;
	} else {
		_r->contacts = c;
	}

	return c;
}
Beispiel #16
0
/* Returns:
    0  : ACK to a local reply
    -1 : error
    1  : is not an ACK  or a non-local ACK
*/
int sl_filter_ACK(struct sip_msg *msg, void *bar )
{
	str *tag_str;

	if (msg->first_line.u.request.method_value!=METHOD_ACK)
		goto pass_it;

	/*check the timeout value*/
	if ( *(sl_timeout)<= get_ticks() )
	{
		LM_DBG("to late to be a local ACK!\n");
		goto pass_it;
	}

	/*force to parse to header -> we need it for tag param*/
	if (parse_headers( msg, HDR_TO_F, 0 )==-1)
	{
		LM_ERR("unable to parse To header\n");
		return -1;
	}

	if (msg->to) {
		tag_str = &(get_to(msg)->tag_value);
		if ( tag_str->len==TOTAG_VALUE_LEN )
		{
			/* calculate the variable part of to-tag */	
			calc_crc_suffix(msg, tag_suffix);
			/* test whether to-tag equal now */
			if (memcmp(tag_str->s,sl_tag.s,sl_tag.len)==0) {
				LM_DBG("local ACK found -> dropping it!\n");
				if_update_stat( sl_enable_stats, rcv_acks, 1);
				run_sl_callbacks( SLCB_ACK_IN, msg, 0, 0, 0, 0 );
				return 0;
			}
		}
	}

pass_it:
	return 1;
}
Beispiel #17
0
/*!
 * \brief Add a new contact in memory
 *
 * Add a new contact in memory, contacts are ordered by:
 * 1) q value, 2) descending modification time
 * \param _r record this contact belongs to
 * \param _c contact
 * \param _ci contact information
 * \return pointer to new created contact on success, 0 on failure
 */
ucontact_t* mem_insert_ucontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci) {
    ucontact_t* ptr, *prev = 0;
    ucontact_t* c;

    if ((c = new_ucontact(_r->domain, &_r->public_identity, _c, _ci)) == 0) {
        LM_ERR("failed to create new contact\n");
        return 0;
    }
    if_update_stat(_r->slot, _r->slot->d->contacts, 1);

    ptr = _r->contacts;

    while (ptr) {//make sure our contacts are ordered oldest(first) to newest(last)
        if (ptr->expires > c->expires)
            break;
        prev = ptr;
        ptr = ptr->next;
    }

    if (ptr) {
        if (!ptr->prev) {
            ptr->prev = c;
            c->next = ptr;
            _r->contacts = c;
        } else {
            c->next = ptr;
            c->prev = ptr->prev;
            ptr->prev->next = c;
            ptr->prev = c;
        }
    } else if (prev) {
        prev->next = c;
        c->prev = prev;
    } else {
        _r->contacts = c;
    }

    return c;
}
/**
 * replicates a local dialog delete event to all the destinations
 * specified with the 'replicate_dialogs' modparam
 */
void replicate_dialog_deleted(struct dlg_cell *dlg)
{
	struct replication_dest *d;
	static str module_name = str_init("dialog");
	str send_buffer;

	if (bin_init(&module_name, REPLICATION_DLG_DELETED, BIN_VERSION) != 0)
		goto error;

	bin_push_str(&dlg->callid);
	bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag);
	bin_push_str(&dlg->legs[callee_idx(dlg)].tag);

	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,delete_sent,1);
	return;
error:
	LM_ERR("Failed to replicate deleted dialog\n");
}
Beispiel #19
0
int sl_reply_error(struct sip_msg *msg )
{
	char err_buf[MAX_REASON_LEN];
	int sip_error;
	str text;
	int ret;

	ret = err2reason_phrase( prev_ser_error, &sip_error, 
		err_buf, sizeof(err_buf), "SL");
	if (ret<=0) {
		LM_ERR("err2reason failed\n");
		return -1;
	}
	text.len = ret;
	text.s = err_buf;
	LM_DBG("error text is %.*s\n",text.len,text.s);

	ret = sl_send_reply_helper( msg, sip_error, &text);
	if (ret==-1)
		return -1;
	if_update_stat( sl_enable_stats, sent_err_rpls , 1);
	return ret;
}
Beispiel #20
0
/*!
 * \brief Function that is registered as TM callback and called on replies
 *
 * Function that is registered as TM callback and called on replies. It
 * parses the reply and set the appropriate event. This is then used to
 * update the dialog state, run eventual dialog callbacks and save or
 * update the necessary informations about the dialog.
 * \see next_state_dlg
 * \param t transaction, unused
 * \param type type of the entered callback
 * \param param saved dialog structure in the callback
 */
static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
{
    dlg_cell_t *dlg = NULL;
	dlg_iuid_t *iuid = NULL;
    int new_state, old_state, unref, event;
    str tag;
    sip_msg_t *req = param->req;
	sip_msg_t *rpl = param->rpl;

	if (shutdown_done)
		return;
	iuid = (dlg_iuid_t*)(*param->param);
	dlg = dlg_get_by_iuid(iuid);
	if(dlg==0)
		return;

	unref = 0;
	if (type & (TMCB_RESPONSE_IN|TMCB_ON_FAILURE)) {
		/* Set the dialog context so it is available in onreply_route and failure_route*/
		set_current_dialog(req, dlg);
		dlg_set_ctx_iuid(dlg);
		goto done;
	}

	if (type==TMCB_RESPONSE_FWDED) {
		/* The state does not change, but the msg is mutable in this callback*/
		run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
		goto done;
	}

	if (type==TMCB_DESTROY)
		event = DLG_EVENT_TDEL;
	else if (param->code<200)
		event = DLG_EVENT_RPL1xx;
	else if (param->code<300)
		event = DLG_EVENT_RPL2xx;
	else
		event = DLG_EVENT_RPL3xx;

	next_state_dlg( dlg, event, &old_state, &new_state, &unref);
	dlg_run_event_route(dlg, (rpl==FAKED_REPLY)?NULL:rpl, old_state, new_state);

	if (new_state==DLG_STATE_EARLY) {
		run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
		if (old_state!=DLG_STATE_EARLY)
			if_update_stat(dlg_enable_stats, early_dlgs, 1);
		goto done;
	}

	if (new_state==DLG_STATE_CONFIRMED_NA &&
	old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) {
		LM_DBG("dialog %p confirmed (ACK pending)\n",dlg);

		 if (rpl != FAKED_REPLY) {
			/* get to tag*/
			if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0)
						|| !rpl->to) ) {
				LM_ERR("bad reply or missing TO hdr :-/\n");
				tag.s = 0;
				tag.len = 0;
			} else {
				tag = get_to(rpl)->tag_value;
				if (tag.s==0 || tag.len==0) {
					LM_ERR("missing TAG param in TO hdr :-/\n");
					tag.s = 0;
					tag.len = 0;
				}
			}

			/* save callee's tag, cseq, contact and record route*/
			if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) {
				LM_ERR("could not add further info to the dialog\n");
			}
		 } else {
			 LM_ERR("Faked reply!\n");
		 }

		/* set start time */
		dlg->start_ts = (unsigned int)(time(0));

		/* save the settings to the database,
		 * if realtime saving mode configured- save dialog now
		 * else: the next time the timer will fire the update*/
		dlg->dflags |= DLG_FLAG_NEW;
		if ( dlg_db_mode==DB_MODE_REALTIME )
			update_dialog_dbinfo(dlg);

		if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) {
			LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] "
				"with clid '%.*s' and tags '%.*s' '%.*s'\n",
				dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state,
				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);
		} else {
			/* dialog pointer inserted in timer list */
			dlg_ref(dlg, 1);
		}

		/* dialog confirmed (ACK pending) */
		run_dlg_callbacks( DLGCB_CONFIRMED_NA, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);

		if (old_state==DLG_STATE_EARLY)
			if_update_stat(dlg_enable_stats, early_dlgs, -1);

		if (unref) dlg_unref(dlg, unref);
		if_update_stat(dlg_enable_stats, active_dlgs, 1);
		goto done;
	}

	if ( new_state==DLG_STATE_DELETED
				&& (old_state==DLG_STATE_UNCONFIRMED
					|| old_state==DLG_STATE_EARLY) ) {
		LM_DBG("dialog %p failed (negative reply)\n", dlg);
		/* dialog setup not completed (3456XX) */
		run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
		if(dlg_wait_ack==1)
			dlg_set_tm_waitack(t, dlg);
		/* do unref */
		if (unref)
			dlg_unref(dlg, unref);
		if (old_state==DLG_STATE_EARLY)
			if_update_stat(dlg_enable_stats, early_dlgs, -1);

		if_update_stat(dlg_enable_stats, failed_dlgs, 1);

		goto done;
	}

	if (unref) dlg_unref(dlg, unref);

done:
	/* unref due to dlg_get_by_iuid() */
	dlg_release(dlg);
	return;
}
Beispiel #21
0
/*!
 * \brief Timer function that removes expired dialogs, run timeout route
 * \param tl dialog timer list
 */
void dlg_ontimeout(struct dlg_tl *tl)
{
	dlg_cell_t *dlg;
	int new_state, old_state, unref;
	sip_msg_t *fmsg;
	void* timeout_cb = 0;

	/* get the dialog tl payload */
	dlg = ((struct dlg_cell*)((char *)(tl) -
			(unsigned long)(&((struct dlg_cell*)0)->tl)));

	/* mark dialog as expired */
	dlg->dflags |= DLG_FLAG_EXPIRED;

	if(dlg->state==DLG_STATE_CONFIRMED_NA
				|| dlg->state==DLG_STATE_CONFIRMED)
	{
		if(dlg->toroute>0 && dlg->toroute<main_rt.entries
			&& main_rt.rlist[dlg->toroute]!=NULL)
		{
			fmsg = faked_msg_next();
			if (exec_pre_script_cb(fmsg, REQUEST_CB_TYPE)>0)
			{
				dlg_ref(dlg, 1);
				dlg_set_ctx_iuid(dlg);
				LM_DBG("executing route %d on timeout\n", dlg->toroute);
				set_route_type(REQUEST_ROUTE);
				run_top_route(main_rt.rlist[dlg->toroute], fmsg, 0);
				dlg_reset_ctx_iuid();
				exec_post_script_cb(fmsg, REQUEST_CB_TYPE);
				dlg_unref(dlg, 1);
			}
		}

		if(dlg->iflags&DLG_IFLAG_TIMEOUTBYE)
		{
			/* set the dialog context so that it's available in
			 * tm:local-request event route */
			dlg_set_ctx_iuid(dlg);
			if(dlg_bye_all(dlg, NULL)<0)
				dlg_unref(dlg, 1);
			dlg_reset_ctx_iuid();	

			dlg_unref(dlg, 1);
			if_update_stat(dlg_enable_stats, expired_dlgs, 1);
			return;
		}
	}

	next_state_dlg( dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref);
    /* used for computing duration for timed out acknowledged dialog */
	if (DLG_STATE_CONFIRMED == old_state) {
		timeout_cb = (void *)CONFIRMED_DIALOG_STATE;
	}	

	dlg_run_event_route(dlg, NULL, old_state, new_state);

	if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
		LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
			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);

		/* dialog timeout */
		run_dlg_callbacks( DLGCB_EXPIRED, dlg, NULL, NULL, DLG_DIR_NONE, timeout_cb);

		dlg_unref(dlg, unref+1);

		if_update_stat( dlg_enable_stats, expired_dlgs, 1);
		if_update_stat( dlg_enable_stats, active_dlgs, -1);
	} else {
		dlg_unref(dlg, 1);
	}

	return;
}
Beispiel #22
0
/*!
 * \brief Function that is registered as RR callback for dialog tracking
 * 
 * Function that is registered as RR callback for dialog tracking. It
 * sets the appropriate events after the SIP method and run the state
 * machine to update the dialog state. It updates then the saved
 * dialogs and also the statistics.
 * \param req SIP request
 * \param route_params record-route parameter
 * \param param unused
 */
void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
{
	dlg_cell_t *dlg;
	dlg_iuid_t *iuid;
	str val, callid, ftag, ttag;
	int h_entry, h_id, new_state, old_state, unref, event, timeout, reset;
	unsigned int dir;
	int ret = 0;

	dlg = dlg_get_ctx_dialog();
	if (dlg!=NULL) {
		dlg_release(dlg);
		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;

	if ( seq_match_mode!=SEQ_MATCH_NO_ID ) {
		if( 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 = dlg_lookup(h_entry, h_id);
			if (dlg==0) {
				LM_WARN("unable to find dialog for %.*s "
					"with route param '%.*s' [%u:%u]\n",
					req->first_line.u.request.method.len,
					req->first_line.u.request.method.s,
					val.len,val.s, h_entry, h_id);
				if (seq_match_mode==SEQ_MATCH_STRICT_ID )
					return;
			} else {
				if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) {
					// lookup_dlg has incremented the ref count by 1
					dlg_release(dlg);
					return;
				}
				if (match_dialog( dlg, &callid, &ftag, &ttag, &dir )==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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
							dlg->tag[DLG_CALLER_LEG].len,
							dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s,
							dlg->tag[DLG_CALLEE_LEG].len);
					// lookup_dlg has incremented the ref count by 1
					dlg_release(dlg);

					// Reset variables in order to do a lookup based on SIP-Elements.
					dlg = 0;
					dir = DLG_DIR_NONE;

					if (seq_match_mode==SEQ_MATCH_STRICT_ID )
						return;
				}
			}
		}
	}

	if (dlg==0) {
		if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0)
			return;
		/* TODO - try to use the RR dir detection to speed up here the
		 * search -bogdan */
		dlg = get_dlg(&callid, &ftag, &ttag, &dir);
		if (dlg==0){
			LM_DBG("Callid '%.*s' not found\n",
				req->callid->body.len, req->callid->body.s);
			return;
		}
	}

    /* set current dialog - re-use ref increment from dlg_get() above */
    set_current_dialog( req, dlg);
    _dlg_ctx.iuid.h_entry = dlg->h_entry;
    _dlg_ctx.iuid.h_id = dlg->h_id;

	if (req->first_line.u.request.method_value != METHOD_ACK) {
		iuid = dlg_get_iuid_shm_clone(dlg);
		if(iuid!=NULL)
		{
			/* register callback for the replies of this request */
			if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_IN|TMCB_ON_FAILURE,
					dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) {
				LM_ERR("failed to register TMCB (3)\n");
				shm_free(iuid);
			}
			iuid = NULL;
		}
	}
	
	/* 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;
	}

	next_state_dlg( dlg, event, &old_state, &new_state, &unref);

	CURR_DLG_ID = req->id;
	CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
	CURR_DLG_STATUS = new_state;

	dlg_run_event_route(dlg, req, old_state, new_state);

	/* delay deletion of dialog until transaction has died off in order
	 * to absorb in-air messages */
	if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
		iuid = dlg_get_iuid_shm_clone(dlg);
		if(iuid!=NULL) {
			if ( d_tmb.register_tmcb(req, NULL, TMCB_DESTROY,
					unref_dlg_from_cb, (void*)iuid, dlg_iuid_sfree)<0 ) {
				LM_ERR("failed to register deletion delay function\n");
				shm_free(iuid);
			} else {
				dlg_ref(dlg, 1);
			}
		}
	}

	if (new_state==DLG_STATE_CONFIRMED && old_state!=DLG_STATE_CONFIRMED)
		dlg_ka_add(dlg);

	/* run actions for the transition */
	if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED &&
	old_state!=DLG_STATE_DELETED) {
		LM_DBG("BYE successfully processed\n");
		/* remove from timer */
		ret = remove_dialog_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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
		} else if (ret > 0) {
			LM_WARN("inconsitent dlg timer data 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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
		} else {
			/* one extra unref due to removal from timer list */
			unref++;
		}
		/* dialog terminated (BYE) */
        dlg_terminated( req, dlg, dir);

		dlg_unref(dlg, unref);

		_dlg_ctx.cpid = my_pid();
		_dlg_ctx.expect_t = 1;
		dlg_set_ctx_iuid(dlg);

		if_update_stat( dlg_enable_stats, active_dlgs, -1);
		goto done;
	}

	if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK)
	&& (new_state==DLG_STATE_CONFIRMED || new_state==DLG_STATE_EARLY)) {

		timeout = get_dlg_timeout(req);
		if (timeout!=default_timeout) {
			dlg->lifetime = timeout;
		}
		reset = !((dlg->iflags & DLG_IFLAG_TIMER_NORESET) || dlg_timeout_noreset);

		if ((new_state!=DLG_STATE_EARLY) && (old_state!=DLG_STATE_CONFIRMED || reset)) {
			if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) {
				LM_ERR("failed to update dialog lifetime\n");
			} else {
				dlg->dflags |= DLG_FLAG_CHANGED;
			}
		}
		if(event != DLG_EVENT_REQACK) {
			if(dlg_refresh_contacts(dlg, req, dir)!=0) {
				LM_ERR("contacts update failed\n");
			} else {
				dlg->dflags |= DLG_FLAG_CHANGED;
			}
			if(update_cseqs(dlg, req, dir)!=0) {
				LM_ERR("cseqs update failed\n");
			} else {
				dlg->dflags |= DLG_FLAG_CHANGED;
			}
		}
		if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) {
			update_dialog_dbinfo(dlg);
		}

		if (old_state==DLG_STATE_CONFIRMED_NA) {
			LM_DBG("confirming ACK successfully processed\n");

			/* confirming ACK request */
			run_dlg_callbacks( DLGCB_CONFIRMED, dlg, req, NULL, dir, 0);
		} else {
			LM_DBG("sequential request successfully processed\n");

			/* within dialog request */
			run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0);

			if ( (event!=DLG_EVENT_REQACK) &&
					(dlg->cbs.types)&DLGCB_RESPONSE_WITHIN ) {
				iuid = dlg_get_iuid_shm_clone(dlg);
				if(iuid!=NULL)
				{
					/* register callback for the replies of this request */
					if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
							(dir==DLG_DIR_UPSTREAM)?dlg_seq_down_onreply:
														dlg_seq_up_onreply,
							(void*)iuid, dlg_iuid_sfree)<0 ) {
						LM_ERR("failed to register TMCB (2)\n");
						shm_free(iuid);
					}
				}
			}
		}
	}

	if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){
		dlg->dflags |= DLG_FLAG_CHANGED;
		if(dlg_db_mode == DB_MODE_REALTIME)
			update_dialog_dbinfo(dlg);
	}

done:
	dlg_release(dlg);
	return;
}
Beispiel #23
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;
}
Beispiel #24
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;
}
Beispiel #25
0
/**
 * replicates a confirmed dialog from another OpenSIPS instance
 * by reading the relevant information using the Binary Packet Interface
 */
int dlg_replicated_create(bin_packet_t *packet, struct dlg_cell *cell, str *ftag,
							str *ttag, int safe)
{
	int h_entry;
	unsigned int dir, dst_leg;
	str callid = { NULL, 0 }, 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;

	LM_DBG("Received replicated dialog!\n");
	if (!cell) {
		DLG_BIN_POP(str, packet, callid, malformed);
		DLG_BIN_POP(str, packet, from_tag, malformed);
		DLG_BIN_POP(str, packet, to_tag, malformed);
		DLG_BIN_POP(str, packet, from_uri, malformed);
		DLG_BIN_POP(str, packet, to_uri, malformed);

		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);
			/* unmark dlg as loaded from DB (otherwise it would have been
			 * dropped later when syncing from cluster is done) */
			dlg->flags &= ~DLG_FLAG_FROM_DB;
			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;
	}
	if_update_stat(dlg_enable_stats, processed_dlgs, 1);

	DLG_BIN_POP(int, packet, dlg->h_id, pre_linking_error);
	DLG_BIN_POP(int, packet, dlg->start_ts, pre_linking_error);
	DLG_BIN_POP(int, packet, dlg->state, pre_linking_error);

	/* next_id follows the max value of all replicated ids */
	if (d_table->entries[dlg->h_entry].next_id <= dlg->h_id)
		d_table->entries[dlg->h_entry].next_id = dlg->h_id + 1;

	DLG_BIN_POP(str, packet, sock, pre_linking_error);

	caller_sock = fetch_socket_info(&sock);

	DLG_BIN_POP(str, packet, sock, pre_linking_error);

	callee_sock = fetch_socket_info(&sock);

	if (!caller_sock || !callee_sock) {
		LM_ERR("Replicated dialog doesn't match any listening sockets\n");
		goto pre_linking_error;
	}

	DLG_BIN_POP(str, packet, cseq1, pre_linking_error);
	DLG_BIN_POP(str, packet, cseq2, pre_linking_error);
	DLG_BIN_POP(str, packet, rroute1, pre_linking_error);
	DLG_BIN_POP(str, packet, rroute2, pre_linking_error);
	DLG_BIN_POP(str, packet, contact1, pre_linking_error);
	DLG_BIN_POP(str, packet, contact2, pre_linking_error);
	DLG_BIN_POP(str, packet, mangled_fu, pre_linking_error);
	DLG_BIN_POP(str, packet, mangled_tu, pre_linking_error);

	/* add the 2 legs */
	/* TODO - sdp here */
	if (dlg_update_leg_info(0, dlg, &from_tag, &rroute1, &contact1,
		&cseq1, caller_sock, 0, 0,0) != 0 ||
		dlg_update_leg_info(1, dlg, &to_tag, &rroute2, &contact2,
		&cseq2, callee_sock, &mangled_fu, &mangled_tu,0) != 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 */
	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++;

	DLG_BIN_POP(str, packet, vars, pre_linking_error);
	DLG_BIN_POP(str, packet, profiles, pre_linking_error);
	DLG_BIN_POP(int, packet, dlg->user_flags, pre_linking_error);
	DLG_BIN_POP(int, packet, dlg->mod_flags, pre_linking_error);

	DLG_BIN_POP(int, packet, dlg->flags, pre_linking_error);
	/* also save the dialog into the DB on this instance */
	dlg->flags |= DLG_FLAG_NEW;

	DLG_BIN_POP(int, packet, dlg->tl.timeout, pre_linking_error);
	DLG_BIN_POP(int, packet, dlg->legs[DLG_CALLER_LEG].last_gen_cseq, pre_linking_error);
	DLG_BIN_POP(int, packet, dlg->legs[callee_idx(dlg)].last_gen_cseq, pre_linking_error);

	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;

	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);

malformed:
	return -1;
}
Beispiel #26
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);
	}
}
Beispiel #27
0
/* callback function to handle responses to the BYE request */
void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps){

	struct dlg_cell* dlg;
	int event, old_state, new_state, unref, ret;
	dlg_iuid_t *iuid = NULL;

	if(ps->param == NULL || *ps->param == NULL){
		LM_ERR("invalid parameter\n");
		return;
	}

	if(ps->code < 200){
		LM_DBG("receiving a provisional reply\n");
		return;
	}

	LM_DBG("receiving a final reply %d\n",ps->code);

	iuid = (dlg_iuid_t*)(*ps->param);
	dlg = dlg_get_by_iuid(iuid);
	if(dlg==0)
		return;

	event = DLG_EVENT_REQBYE;
	next_state_dlg(dlg, event, &old_state, &new_state, &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);

		/* remove from timer */
		ret = remove_dialog_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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
		} else if (ret > 0) {
			LM_WARN("inconsitent dlg timer data 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->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
		} else {
			unref++;
		}
		/* dialog terminated (BYE) */
		run_dlg_callbacks( DLGCB_TERMINATED, dlg, ps->req, ps->rpl, DLG_DIR_NONE, 0);

		LM_DBG("first final reply\n");
		/* derefering the dialog */
		dlg_unref(dlg, unref+1);

		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 (dlg_db_mode)
			remove_dialog_from_db(dlg);
		/* force delete from mem */
		dlg_unref(dlg, 1);
	}
	dlg_iuid_sfree(iuid);
}
Beispiel #28
0
/*!
 * \brief Create a new dialog from a sip message
 *
 * Create a new dialog from a SIP message, register a callback
 * to keep track of the dialog with help of the tm module.
 * This function is either called from the request callback, or
 * from the dlg_manage function in the configuration script.
 * \see dlg_onreq
 * \see w_dlg_manage
 * \param req SIP message
 * \param t transaction
 * \param run_initial_cbs if set zero, initial callbacks are not executed
 * \return 0 on success, -1 on failure
 */ 
int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
{
	dlg_cell_t *dlg;
	str s;
	str callid;
    str ftag;
    str ttag;
    str req_uri;
    unsigned int dir;

	dlg = dlg_get_ctx_dialog();
    if(dlg != NULL) {
		dlg_release(dlg);
        return -1;
	}

	if(req->first_line.u.request.method_value != METHOD_INVITE)
		return -1;

    if(pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
        LM_WARN("pre-matching failed\n");
        return -1;
    }

    if(ttag.s!=0 && ttag.len!=0)
        return -1;

    if(pv_printf_s(req, ruri_param_model, &req_uri)<0) {
        LM_ERR("error - cannot print the r-uri format\n");
        return -1;
    }
    trim(&req_uri);

	dir = DLG_DIR_NONE;
	/* search dialog by SIP attributes
	 * - hash table slot is left locked  */
	dlg = dlg_search(&callid, &ftag, &ttag, &dir);
	if(dlg) {
		if (detect_spirals) {
			if (spiral_detected == 1) {
				dlg_hash_release(&callid);
				return 0;
			}

			if ( dlg->state != DLG_STATE_DELETED ) {
				LM_DBG("Callid '%.*s' found, must be a spiraled request\n",
					callid.len, callid.s);
				spiral_detected = 1;

				if (run_initial_cbs)
					run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, NULL,
							DLG_DIR_DOWNSTREAM, 0);
				/* set ctx dlg id shortcuts */
				_dlg_ctx.iuid.h_entry = dlg->h_entry;
				_dlg_ctx.iuid.h_id = dlg->h_id;
				/* search_dlg() has incremented the ref count by 1 */
				dlg_release(dlg);
				dlg_hash_release(&callid);
				return 0;
			}
			dlg_release(dlg);
		}
    }
    spiral_detected = 0;

    dlg = build_new_dlg (&callid /*callid*/,
                         &(get_from(req)->uri) /*from uri*/,
                         &(get_to(req)->uri) /*to uri*/,
                         &ftag/*from_tag*/,
                         &req_uri /*r-uri*/ );

	if (dlg==0) {
		dlg_hash_release(&callid);
		LM_ERR("failed to create new dialog\n");
		return -1;
	}

	/* save caller's tag, cseq, contact and record route*/
	if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
			&(get_from(req)->tag_value)) !=0) {
		dlg_hash_release(&callid);
		LM_ERR("could not add further info to the dialog\n");
		shm_free(dlg);
		return -1;
	}

	/* Populate initial varlist: */
	dlg->vars = get_local_varlist_pointer(req, 1);

	/* after dlg_search() slot was kept locked */
	link_dlg(dlg, 0, 1);
	/* unlock after dlg_search() */
	dlg_hash_release(&callid);

	dlg->lifetime = get_dlg_timeout(req);
	s.s   = _dlg_ctx.to_route_name;
	s.len = strlen(s.s);
	dlg_set_toroute(dlg, &s);
	dlg->sflags |= _dlg_ctx.flags;
	dlg->iflags |= _dlg_ctx.iflags;

	if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0)
		dlg->iflags |= DLG_IFLAG_TIMEOUTBYE;

    if (run_initial_cbs)  run_create_callbacks( dlg, req);

	/* first INVITE seen (dialog created, unconfirmed) */
	if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
			add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) {
		LM_ERR("failed to add RR param\n");
		goto error;
	}

    if_update_stat( dlg_enable_stats, processed_dlgs, 1);

	_dlg_ctx.cpid = my_pid();
    _dlg_ctx.iuid.h_entry = dlg->h_entry;
    _dlg_ctx.iuid.h_id = dlg->h_id;
    set_current_dialog(req, dlg);

	return 0;

error:
	if (!spiral_detected)
		dlg_unref(dlg, 1);               // undo ref regarding linking
	return -1;
}
Beispiel #29
0
/*  This function is called whenever a reply for our module is received; 
  * we need to register  this function on module initialization;
  *  Returns :   0 - core router stops
  *              1 - core router relay statelessly
  */
int reply_received( struct sip_msg  *p_msg )
{
	int msg_status;
	int last_uac_status;
	int branch;
	int reply_status;
	utime_t timer;
	/* has the transaction completed now and we need to clean-up? */
	branch_bm_t cancel_bitmap;
	struct ua_client *uac;
	struct cell *t;
	struct usr_avp **backup_list;
	unsigned int has_reply_route;

	set_t(T_UNDEFINED);

	/* make sure we know the associated transaction ... */
	if (t_check(p_msg, &branch ) == -1) goto not_found;

	/*... if there is none, tell the core router to fwd statelessly */
	t = get_t();
	if ((t == 0) || (t == T_UNDEFINED)) goto not_found;

	cancel_bitmap=0;
	msg_status=p_msg->REPLY_STATUS;

	uac=&t->uac[branch];
	LM_DBG("org. status uas=%d, uac[%d]=%d local=%d is_invite=%d)\n",
		t->uas.status, branch, uac->last_received, 
		is_local(t), is_invite(t));
	last_uac_status=uac->last_received;
	if_update_stat( tm_enable_stats, tm_rcv_rpls , 1);

	/* it's a cancel which is not e2e ? */
	if ( get_cseq(p_msg)->method_id==METHOD_CANCEL && is_invite(t) ) {
		/* ... then just stop timers */
		reset_timer( &uac->local_cancel.retr_timer);
		if ( msg_status >= 200 ) {
				reset_timer( &uac->local_cancel.fr_timer);
		}
		LM_DBG("reply to local CANCEL processed\n");
		goto done;
	}

	/* *** stop timers *** */
	/* stop retransmission */
	reset_timer(&uac->request.retr_timer);

	/* stop final response timer only if I got a final response */
	if ( msg_status >= 200 ) {
		reset_timer( &uac->request.fr_timer);
	}

	/* acknowledge negative INVITE replies (do it before detailed
	 * on_reply processing, which may take very long, like if it
	 * is attempted to establish a TCP connection to a fail-over dst */
	if (is_invite(t) && ((msg_status >= 300) ||
	(is_local(t) && !no_autoack(t) && msg_status >= 200) )) {
		if (send_ack(p_msg, t, branch)!=0)
			LM_ERR("failed to send ACK (local=%s)\n", is_local(t)?"yes":"no");
	}

	_tm_branch_index = branch;

	/* processing of on_reply block */
	has_reply_route = (t->on_reply) || (t->uac[branch].on_reply);
	if (has_reply_route) {
		if (onreply_avp_mode) {
			/* lock the reply*/
			LOCK_REPLIES( t );
			/* set the as avp_list the one from transaction */
			backup_list = set_avp_list(&t->user_avps);
		} else {
			backup_list = 0;
		}
		/* transfer transaction flag to branch context */
		p_msg->flags = t->uas.request->flags;
		setb0flags(t->uac[branch].br_flags);
		/* run block - first per branch and then global one */
		if ( t->uac[branch].on_reply &&
		(run_top_route(onreply_rlist[t->uac[branch].on_reply].a,p_msg)
		&ACT_FL_DROP) && (msg_status<200) ) {
			if (onreply_avp_mode) {
				UNLOCK_REPLIES( t );
				set_avp_list( backup_list );
			}
			LM_DBG("dropping provisional reply %d\n", msg_status);
			goto done;
		}
		if ( t->on_reply && (run_top_route(onreply_rlist[t->on_reply].a,p_msg)
		&ACT_FL_DROP) && (msg_status<200) ) {
			if (onreply_avp_mode) {
				UNLOCK_REPLIES( t );
				set_avp_list( backup_list );
			}
			LM_DBG("dropping provisional reply %d\n", msg_status);
			goto done;
		}
		/* transfer current message context back to t */
		t->uac[branch].br_flags = getb0flags();
		t->uas.request->flags = p_msg->flags;
		if (onreply_avp_mode)
			/* restore original avp list */
			set_avp_list( backup_list );
	}

	if (!onreply_avp_mode || !has_reply_route)
		/* lock the reply*/
		LOCK_REPLIES( t );

	/* mark that the UAC received replies */
	uac->flags |= T_UAC_HAS_RECV_REPLY;

	/* we fire a cancel on spot if (a) branch is marked "to be canceled" or (b)
	 * the whole transaction was canceled (received cancel) and no cancel sent
	 * yet on this branch; and of course, only if a provisional reply :) */
	if (t->uac[branch].flags&T_UAC_TO_CANCEL_FLAG ||
	((t->flags&T_WAS_CANCELLED_FLAG) && !t->uac[branch].local_cancel.buffer.s)) {
		if ( msg_status < 200 )
			/* reply for an UAC with a pending cancel -> do cancel now */
			cancel_branch(t, branch);
		/* reset flag */
		t->uac[branch].flags &= ~(T_UAC_TO_CANCEL_FLAG);
	}

	if (is_local(t)) {
		reply_status = local_reply(t,p_msg, branch,msg_status,&cancel_bitmap);
		if (reply_status == RPS_COMPLETED) {
			cleanup_uac_timers(t);
			if (is_invite(t)) cancel_uacs(t, cancel_bitmap);
			/* There is no need to call set_final_timer because we know
			 * that the transaction is local */
			put_on_wait(t);
		}
	} else {
		reply_status = relay_reply(t,p_msg,branch,msg_status,&cancel_bitmap);
		/* clean-up the transaction when transaction completed */
		if (reply_status == RPS_COMPLETED) {
			/* no more UAC FR/RETR (if I received a 2xx, there may
			 * be still pending branches ...
			 */
			cleanup_uac_timers(t);
			if (is_invite(t)) cancel_uacs(t, cancel_bitmap);
			/* FR for negative INVITES, WAIT anything else */
			/* set_final_timer(t); */
		}
	}
	
	if (reply_status!=RPS_PROVISIONAL)
		goto done;
	
	/* update FR/RETR timers on provisional replies */
	if (msg_status < 200 && (restart_fr_on_each_reply ||
	((last_uac_status<msg_status) &&
	((msg_status >= 180) || (last_uac_status == 0)))
	) ) { /* provisional now */
		if (is_invite(t)) {
			/* invite: change FR to longer FR_INV, do not
			 * attempt to restart retransmission any more
			 */
			backup_list = set_avp_list(&t->user_avps);
			if (!fr_inv_avp2timer(&timer)) {
				LM_DBG("FR_INV_TIMER = %lld\n", timer);
				set_timer(&uac->request.fr_timer,
					FR_INV_TIMER_LIST, &timer);
			} else {
				set_timer(& uac->request.fr_timer, FR_INV_TIMER_LIST, 0);
			}
			set_avp_list(backup_list);
		} else {
			/* non-invite: restart retransmissions (slow now) */
			uac->request.retr_list = RT_T2;
			set_timer(&uac->request.retr_timer, RT_T2, 0);
		}
	} /* provisional replies */
	
done:
	/* we are done with the transaction, so unref it - the reference
	 * was incremented by t_check() function -bogdan*/
	t_unref(p_msg);
	/* don't try to relay statelessly neither on success
	 * (we forwarded statefully) nor on error; on troubles, 
	 * simply do nothing; that will make the other party to 
	 * retransmit; hopefuly, we'll then be better off 
	 */
	_tm_branch_index = 0;
	return 0;
not_found:
	set_t(T_UNDEFINED);
	return 1;
}
Beispiel #30
0
/*!
 * \brief Remove contact in memory from the list and delete it
 * \param _r record this contact belongs to
 * \param _c deleted contact
 */
void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c)
{
	mem_remove_ucontact(_r, _c);
	if_update_stat( _r->slot, _r->slot->d->contacts, -1);
	free_ucontact(_c);
}