Beispiel #1
0
/**
 * fetch_dlg_value - search for @name in @dlg, write results to @out_val
 *
 * If @val_has_buf is true, @out_val may contain a user-supplied pkg buffer
 * which will be realloc'ed as necessary in order to hold the value.
 *
 * If @val_has_buf is false, the returned @out_val string must not be freed!
 *
 * @return:
 *  0 - success
 * -1 - error
 * -2 - not found
 */
int fetch_dlg_value(struct dlg_cell *dlg, const str *name,
                    str *out_val, int val_has_buf)
{
	struct dlg_val *dv;
	unsigned int id;
	str *val;

	LM_DBG("looking for <%.*s>\n",name->len,name->s);

	id = _get_name_id(name);

	if (!val_has_buf) {
		val = &val_buf;
		val->len = val_buf_size;
	} else
		val = out_val;

	/* lock dialog (if not already locked via a callback triggering)*/
	if (dlg->locked_by!=process_no)
		dlg_lock_dlg( dlg );

	/* iterate the list */
	for( dv=dlg->vals ; dv ; dv=dv->next) {
		if (id==dv->id && name->len==dv->name.len &&
		memcmp(name->s,dv->name.s,name->len)==0 ) {
			LM_DBG("var found-> <%.*s>!\n",dv->val.len,dv->val.s);
			/* found -> make a copy of the value under lock */
			if (dv->val.len > val->len) {
				val->s = (char*)pkg_realloc(val->s,dv->val.len);
				if (val->s==NULL) {
					if (!val_has_buf)
						val_buf_size = 0;

					if (dlg->locked_by!=process_no)
						dlg_unlock_dlg( dlg );
					LM_ERR("failed to do realloc for %d\n",dv->val.len);
					return -1;
				}

				if (!val_has_buf)
					val_buf_size = dv->val.len;
			}
			memcpy( val->s, dv->val.s, dv->val.len );
			val->len = dv->val.len;
			*out_val = *val;

			/* unlock dialog */
			if (dlg->locked_by!=process_no)
				dlg_unlock_dlg( dlg );
			return 0;
		}
	}

	/* unlock dialog */
	if (dlg->locked_by!=process_no)
		dlg_unlock_dlg( dlg );
	LM_DBG("var NOT found!\n");

	return -2;
}
Beispiel #2
0
struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param )
{
	struct mi_root* rpl_tree= NULL;
	struct mi_node* rpl = NULL;
	struct dlg_cell* dlg = NULL;
	unsigned int idx,cnt;

	rpl_tree = process_mi_params( cmd_tree, &dlg, &idx, &cnt);
	if (rpl_tree)
		/* param error */
		return rpl_tree;

	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
	if (rpl_tree==0)
		goto error;
	rpl = &rpl_tree->node;

	if (dlg==NULL) {
		if ( internal_mi_print_dlgs(rpl_tree, rpl, 1, idx, cnt)!=0 )
			goto error;
	} else {
		if ( internal_mi_print_dlg(rpl,dlg,1)!=0 )
			goto error;
		/* done with the dialog -> unlock it */
		dlg_unlock_dlg(dlg);
	}

	return rpl_tree;
error:
	/* if a dialog ref was returned, unlock it now */
	if (dlg) dlg_unlock_dlg(dlg);
	/* trash everything that was built so far */
	if (rpl_tree) free_mi_tree(rpl_tree);
	return NULL;
}
Beispiel #3
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 #4
0
/* removes expired dlgs from main ping_timer list
 * and links them back into a new list */
struct dlg_ping_list* get_timeout_dlgs(void)
{
	struct dlg_ping_list *ret = NULL,*it=NULL,*next=NULL;
	struct dlg_cell *current;
	int detached;

	lock_get(ping_timer->lock);

	for (it=ping_timer->first;it;it=next) {
		current = it->dlg;
		next = it->next;
		detached = 0;

		if (current->flags & DLG_FLAG_PING_CALLER) {
			dlg_lock_dlg(current);
			if (current->legs[DLG_CALLER_LEG].reply_received == 0) {
				dlg_unlock_dlg(current);

				detach_node_unsafe(it);
				detached=1;

				if (ret == NULL)
					ret = it;
				else
				{
					it->next = ret;
					ret = it;
				}
			}
			else
				dlg_unlock_dlg(current);
		}

		if (detached == 0) {
			if (current->flags & DLG_FLAG_PING_CALLEE) {
				dlg_lock_dlg(current);
				if (current->legs[callee_idx(current)].reply_received == 0) {
					dlg_unlock_dlg(current);

					detach_node_unsafe(it);
					if (ret == NULL)
						ret = it;
					else
					{
						it->next = ret;
						ret = it;
					}
				}
				else
					dlg_unlock_dlg(current);
			}
		}
	}

	lock_release(ping_timer->lock);

	return ret;
}
Beispiel #5
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 #6
0
int pv_set_dlg_timeout(struct sip_msg *msg, pv_param_t *param,
		int op, pv_value_t *val)
{
	struct dlg_cell *dlg;
	int timeout, db_update = 0, timer_update = 0;

	if (val==NULL || val->flags & PV_VAL_NULL) {
		LM_ERR("cannot assign dialog timeout to NULL\n");
		return -1;
	}

	if (!(val->flags&PV_VAL_INT)){
		/* try parsing the string */
		if (str2sint(&val->rs, &timeout) < 0) {
			LM_ERR("assigning non-int value to dialog flags\n");
			return -1;
		}
	} else {
		timeout = val->ri;
	}

	if (timeout < 0) {
		LM_ERR("cannot set a negative timeout\n");
		return -1;
	}
	if ((dlg = get_current_dialog()) != NULL) {
		dlg_lock_dlg(dlg);
		dlg->lifetime = timeout;
		/* update now only if realtime and the dialog is confirmed */
		if (dlg->state >= DLG_STATE_CONFIRMED && dlg_db_mode == DB_MODE_REALTIME)
			db_update = 1;
		else
			dlg->flags |= DLG_FLAG_CHANGED;

		if (dlg->state == DLG_STATE_CONFIRMED_NA ||
		dlg->state == DLG_STATE_CONFIRMED)
			timer_update = 1;

		dlg_unlock_dlg(dlg);

		if (db_update)
			update_dialog_timeout_info(dlg);

		if (replication_dests)
			replicate_dialog_updated(dlg);

		if (timer_update && update_dlg_timer(&dlg->tl, timeout) < 0) {
			LM_ERR("failed to update timer\n");
			return -1;
		}
	} else if (current_processing_ctx) {
		/* store it until we match the dialog */
		ctx_timeout_set( timeout );
	} else {
		LM_CRIT("BUG - no proicessing context found !\n");
		return -1;
	}

	return 0;
}
Beispiel #7
0
int store_dlg_value(struct dlg_cell *dlg, str *name, str *val)
{
	int ret;

	/* lock dialog */
	dlg_lock_dlg( dlg );
	ret = store_dlg_value_unsafe(dlg,name,val);
	/* unlock dialog */
	dlg_unlock_dlg( dlg );

	return ret;
}
Beispiel #8
0
int store_dlg_value(struct dlg_cell *dlg, str *name, str *val)
{
	int ret;

	/* lock dialog (if not already locked via a callback triggering)*/
	if (dlg->locked_by!=process_no)
		dlg_lock_dlg( dlg );
	ret = store_dlg_value_unsafe(dlg,name,val);
	/* unlock dialog */
	if (dlg->locked_by!=process_no)
		dlg_unlock_dlg( dlg );

	return ret;
}
Beispiel #9
0
void reply_from_caller(struct cell* t, int type, struct tmcb_params* ps)
{
	struct sip_msg *rpl;
	int statuscode;
	struct dlg_cell *dlg;

	if(ps == NULL || ps->rpl == NULL)
	{
			LM_ERR("Wrong tmcb params\n");
			return;
	}
	if( ps->param== NULL )
	{
			LM_ERR("Null callback parameter\n");
			return;
	}
	
	rpl = ps->rpl;
	statuscode = ps->code;
	dlg = *(ps->param);

	LM_DBG("Status Code received =  [%d]\n", statuscode);

	if (rpl == FAKED_REPLY || statuscode == 408) {
		/* timeout occured, nothing else to do now
		 * next time timer fires, it will detect ping reply was not received
		 */
		LM_INFO("terminating dialog ( due to timeout ) "
					"with callid = [%.*s] \n",dlg->callid.len,dlg->callid.s);
		return;
	}

	if (statuscode == 481)
	{
		/* call/transaction does not exist 
		 * terminate the dialog */
		LM_INFO("terminating dialog ( due to 481 ) "
				"with callid = [%.*s] \n",dlg->callid.len,dlg->callid.s);

		return;
	}

	dlg_lock_dlg(dlg);
	dlg->legs[DLG_CALLER_LEG].reply_received = 1;
	dlg_unlock_dlg(dlg);
}
Beispiel #10
0
int pv_get_dlg_timeout(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	int l = 0;
	char *ch = NULL;
	struct dlg_cell *dlg;

	if(res==NULL)
		return -1;

	if ( (dlg=get_current_dialog())!=NULL ) {

		dlg_lock_dlg(dlg);
		if (dlg->state == DLG_STATE_DELETED)
			l = 0;
		else if (dlg->state < DLG_STATE_CONFIRMED_NA)
			l = dlg->lifetime;
		else
			l = dlg->tl.timeout - get_ticks();
		dlg_unlock_dlg(dlg);

	} else if (current_processing_ctx) {
		if ((l=ctx_timeout_get())==0)
			return pv_get_null( msg, param, res);
	} else {
		return pv_get_null( msg, param, res);
	}

	res->ri = l;

	ch = int2str( (unsigned long)res->ri, &l);
	res->rs.s = ch;
	res->rs.len = l;

	res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;

	return 0;
}
Beispiel #11
0
dlg_t * build_dlg_t(struct dlg_cell * cell, int dst_leg, int src_leg)
{
	dlg_t* td = NULL;
	str cseq;
	unsigned int loc_seq;

	td = (dlg_t*)pkg_malloc(sizeof(dlg_t));
	if(!td){
		LM_ERR("out of pkg memory\n");
		return NULL;
	}
	memset(td, 0, sizeof(dlg_t));

	if ((dst_leg == DLG_CALLER_LEG && (cell->flags & DLG_FLAG_PING_CALLER)) ||
		(dst_leg == callee_idx(cell) && (cell->flags & DLG_FLAG_PING_CALLEE)))
	{
		dlg_lock_dlg(cell);
		if (cell->legs[dst_leg].last_gen_cseq == 0)
		{
			/* no OPTIONS pings for this dlg yet */
			dlg_unlock_dlg(cell);
			goto before_strcseq;
		}
		else
		{
			/* OPTIONS pings sent, use new cseq */
			td->loc_seq.value = ++(cell->legs[dst_leg].last_gen_cseq);
			td->loc_seq.is_set=1;
			dlg_unlock_dlg(cell);
			goto after_strcseq;
		}
	}
before_strcseq:
	/*local sequence number*/
	cseq = cell->legs[dst_leg].r_cseq;
	if( !cseq.s || !cseq.len || str2int(&cseq, &loc_seq) != 0){
		LM_ERR("invalid cseq\n");
		goto error;
	}
	/*we don not increase here the cseq as this will be done by TM*/
	td->loc_seq.value = loc_seq;
	td->loc_seq.is_set = 1;

after_strcseq:

	/*route set*/
	if( cell->legs[dst_leg].route_set.s && cell->legs[dst_leg].route_set.len){
		if( parse_rr_body(cell->legs[dst_leg].route_set.s,
			cell->legs[dst_leg].route_set.len, &td->route_set) !=0){
		 	LM_ERR("failed to parse route set\n");
			goto error;
		}
	} 

	/*remote target--- Request URI*/
	if (cell->legs[dst_leg].contact.s==0 || cell->legs[dst_leg].contact.len==0){
		LM_ERR("no contact available\n");
		goto error;
	}
	td->rem_target = cell->legs[dst_leg].contact;

	td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): 
					 *dlg_leg_to_uri(cell,dst_leg);
	td->loc_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_to_uri(cell,dst_leg):
					 *dlg_leg_from_uri(cell,dst_leg);
	td->id.call_id = cell->callid;
	td->id.rem_tag = cell->legs[dst_leg].tag;
	td->id.loc_tag = cell->legs[src_leg].tag;

	td->state= DLG_CONFIRMED;
	td->send_sock = cell->legs[dst_leg].bind_addr;

	return td;

error:
	free_tm_dlg(td);
	return NULL;
}
Beispiel #12
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 #13
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;
}
/**
 * replicates a local dialog update to all the destinations
 * specified with the 'replicate_dialogs' modparam
 */
void replicate_dialog_updated(struct dlg_cell *dlg)
{
	struct replication_dest *d;
	static str module_name = str_init("dialog");
	int callee_leg;
	str *vars, *profiles;
	str send_buffer;

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

	callee_leg = callee_idx(dlg);

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

	bin_push_str(&dlg->from_uri);
	bin_push_str(&dlg->to_uri);

	bin_push_int(dlg->h_id);
	bin_push_int(dlg->start_ts);
	bin_push_int(dlg->state);

	bin_push_str(&dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str);
	if (dlg->legs[callee_leg].bind_addr)
		bin_push_str(&dlg->legs[callee_leg].bind_addr->sock_str);
	else
		bin_push_str(NULL);

	bin_push_str(&dlg->legs[DLG_CALLER_LEG].r_cseq);
	bin_push_str(&dlg->legs[callee_leg].r_cseq);
	bin_push_str(&dlg->legs[DLG_CALLER_LEG].route_set);
	bin_push_str(&dlg->legs[callee_leg].route_set);
	bin_push_str(&dlg->legs[DLG_CALLER_LEG].contact);
	bin_push_str(&dlg->legs[callee_leg].contact);
	bin_push_str(&dlg->legs[callee_leg].from_uri);
	bin_push_str(&dlg->legs[callee_leg].to_uri);

	/* XXX: on shutdown only? */
	vars = write_dialog_vars(dlg->vals);
	dlg_lock_dlg(dlg);
	profiles = write_dialog_profiles(dlg->profile_links);
	dlg_unlock_dlg(dlg);

	bin_push_str(vars);
	bin_push_str(profiles);
	bin_push_int(dlg->user_flags);
	bin_push_int(dlg->flags &
			     ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED));
	bin_push_int((unsigned int)time(0) + dlg->tl.timeout - get_ticks());
	bin_push_int(dlg->legs[DLG_CALLER_LEG].last_gen_cseq);
	bin_push_int(dlg->legs[callee_leg].last_gen_cseq);

	bin_get_buffer(&send_buffer);

	for (d = replication_dests; d; d = d->next)
		msg_send(0,PROTO_BIN,&d->to,0,send_buffer.s,send_buffer.len,0);

	if_update_stat(dlg_enable_stats,update_sent,1);
	return;

error:
	LM_ERR("Failed to replicate updated dialog\n");
}
Beispiel #15
0
static void dual_bye_event(struct dlg_cell* dlg, struct sip_msg *req, int extra_unref)
{
	int event, old_state, new_state, unref, ret;
	struct sip_msg *fake_msg=NULL;
	context_p old_ctx;
	context_p *new_ctx;

	event = DLG_EVENT_REQBYE;
	next_state_dlg(dlg, event, DLG_DIR_DOWNSTREAM, &old_state, &new_state,
			&unref, dlg->legs_no[DLG_LEG_200OK], 0);
	unref += extra_unref;

	if(new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED){

		LM_DBG("removing dialog with h_entry %u and h_id %u\n",
			dlg->h_entry, dlg->h_id);

		/*destroy linkers */
		dlg_lock_dlg(dlg);
		destroy_linkers(dlg->profile_links, 0);
		dlg->profile_links = NULL;
		dlg_unlock_dlg(dlg);

		/* remove from timer */
		ret = remove_dlg_timer(&dlg->tl);
		if (ret < 0) {
			LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
				"with clid '%.*s' and tags '%.*s' '%.*s'\n",
				dlg, dlg->h_entry, dlg->h_id,
				dlg->callid.len, dlg->callid.s,
				dlg_leg_print_info( dlg, DLG_CALLER_LEG, tag),
				dlg_leg_print_info( dlg, callee_idx(dlg), tag));
		} else if (ret > 0) {
			LM_DBG("dlg already expired (not in timer list) %p [%u:%u] "
				"with clid '%.*s' and tags '%.*s' '%.*s'\n",
				dlg, dlg->h_entry, dlg->h_id,
				dlg->callid.len, dlg->callid.s,
				dlg_leg_print_info( dlg, DLG_CALLER_LEG, tag),
				dlg_leg_print_info( dlg, callee_idx(dlg), tag));
		} else {
			/* successfully removed from timer list */
			unref++;
		}

		if (req==NULL) {
			/* set new msg & processing context */
			if (push_new_processing_context( dlg, &old_ctx, &new_ctx, &fake_msg)==0) {
				/* dialog terminated (BYE) */
				run_dlg_callbacks( DLGCB_TERMINATED, dlg, fake_msg,
					DLG_DIR_NONE, NULL, 0);
				/* reset the processing context */
				if (current_processing_ctx == NULL)
					*new_ctx = NULL;
				else
					context_destroy(CONTEXT_GLOBAL, *new_ctx);
				current_processing_ctx = old_ctx;
			} /* no CB run in case of failure FIXME */
		} else {
			/* we should have the msg and context from upper levels */
			/* dialog terminated (BYE) */
			run_dlg_callbacks( DLGCB_TERMINATED, dlg, req,
				DLG_DIR_NONE, NULL, 0);
		}

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

		if_update_stat( dlg_enable_stats, active_dlgs, -1);
	}

	if(new_state == DLG_STATE_DELETED && old_state == DLG_STATE_DELETED ) {
		/* trash the dialog from DB and memory */
		LM_DBG("second final reply\n");
		/* delete the dialog from DB */
		if (should_remove_dlg_db())
			remove_dialog_from_db(dlg);
		/* force delete from mem */
		unref_dlg(dlg, unref);
	}
}
Beispiel #16
0
/**
 * replicates a locally created dialog to all the destinations
 * specified with the 'replicate_dialogs' modparam
 */
void replicate_dialog_created(struct dlg_cell *dlg)
{
	static str module_name = str_init("dialog");
	int callee_leg;
	str *vars, *profiles;

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

	bin_push_int(clusterer_api.get_my_id());

	callee_leg = callee_idx(dlg);

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

	bin_push_str(&dlg->from_uri);
	bin_push_str(&dlg->to_uri);

	bin_push_int(dlg->h_id);
	bin_push_int(dlg->start_ts);
	bin_push_int(dlg->state);

	bin_push_str(&dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str);
	if (dlg->legs[callee_leg].bind_addr)
		bin_push_str(&dlg->legs[callee_leg].bind_addr->sock_str);
	else
		bin_push_str(NULL);

	bin_push_str(&dlg->legs[DLG_CALLER_LEG].r_cseq);
	bin_push_str(&dlg->legs[callee_leg].r_cseq);
	bin_push_str(&dlg->legs[DLG_CALLER_LEG].route_set);
	bin_push_str(&dlg->legs[callee_leg].route_set);
	bin_push_str(&dlg->legs[DLG_CALLER_LEG].contact);
	bin_push_str(&dlg->legs[callee_leg].contact);
	bin_push_str(&dlg->legs[callee_leg].from_uri);
	bin_push_str(&dlg->legs[callee_leg].to_uri);

	/* XXX: on shutdown only? */
	vars = write_dialog_vars(dlg->vals);
	dlg_lock_dlg(dlg);
	profiles = write_dialog_profiles(dlg->profile_links);
	dlg_unlock_dlg(dlg);

	bin_push_str(vars);
	bin_push_str(profiles);
	bin_push_int(dlg->user_flags);
	bin_push_int(dlg->flags &
			     ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED));
	bin_push_int((unsigned int)time(0) + dlg->tl.timeout - get_ticks());
	bin_push_int(dlg->legs[DLG_CALLER_LEG].last_gen_cseq);
	bin_push_int(dlg->legs[callee_leg].last_gen_cseq);

	if (clusterer_api.send_to(dialog_replicate_cluster, PROTO_BIN) < 0)
 		goto error;

	if_update_stat(dlg_enable_stats,create_sent,1);
	return;

error:
	LM_ERR("Failed to replicate created dialog\n");
}