Ejemplo n.º 1
0
void link_dlg(struct dlg_cell *dlg, int n)
{
	struct dlg_entry *d_entry;

	d_entry = &(d_table->entries[dlg->h_entry]);

	dlg_lock( d_table, d_entry);

	dlg->h_id = d_entry->next_id++;
	if (d_entry->first==0) {
		d_entry->first = d_entry->last = dlg;
	} else {
		d_entry->last->next = dlg;
		dlg->prev = d_entry->last;
		d_entry->last = dlg;
	}

	dlg->ref += 1 + n;
	d_entry->cnt++;

	LM_DBG("ref dlg %p with %d -> %d in h_entry %p - %d \n", dlg, n+1, dlg->ref,
								d_entry,dlg->h_entry);

	dlg_unlock( d_table, d_entry);
	return;
}
Ejemplo n.º 2
0
/*!
 * \brief Release hash table slot by call-id
 * \param callid call-id value
 */
void dlg_hash_release(str *callid)
{
	unsigned int he;
	struct dlg_entry *d_entry;

	he = core_hash(callid, 0, d_table->size);
	d_entry = &(d_table->entries[he]);
	dlg_unlock(d_table, d_entry);
}
Ejemplo n.º 3
0
static int internal_mi_print_dlgs(struct mi_root *rpl_tree,struct mi_node *rpl,
						int with_context, unsigned int idx, unsigned int cnt)
{
	struct dlg_cell *dlg;
	unsigned int i;
	unsigned int n;
	unsigned int total;
	char *p;

	total = 0;
	if (cnt) {
		for(i=0;i<d_table->size ; total+=d_table->entries[i++].cnt );
		p = int2str((unsigned long)total, (int*)&n);
		if (add_mi_node_child(rpl,MI_DUP_VALUE,"dlg_counter",11,p,n)==0)
			return -1;
	}

	LM_DBG("printing %i dialogs, idx=%d, cnt=%d\n", total,idx,cnt);
	rpl->flags |= MI_NOT_COMPLETED;

	for( i=0,n=0 ; i<d_table->size ; i++ ) {
		dlg_lock( d_table, &(d_table->entries[i]) );

		for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
			if (cnt && n<idx) {n++;continue;}
			if (internal_mi_print_dlg(rpl, dlg, with_context)!=0)
				goto error;
			n++;
			if (cnt && n>=idx+cnt) {
				dlg_unlock( d_table, &(d_table->entries[i]) );
				return 0;
			}
			if ( (n % 50) == 0 )
				flush_mi_tree(rpl_tree);
		}
		dlg_unlock( d_table, &(d_table->entries[i]) );
	}
	return 0;

error:
	dlg_unlock( d_table, &(d_table->entries[i]) );
	LM_ERR("failed to print dialog\n");
	return -1;
}
Ejemplo n.º 4
0
/*!
 * \brief Unreference a dialog with locking
 * \see unref_dlg_unsafe
 * \param dlg dialog
 * \param cnt decrement for the reference counter
 */
void dlg_unref(dlg_cell_t *dlg, unsigned int cnt)
{
	dlg_entry_t *d_entry;

	d_entry = &(d_table->entries[dlg->h_entry]);

	dlg_lock( d_table, d_entry);
	unref_dlg_unsafe( dlg, cnt, d_entry);
	dlg_unlock( d_table, d_entry);
}
Ejemplo n.º 5
0
void unref_dlg(struct dlg_cell *dlg, unsigned int cnt)
{
	struct dlg_entry *d_entry;

	d_entry = &(d_table->entries[dlg->h_entry]);

	dlg_lock( d_table, d_entry);
	unref_dlg_unsafe( dlg, cnt, d_entry);
	dlg_unlock( d_table, d_entry);
}
Ejemplo n.º 6
0
int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
{

	dlg_cell_t *dlg;
	str * value;
	str spv;

	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR
			|| param->pvn.u.isname.type!=AVP_NAME_STR
			|| param->pvn.u.isname.name.s.s==NULL) {
		LM_CRIT("BUG - bad parameters\n");
		return -1;
	}

	/* Retrieve the dialog for current message */
	dlg=dlg_get_msg_dialog( msg);

	if (dlg) {
		/* Lock the dialog */
		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
	} else {
		/* Verify the local list */
		get_local_varlist_pointer(msg, 0);
	}

	/* dcm: todo - the value should be cloned for safe usage */
	value = get_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s);

	spv.s = NULL;
	if(value) {
		spv.len = pv_get_buffer_size();
		if(spv.len<value->len+1) {
			LM_ERR("pv buffer too small (%d) - needed %d\n", spv.len, value->len);
		} else {
			spv.s = pv_get_buffer();
			strncpy(spv.s, value->s, value->len);
			spv.len = value->len;
			spv.s[spv.len] = '\0';
		}
	}

	print_lists(dlg);

	/* unlock dialog */
	if (dlg) {
		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
		dlg_release(dlg);
	}

	if (spv.s)
		return pv_get_strval(msg, param, res, &spv);


	return pv_get_null(msg, param, res);
}
Ejemplo n.º 7
0
/*!
 * \brief Check if a dialog belongs to a profile
 * \param msg SIP message
 * \param profile dialog profile table
 * \param value value
 * \return 1 on success, -1 on failure
 */
int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
		str *value)
{
	struct dlg_cell *dlg;
	struct dlg_profile_link *linker;
	struct dlg_entry *d_entry;
	int ret;

	/* get current dialog */
	dlg = dlg_get_msg_dialog(msg);

	if (dlg==NULL)
		return -1;

	ret = -1;
	/* check the dialog linkers */
	d_entry = &d_table->entries[dlg->h_entry];
	dlg_lock( d_table, d_entry);
	for( linker=dlg->profile_links ; linker ; linker=linker->next) {
		if (linker->profile==profile) {
			if (profile->has_value==0) {
				dlg_unlock( d_table, d_entry);
				ret = 1;
				goto done;
			} else if (value && value->len==linker->hash_linker.value.len &&
			memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
				dlg_unlock( d_table, d_entry);
				ret = 1;
				goto done;
			}
			/* allow further search - maybe the dialog is inserted twice in
			 * the same profile, but with different values -bogdan
			 */
		}
	}
	dlg_unlock( d_table, d_entry);

done:
	dlg_release(dlg);
	return ret;
}
Ejemplo n.º 8
0
/*!
 * \brief Unreference a dialog with locking
 * \see unref_dlg_unsafe
 * \param dlg dialog
 * \param cnt decrement for the reference counter
 */
void dlg_unref_helper(dlg_cell_t *dlg, unsigned int cnt, const char *fname,
		int fline)
{
	dlg_entry_t *d_entry;

	LM_DBG("unref op on %p with %d from %s:%d\n", dlg, cnt, fname, fline);
	d_entry = &(d_table->entries[dlg->h_entry]);

	dlg_lock( d_table, d_entry);
	unref_dlg_unsafe( dlg, cnt, d_entry);
	dlg_unlock( d_table, d_entry);
}
Ejemplo n.º 9
0
/*!
 * \brief Update or set the Contact for an existing dialog
 * \param dlg dialog
 * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
 * \param ct Contact of caller or callee
 * \return 0 on success, -1 on failure
 */
int dlg_update_contact(struct dlg_cell * dlg, unsigned int leg, str *ct)
{
	dlg_entry_t *d_entry;

	d_entry = &(d_table->entries[dlg->h_entry]);

	dlg_lock(d_table, d_entry);

	if ( dlg->contact[leg].s ) {
		if(dlg->contact[leg].len == ct->len
				&& memcmp(dlg->contact[leg].s, ct->s, ct->len)==0) {
			LM_DBG("same contact for leg[%d] - [%.*s]\n", leg,
				dlg->contact[leg].len, dlg->contact[leg].s);
			goto done;
		}
		if (dlg->contact[leg].len < ct->len) {
			shm_free(dlg->contact[leg].s);
			dlg->contact[leg].s = (char*)shm_malloc(ct->len);
			if (dlg->contact[leg].s==NULL)
				goto error;
		}
	} else {
		dlg->contact[leg].s = (char*)shm_malloc(ct->len);
		if (dlg->contact[leg].s==NULL)
			goto error;
	}

	memcpy( dlg->contact[leg].s, ct->s, ct->len );
	dlg->contact[leg].len = ct->len;

	LM_DBG("contact of leg[%d] is %.*s\n", leg,
			dlg->contact[leg].len, dlg->contact[leg].s);
done:
	dlg_unlock(d_table, d_entry);
	return 0;
error:
	dlg_unlock(d_table, d_entry);
	LM_ERR("not more shm mem\n");
	return -1;
}
Ejemplo n.º 10
0
/*!
 * \brief Helper function that outputs all dialogs via the RPC interface
 * \see rpc_print_dlgs
 * \param rpc RPC node that should be filled
 * \param c RPC void pointer
 * \param with_context if 1 then the dialog context will be also printed
 */
static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
{
	dlg_cell_t *dlg;
	unsigned int i;

	for( i=0 ; i<d_table->size ; i++ ) {
		dlg_lock( d_table, &(d_table->entries[i]) );

		for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
			internal_rpc_print_dlg(rpc, c, dlg, with_context);
		}
		dlg_unlock( d_table, &(d_table->entries[i]) );
	}
}
Ejemplo n.º 11
0
/*!
 * \brief Helper function that output all dialogs via the MI interface
 * \see mi_print_dlgs
 * \param rpl MI node that should be filled
 * \param with_context if 1 then the dialog context will be also printed
 * \return 0 on success, -1 on failure
 */
static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context)
{
	struct dlg_cell *dlg;
	unsigned int i;

	LM_DBG("printing %i dialogs\n", d_table->size);

	for( i=0 ; i<d_table->size ; i++ ) {
		dlg_lock( d_table, &(d_table->entries[i]) );

		for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
			if (internal_mi_print_dlg(rpl, dlg, with_context)!=0)
				goto error;
		}
		dlg_unlock( d_table, &(d_table->entries[i]) );
	}
	return 0;

error:
	dlg_unlock( d_table, &(d_table->entries[i]) );
	LM_ERR("failed to print dialog\n");
	return -1;
}
Ejemplo n.º 12
0
int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
{
    if( !dlg || !key || key->len > strlen(key->s) || (val && val->len > strlen(val->s)))
    {
        LM_ERR("BUG - bad parameters\n");
        return -1;
    }

    dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));

    if( !val)
    {
        if (set_dlg_variable_unsafe(dlg, key, NULL)!=0) {
            LM_ERR("failed to delete dialog variable <%.*s>\n", key->len,key->s);
            goto error;
        }
    } else {
        if (set_dlg_variable_unsafe(dlg, key, val)!=0) {
            LM_ERR("failed to store dialog values <%.*s>\n",key->len,key->s);
            goto error;
        }
    }

    dlg->dflags &= DLG_FLAG_CHANGED_VARS;
    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));

    if ( dlg_db_mode==DB_MODE_REALTIME )
        update_dialog_dbinfo(dlg);

    print_lists(dlg);

    return 0;

error:
    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
    return -1;
}
Ejemplo n.º 13
0
str * get_dlg_variable(struct dlg_cell *dlg, str *key)
{
    str* var = NULL;

    if( !dlg || !key || key->len > strlen(key->s))
    {
        LM_ERR("BUG - bad parameters\n");

        return NULL;
    }

    dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
    var = get_dlg_variable_unsafe( dlg, key);
    dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));

    return var;
}
Ejemplo n.º 14
0
/*!
 * \brief Helper function that outputs a dialog via the RPC interface
 * \see rpc_print_dlgs
 * \param rpc RPC node that should be filled
 * \param c RPC void pointer
 * \param with_context if 1 then the dialog context will be also printed
 */
static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
	str callid, from_tag;
	dlg_entry_t *d_entry;
	dlg_cell_t *dlg;
	unsigned int h_entry;

	if (rpc->scan(c, ".S.S", &callid, &from_tag) < 2) return;

	h_entry = core_hash( &callid, 0, d_table->size);
	d_entry = &(d_table->entries[h_entry]);
	dlg_lock( d_table, d_entry);
	for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
		if (match_downstream_dialog( dlg, &callid, &from_tag)==1) {
			internal_rpc_print_dlg(rpc, c, dlg, with_context);
		}
	}
	dlg_unlock( d_table, d_entry);
}
Ejemplo n.º 15
0
/**
 * clean old unconfirmed dialogs
 *
 */
int dlg_clean_run(ticks_t ti)
{
	unsigned int i;
	unsigned int tm;
	dlg_cell_t *dlg;
	dlg_cell_t *tdlg;

	tm = (unsigned int)time(NULL);
	for(i=0; i<d_table->size; i++)
	{
		dlg_lock(d_table, &d_table->entries[i]);
		dlg = d_table->entries[i].first;
		while (dlg) {
			tdlg = dlg;
			dlg = dlg->next;
			if(tdlg->state==DLG_STATE_UNCONFIRMED && tdlg->init_ts>0
					&& tdlg->init_ts<tm-dlg_early_timeout) {
				/* dialog in early state older than 5min */
				LM_NOTICE("dialog in early state is too old (%p ref %d)\n",
						tdlg, tdlg->ref);
				unlink_unsafe_dlg(&d_table->entries[i], tdlg);
				destroy_dlg(tdlg);
			}
			if(tdlg->state==DLG_STATE_CONFIRMED_NA && tdlg->start_ts>0
					&& tdlg->start_ts<tm-dlg_noack_timeout) {
				if(update_dlg_timer(&tdlg->tl, 10)<0) {
					LM_ERR("failed to update dialog lifetime in long non-ack state\n");
				}
				tdlg->lifetime = 10;
				tdlg->dflags |= DLG_FLAG_CHANGED;
			}
			if(tdlg->state==DLG_STATE_DELETED && tdlg->end_ts>0
					&& tdlg->end_ts<tm-dlg_end_timeout) {
				/* dialog in deleted state older than 5min */
				LM_NOTICE("dialog in delete state is too old (%p ref %d)\n",
						tdlg, tdlg->ref);
				unlink_unsafe_dlg(&d_table->entries[i], tdlg);
				destroy_dlg(tdlg);
			}
		}
		dlg_unlock(d_table, &d_table->entries[i]);
	}
	return 0;
}
Ejemplo n.º 16
0
/*!
 * \brief Link a dialog profile
 * \param linker dialog linker
 * \param dlg dialog cell
 */
static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg)
{
	unsigned int hash;
	struct dlg_profile_entry *p_entry;
	struct dlg_entry *d_entry;

	/* add the linker to the dialog */
	/* FIXME zero h_id is not 100% for testing if the dialog is inserted
	 * into the hash table -> we need circular lists  -bogdan */
	if (dlg->h_id) {
		d_entry = &d_table->entries[dlg->h_entry];
		dlg_lock( d_table, d_entry);
		linker->next = dlg->profile_links;
		dlg->profile_links =linker;
		linker->hash_linker.dlg = dlg;
		dlg_unlock( d_table, d_entry);
	} else {
		linker->next = dlg->profile_links;
		dlg->profile_links =linker;
		linker->hash_linker.dlg = dlg;
	}

	/* calculate the hash position */
	hash = calc_hash_profile(&linker->hash_linker.value, dlg, linker->profile);
	linker->hash_linker.hash = hash;

	/* insert into profile hash table */
	p_entry = &linker->profile->entries[hash];
	lock_get( &linker->profile->lock );
	if (p_entry->first) {
		linker->hash_linker.prev = p_entry->first->prev;
		linker->hash_linker.next = p_entry->first;
		p_entry->first->prev->next = &linker->hash_linker;
		p_entry->first->prev = &linker->hash_linker;
	} else {
		p_entry->first = linker->hash_linker.next 
			= linker->hash_linker.prev = &linker->hash_linker;
	}
	p_entry->content ++;
	lock_release( &linker->profile->lock );
}
Ejemplo n.º 17
0
void print_all_dlgs() {
    //print all dialog information  - this is just for testing and is set to happen every 10 seconds

    struct dlg_cell *dlg;
    unsigned int i;


    LM_DBG("********************");
    LM_DBG("printing %i dialogs\n", d_table->size);

    for (i = 0; i < d_table->size; i++) {
        dlg_lock(d_table, &(d_table->entries[i]));

        for (dlg = d_table->entries[i].first; dlg; dlg = dlg->next) {
            internal_print_all_dlg(dlg);
        }
        dlg_unlock(d_table, &(d_table->entries[i]));
    }
    LM_DBG("********************");

}
Ejemplo n.º 18
0
int dmq_send_all_dlgs(dmq_node_t* dmq_node) {
	int index;
	dlg_entry_t entry;
	dlg_cell_t *dlg;

	LM_DBG("sending all dialogs \n");

	for(index = 0; index< d_table->size; index++){
		/* lock the whole entry */
		entry = (d_table->entries)[index];
		dlg_lock( d_table, &entry);

		for(dlg = entry.first; dlg != NULL; dlg = dlg->next){
				dlg->dflags |= DLG_FLAG_CHANGED_PROF;
				dlg_dmq_replicate_action(DLG_DMQ_UPDATE, dlg, 0, dmq_node);
		}

		dlg_unlock( d_table, &entry);
	}

	return 0;
}
Ejemplo n.º 19
0
/*!
 * \brief Link a dialog profile
 * \param linker dialog linker
 * \param dlg dialog cell
 */
static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg)
{
	struct dlg_entry *d_entry;

	/* add the linker to the dialog */
	/* FIXME zero h_id is not 100% for testing if the dialog is inserted
	 * into the hash table -> we need circular lists  -bogdan */
	if (dlg->h_id) {
		d_entry = &d_table->entries[dlg->h_entry];
		dlg_lock( d_table, d_entry);
		linker->next = dlg->profile_links;
		dlg->profile_links =linker;
		linker->hash_linker.dlg = dlg;
		dlg_unlock( d_table, d_entry);
	} else {
		linker->next = dlg->profile_links;
		dlg->profile_links =linker;
		linker->hash_linker.dlg = dlg;
	}

	atomic_or_int((volatile int*)&dlg->dflags, DLG_FLAG_CHANGED_PROF);
	link_profile(linker, &dlg->callid);
}
Ejemplo n.º 20
0
/**
 * replicates the remote update of an ongoing dialog locally
 * by reading the relevant information using the Binary Packet Interface
 */
int dlg_replicated_update(void)
{
	struct dlg_cell *dlg;
	str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles;
	unsigned int dir, dst_leg;
	int timeout, h_entry;
	str st;
	struct dlg_entry *d_entry;

	bin_pop_str(&call_id);
	bin_pop_str(&from_tag);
	bin_pop_str(&to_tag);
	bin_pop_str(&from_uri);
	bin_pop_str(&to_uri);

	LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n",
	call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s,
	from_uri.len, from_uri.s, to_uri.len, to_uri.s);

	dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg);

	h_entry = dlg_hash(&call_id);
	d_entry = &d_table->entries[h_entry];

	dlg_lock(d_table, d_entry);

	if (!dlg) {
		/* TODO: change to LM_DBG */
		LM_ERR("dialog not found, building new\n");

		dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag);
		if (!dlg) {
			LM_ERR("Failed to create replicated dialog!\n");
			goto error;
		}

		return dlg_replicated_create(dlg, &from_tag, &to_tag, 0);
	}

	bin_skip_int(2);
	bin_pop_int(&dlg->state);

	bin_skip_str(2);

	bin_pop_str(&st);
	if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) {
		LM_ERR("failed to update caller cseq\n");
		goto error;
	}

	bin_pop_str(&st);
	if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) {
		LM_ERR("failed to update callee cseq\n");
		goto error;
	}

	bin_skip_str(6);
	bin_pop_str(&vars);
	bin_pop_str(&profiles);
	bin_pop_int(&dlg->user_flags);
	bin_pop_int(&dlg->flags);

	bin_pop_int(&timeout);
	bin_skip_int(2);

	timeout -= time(0);
	LM_DBG("Received updated timeout of %d for dialog %.*s\n",timeout,call_id.len,call_id.s);

	if (dlg->lifetime != timeout) {
		dlg->lifetime = timeout;
		if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1)
			LM_ERR("failed to update dialog lifetime!\n");
	}

	unref_dlg_unsafe(dlg, 1, d_entry);

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

	return 0;

error:
	dlg_unlock(d_table, d_entry);
	return -1;
}
Ejemplo n.º 21
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:
				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);
}
Ejemplo n.º 22
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);
}
Ejemplo n.º 23
0
void dialog_update_db(unsigned int ticks, void * param)
{
	static db_ps_t my_ps_update = NULL;
	static db_ps_t my_ps_insert = NULL;
	static db_ps_t my_ps_update_vp = NULL;
	int index;
	db_val_t values[DIALOG_TABLE_TOTAL_COL_NO];
	struct dlg_entry entry;
	struct dlg_cell  * cell; 
	unsigned char on_shutdown;
	int callee_leg,ins_done=0;
	static query_list_t *ins_list = NULL;

	db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = {	&h_entry_column,
			&h_id_column,		&call_id_column,		&from_uri_column,
			&from_tag_column,	&to_uri_column,			&to_tag_column,
			&from_sock_column,	&to_sock_column,		&start_time_column,
			&from_route_column,	&to_route_column, 	&from_contact_column,
			&to_contact_column, &mangled_fu_column, &mangled_tu_column,
			/*update chunk */
			&state_column,		&timeout_column,		&from_cseq_column,
			&to_cseq_column,	&from_ping_cseq_column, &to_ping_cseq_column,
			&vars_column,		&profiles_column,		&sflags_column, &flags_column};

	if (dialog_db_handle==0 || use_dialog_table()!=0)
		return;

	on_shutdown = (ticks==0);

	/*save the current dialogs information*/
	VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = 
	VAL_TYPE(values+16) = VAL_TYPE(values+17) = VAL_TYPE(values+20) =
	VAL_TYPE(values+21) = VAL_TYPE(values+24) = VAL_TYPE(values+25)= DB_INT;

	VAL_TYPE(values+2) = VAL_TYPE(values+3) = VAL_TYPE(values+4) = 
	VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = 
	VAL_TYPE(values+8) = VAL_TYPE(values+10) = VAL_TYPE(values+11) = 
	VAL_TYPE(values+12) = VAL_TYPE(values+13) = VAL_TYPE(values+14) =
	VAL_TYPE(values+15) = VAL_TYPE(values+18) = VAL_TYPE(values+19) = 
	VAL_TYPE(values+22) = VAL_TYPE(values+23) = DB_STR;

	for(index = 0; index< d_table->size; index++){

		/* lock the whole entry */
		entry = (d_table->entries)[index];
		dlg_lock( d_table, &entry);

		for(cell = entry.first; cell != NULL; cell = cell->next){

			callee_leg = callee_idx(cell);

			if( (cell->flags & DLG_FLAG_NEW) != 0 ) {

				if ( cell->state == DLG_STATE_DELETED ) {
					/* don't need to insert dialogs already terminated */
					continue;
				}
				LM_DBG("inserting new dialog %p\n",cell);

				SET_INT_VALUE(values, cell->h_entry);
				SET_INT_VALUE(values+1, cell->h_id);
				SET_STR_VALUE(values+2, cell->callid);
				SET_STR_VALUE(values+3, cell->from_uri);

				SET_STR_VALUE(values+4, cell->legs[DLG_CALLER_LEG].tag);
				SET_STR_VALUE(values+5, cell->to_uri);
				SET_STR_VALUE(values+6, cell->legs[callee_leg].tag);

				SET_STR_VALUE(values+7,
					cell->legs[DLG_CALLER_LEG].bind_addr->sock_str);
				if (cell->legs[callee_leg].bind_addr) {
					SET_STR_VALUE(values+8, 
						cell->legs[callee_leg].bind_addr->sock_str);
				} else {
					VAL_NULL(values+8) = 1;
				}

				SET_INT_VALUE(values+9,  cell->start_ts);

				SET_STR_VALUE(values+10, cell->legs[DLG_CALLER_LEG].route_set);
				SET_STR_VALUE(values+11,
					cell->legs[callee_leg].route_set);
				SET_STR_VALUE(values+12, cell->legs[DLG_CALLER_LEG].contact);
				SET_STR_VALUE(values+13,
					cell->legs[callee_leg].contact);


				SET_STR_VALUE(values+14,cell->legs[callee_leg].from_uri);
				SET_STR_VALUE(values+15,cell->legs[callee_leg].to_uri);

				SET_INT_VALUE(values+16, cell->state);
				SET_INT_VALUE(values+17, (unsigned int)((unsigned int)time(0)
					+ cell->tl.timeout - get_ticks()) );

				SET_STR_VALUE(values+18, cell->legs[DLG_CALLER_LEG].r_cseq);
				SET_STR_VALUE(values+19, cell->legs[callee_leg].r_cseq);

				SET_INT_VALUE(values+20, cell->legs[DLG_CALLER_LEG].last_gen_cseq);
				SET_INT_VALUE(values+21, cell->legs[callee_leg].last_gen_cseq);

				set_final_update_cols(values+22, cell, on_shutdown);
				SET_INT_VALUE(values+25, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED));

				CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert;
				if (con_set_inslist(&dialog_dbf,dialog_db_handle,
				&ins_list,insert_keys,DIALOG_TABLE_TOTAL_COL_NO) < 0 )
					CON_RESET_INSLIST(dialog_db_handle);

				if((dialog_dbf.insert(dialog_db_handle, insert_keys, 
				values, DIALOG_TABLE_TOTAL_COL_NO)) !=0){
					LM_ERR("could not add another dialog to db\n");
					goto error;
				}

				if (ins_done==0)
					ins_done=1;

				/* dialog saved */
				run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0);

				cell->flags &= ~(DLG_FLAG_NEW |DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED);

			} else if ( (cell->flags & DLG_FLAG_CHANGED)!=0 || on_shutdown ){
				LM_DBG("updating existing dialog %p\n",cell);

				SET_INT_VALUE(values, cell->h_entry);
				SET_INT_VALUE(values+1, cell->h_id);

				SET_INT_VALUE(values+16, cell->state);
				SET_INT_VALUE(values+17, (unsigned int)((unsigned int)time(0)
					 + cell->tl.timeout - get_ticks()) );
				SET_STR_VALUE(values+18, cell->legs[DLG_CALLER_LEG].r_cseq);
				SET_STR_VALUE(values+19, cell->legs[callee_leg].r_cseq);
				SET_INT_VALUE(values+20, cell->legs[DLG_CALLER_LEG].last_gen_cseq);
				SET_INT_VALUE(values+21, cell->legs[callee_leg].last_gen_cseq);

				set_final_update_cols(values+22, cell, 1);
				SET_INT_VALUE(values+25, cell->flags);

				CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update;

				if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, 
				(values), (insert_keys+16), (values+16), 2, 10)) !=0) {
					LM_ERR("could not update database info\n");
					goto error;
				}

				/* dialog saved */
				run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0);

				cell->flags &= ~(DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED);
			} else if (cell->flags & DLG_FLAG_VP_CHANGED) {

				SET_INT_VALUE(values, cell->h_entry);
				SET_INT_VALUE(values+1, cell->h_id);

				set_final_update_cols(values+22, cell, 0);

				CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update_vp;

				if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, 
				(values), (insert_keys+22), (values+22), 2, 3)) !=0) {
					LM_ERR("could not update database info\n");
					goto error;
				}

				run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0);

				cell->flags &= ~DLG_FLAG_VP_CHANGED;
			}
		}
		dlg_unlock( d_table, &entry);

	}

	if (ins_done) {
		LM_DBG("dlg timer attempting to flush rows to DB\n");
		/* flush everything to DB
		 * so that next-time timer fires
		 * we are sure that DB updates will be succesful */
		if (ql_flush_rows(&dialog_dbf,dialog_db_handle,ins_list) < 0)
			LM_ERR("failed to flush rows to DB\n");
	}

	return;

error:
	dlg_unlock( d_table, &entry);
}
Ejemplo n.º 24
0
int update_dialog_dbinfo(struct dlg_cell * cell)
{
	static db_ps_t my_ps_insert = NULL;
	static db_ps_t my_ps_update = NULL;
	static db_ps_t my_ps_update_vp = NULL;
	struct dlg_entry entry;
	db_val_t values[DIALOG_TABLE_TOTAL_COL_NO];
	int callee_leg;

	db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { &h_entry_column,
			&h_id_column,        &call_id_column,     &from_uri_column,
			&from_tag_column,    &to_uri_column,      &to_tag_column,
			&from_sock_column,   &to_sock_column,
			&start_time_column,  &mangled_fu_column,  &mangled_tu_column,
			
			&state_column,       &timeout_column,
			&from_cseq_column,   &to_cseq_column,     &from_ping_cseq_column,
			&to_ping_cseq_column,&flags_column,
			&vars_column,        &profiles_column,    &sflags_column,
			&from_route_column,
			&to_route_column,    &from_contact_column,&to_contact_column};

	if(use_dialog_table()!=0)
		return -1;

	callee_leg= callee_idx(cell);

	if((cell->flags & DLG_FLAG_NEW) != 0){
		/* save all the current dialogs information*/
		VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+9) = 
		VAL_TYPE(values+12) = VAL_TYPE(values+13) = VAL_TYPE(values+16) =
		VAL_TYPE(values+17) = VAL_TYPE(values+18) = 
		VAL_TYPE(values+21) = DB_INT;

		VAL_TYPE(values+2) = VAL_TYPE(values+3) = VAL_TYPE(values+4) = 
		VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = 
		VAL_TYPE(values+8) = VAL_TYPE(values+10) = VAL_TYPE(values+11) =
		VAL_TYPE(values+14) = VAL_TYPE(values+15) = 
		VAL_TYPE(values+19) = VAL_TYPE(values+20) = VAL_TYPE(values+22) =
		VAL_TYPE(values+23) = VAL_TYPE(values+24) =
		VAL_TYPE(values+25) = DB_STR;

		/* lock the entry */
		entry = (d_table->entries)[cell->h_entry];
		dlg_lock( d_table, &entry);

		SET_INT_VALUE(values, cell->h_entry);
		SET_INT_VALUE(values+1, cell->h_id);
		SET_STR_VALUE(values+2, cell->callid);

		SET_STR_VALUE(values+3, cell->from_uri);
		SET_STR_VALUE(values+4, cell->legs[DLG_CALLER_LEG].tag);
		SET_STR_VALUE(values+5, cell->to_uri);
		SET_STR_VALUE(values+6, cell->legs[callee_leg].tag);

		SET_STR_VALUE(values+7, cell->legs[DLG_CALLER_LEG].bind_addr->sock_str);
		if (cell->legs[callee_leg].bind_addr) {
			SET_STR_VALUE(values+8, 
				cell->legs[callee_leg].bind_addr->sock_str);
		} else {
			VAL_NULL(values+8) = 1;
		}

		SET_INT_VALUE(values+9, cell->start_ts);

		SET_STR_VALUE(values+10,cell->legs[callee_leg].from_uri);
		SET_STR_VALUE(values+11,cell->legs[callee_leg].to_uri);

		SET_INT_VALUE(values+12, cell->state);
		SET_INT_VALUE(values+13, (unsigned int)( (unsigned int)time(0) +
			 cell->tl.timeout - get_ticks()) );

		SET_STR_VALUE(values+14, cell->legs[DLG_CALLER_LEG].r_cseq);
		SET_STR_VALUE(values+15, cell->legs[callee_leg].r_cseq);
		SET_INT_VALUE(values+16,cell->legs[DLG_CALLER_LEG].last_gen_cseq);
		SET_INT_VALUE(values+17,cell->legs[callee_leg].last_gen_cseq);
		SET_INT_VALUE(values+18, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED));
		set_final_update_cols(values+19, cell, 0);
		SET_STR_VALUE(values+22, cell->legs[DLG_CALLER_LEG].route_set);
		SET_STR_VALUE(values+23, cell->legs[callee_leg].route_set);
		SET_STR_VALUE(values+24, cell->legs[DLG_CALLER_LEG].contact);
		SET_STR_VALUE(values+25, cell->legs[callee_leg].contact);

		CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert;

		if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, 
								DIALOG_TABLE_TOTAL_COL_NO)) !=0){
			LM_ERR("could not add another dialog to db\n");
			goto error;
		}

		/* dialog saved */
		run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0);

		cell->flags &= ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED);

	} else if((cell->flags & DLG_FLAG_CHANGED) != 0) {
		/* save only dialog's state and timeout */
		VAL_TYPE(values) = VAL_TYPE(values+1) = 
		VAL_TYPE(values+12) = VAL_TYPE(values+13) = VAL_TYPE(values+16) =
		VAL_TYPE(values+17) = VAL_TYPE(values+18) =
		VAL_TYPE(values+21) =DB_INT;

		VAL_TYPE(values+14) = VAL_TYPE(values+15) =
		VAL_TYPE(values+19) = VAL_TYPE(values+20) = DB_STR;

		/* lock the entry */
		entry = (d_table->entries)[cell->h_entry];
		dlg_lock( d_table, &entry);

		SET_INT_VALUE(values, cell->h_entry);
		SET_INT_VALUE(values+1, cell->h_id);
		SET_INT_VALUE(values+12, cell->state);
		SET_INT_VALUE(values+13, (unsigned int)( (unsigned int)time(0) +
				 cell->tl.timeout - get_ticks()) );

		SET_STR_VALUE(values+14, cell->legs[DLG_CALLER_LEG].r_cseq);
		SET_STR_VALUE(values+15, cell->legs[callee_leg].r_cseq);
		SET_INT_VALUE(values+16,cell->legs[DLG_CALLER_LEG].last_gen_cseq);
		SET_INT_VALUE(values+17,cell->legs[callee_leg].last_gen_cseq);
		SET_INT_VALUE(values+18, cell->flags);
		set_final_update_cols(values+19, cell, 1);

		CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update;

		if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, 
						(values), (insert_keys+12), (values+12), 2, 10)) !=0){
			LM_ERR("could not update database info\n");
			goto error;
		}

		/* dialog saved */
		run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0);

		cell->flags &= ~(DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED);
	} else if (cell->flags & DLG_FLAG_VP_CHANGED) {
		cell->flags |= DLG_FLAG_VP_CHANGED;
		VAL_TYPE(values) = VAL_TYPE(values+1) = VAL_TYPE(values+21) = DB_INT;
		VAL_TYPE(values+19) = VAL_TYPE(values+20) = DB_STR;

		/* lock the entry */
		entry = (d_table->entries)[cell->h_entry];
		dlg_lock( d_table, &entry);

		SET_INT_VALUE(values, cell->h_entry);
		SET_INT_VALUE(values+1, cell->h_id);

		set_final_update_cols(values+19, cell, 0);

		CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update_vp;

		if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, 
						(values), (insert_keys+19), (values+19), 2, 3)) !=0){
			LM_ERR("could not update database info\n");
			goto error;
		}

		run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0);

		cell->flags &= ~DLG_FLAG_VP_CHANGED;
	} else {
		return 0;
	}

	dlg_unlock( d_table, &entry);
	return 0;

error:
	dlg_unlock( d_table, &entry);
	return -1;
}
Ejemplo n.º 25
0
int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
{
	dlg_cell_t *dlg = NULL;
	int ret = -1;

	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR
			|| param->pvn.u.isname.type!=AVP_NAME_STR
			|| param->pvn.u.isname.name.s.s==NULL ) {
		LM_CRIT("BUG - bad parameters\n");
		goto error;
	}

	/* Retrieve the dialog for current message */
	dlg=dlg_get_msg_dialog( msg);
	
	if (dlg) {
		/* Lock the dialog */
		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
	} else {
		/* Verify the local list */
		get_local_varlist_pointer(msg, 0);
	}

	if (val==NULL || val->flags&(PV_VAL_NONE|PV_VAL_NULL|PV_VAL_EMPTY)) {
		/* if NULL, remove the value */
		ret = set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, NULL);
		if(ret!= 0) {
			/* unlock dialog */
			if (dlg) {
				dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
				dlg_release(dlg);
			}
			return ret;
		}
	} else {
		/* if value, must be string */
		if ( !(val->flags&PV_VAL_STR)) {
			LM_ERR("non-string values are not supported\n");
			/* unlock dialog */
			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
			goto error;
		}

		ret = set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, &val->rs);
		if(ret!= 0) {
			/* unlock dialog */
			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
			goto error;
		}
	}
	/* unlock dialog */
	if (dlg) {
		dlg->dflags |= DLG_FLAG_CHANGED_VARS;
		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
		if ( dlg_db_mode==DB_MODE_REALTIME )
			update_dialog_dbinfo(dlg);

	}
	print_lists(dlg);

	dlg_release(dlg);
	return 0;
error:
	dlg_release(dlg);
	return -1;
}
Ejemplo n.º 26
0
/**
 * replicates the remote update of an ongoing dialog locally
 * by reading the relevant information using the Binary Packet Interface
 */
int dlg_replicated_update(bin_packet_t *packet)
{
	struct dlg_cell *dlg;
	str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles;
	unsigned int dir, dst_leg;
	int timeout, h_entry;
	str st;
	struct dlg_entry *d_entry;
	int rcv_flags, save_new_flag;

	bin_pop_str(packet, &call_id);
	bin_pop_str(packet, &from_tag);
	bin_pop_str(packet, &to_tag);
	bin_pop_str(packet, &from_uri);
	bin_pop_str(packet, &to_uri);

	LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n",
		call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s,
		from_uri.len, from_uri.s, to_uri.len, to_uri.s);

	dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg);

	h_entry = dlg_hash(&call_id);
	d_entry = &d_table->entries[h_entry];

	dlg_lock(d_table, d_entry);

	if (!dlg) {
		LM_DBG("dialog not found, building new\n");

		dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag);
		if (!dlg) {
			LM_ERR("Failed to create replicated dialog!\n");
			goto error;
		}

		return dlg_replicated_create(packet ,dlg, &from_tag, &to_tag, 0);
	}

	bin_skip_int(packet, 2);
	bin_pop_int(packet, &dlg->state);

	bin_skip_str(packet, 2);

	bin_pop_str(packet, &st);
	if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) {
		LM_ERR("failed to update caller cseq\n");
		goto error;
	}

	bin_pop_str(packet, &st);
	if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) {
		LM_ERR("failed to update callee cseq\n");
		goto error;
	}

	bin_skip_str(packet, 6);
	bin_pop_str(packet, &vars);
	bin_pop_str(packet, &profiles);
	bin_pop_int(packet, &dlg->user_flags);
	bin_pop_int(packet, &dlg->mod_flags);

	bin_pop_int(packet, &rcv_flags);
	/* make sure an update received immediately after a create can't
	 * incorrectly erase the DLG_FLAG_NEW before locally writing to DB */
	save_new_flag = dlg->flags & DLG_FLAG_NEW;
	dlg->flags = rcv_flags;
	dlg->flags |= ((save_new_flag ? DLG_FLAG_NEW : 0) | DLG_FLAG_CHANGED);

	bin_pop_int(packet, &timeout);
	bin_skip_int(packet, 2);

	timeout -= time(0);
	LM_DBG("Received updated timeout of %d for dialog %.*s\n",
		timeout, call_id.len, call_id.s);

	if (dlg->lifetime != timeout) {
		dlg->lifetime = timeout;
		switch (update_dlg_timer(&dlg->tl, dlg->lifetime) ) {
		case -1:
			LM_ERR("failed to update dialog lifetime!\n");
			/* continue */
		case 0:
			/* timeout value was updated */
			break;
		case 1:
			/* dlg inserted in timer list with new expire (reference it)*/
			ref_dlg(dlg,1);
		}
	}

	unref_dlg_unsafe(dlg, 1, d_entry);

	if (vars.s && vars.len != 0)
		read_dialog_vars(vars.s, vars.len, dlg);

	dlg->flags |= DLG_FLAG_VP_CHANGED;

	dlg_unlock(d_table, d_entry);

	if (profiles.s && profiles.len != 0)
		read_dialog_profiles(profiles.s, profiles.len, dlg, 1, 1);

	return 0;

error:
	dlg_unlock(d_table, d_entry);
	return -1;
}
Ejemplo n.º 27
0
void rcv_cluster_event(enum clusterer_event ev, int node_id)
{
	struct dlg_sharing_tag *tag;
	struct n_send_info *ni;
	int lock_old_flag;
	struct dlg_cell *dlg, *next_dlg;
	int i;
	int ret;
	int unref;

	if (ev == SYNC_REQ_RCV && receive_sync_request(node_id) < 0)
		LM_ERR("Failed to reply to sync request from node: %d\n", node_id);
	else if (ev == SYNC_DONE) {
		if (dlg_db_mode == DB_MODE_NONE)
			return;
		/* drop dialogs loaded from DB which have not been reconfirmed
		 * through syncing or SIP(updates) */
		for (i = 0; i < d_table->size; i++) {
			dlg_lock(d_table, &d_table->entries[i]);
			dlg = d_table->entries[i].first;
			while (dlg) {
				if (!(dlg->flags & DLG_FLAG_FROM_DB)) {
					dlg = dlg->next;
					continue;
				}
				LM_DBG("Drop DB loaded dialog ID=%lld\n",
					((long long)dlg->h_entry << 32) | (dlg->h_id));

				unref = 1;  /* unref from hash */
				dlg->state = DLG_STATE_DELETED;

				destroy_linkers(dlg->profile_links, 0);
				dlg->profile_links = NULL;

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

				if (dlg_db_mode != DB_MODE_SHUTDOWN) {
					dlg->flags &= ~DLG_FLAG_NEW;
					remove_dialog_from_db(dlg);
					dlg->flags |= DLG_FLAG_DB_DELETED;
				}

				if (dlg_db_mode == DB_MODE_DELAYED)
					unref++;

				next_dlg = dlg->next;
				unref_dlg_unsafe(dlg, unref, &d_table->entries[i]);
				dlg = next_dlg;
			}
			dlg_unlock(d_table, &d_table->entries[i]);
		}
	} else if (ev == CLUSTER_NODE_UP) {
		lock_start_sw_read(shtags_lock);
		for (tag = *shtags_list; tag; tag = tag->next) {
			if (!tag->send_active_msg)
				continue;

			/* send sharing tag active msg to nodes to which we didn't already */
			for (ni = tag->active_msgs_sent; ni && ni->node_id != node_id;
				ni = ni->next) ;
			if (!ni) {
				if (send_shtag_active_info(&tag->name, node_id) < 0) {
					LM_ERR("Failed to send info about sharing tag\n");
					continue;
				}
				ni = shm_malloc(sizeof *ni);
				if (!ni) {
					LM_ERR("No more shm memory!\n");
					return;
				}
				ni->node_id = node_id;
				ni->next = tag->active_msgs_sent;
				lock_switch_write(shtags_lock, lock_old_flag);
				tag->active_msgs_sent = ni;
				lock_switch_read(shtags_lock, lock_old_flag);
			}
		}
		lock_stop_sw_read(shtags_lock);
	}
}
Ejemplo n.º 28
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;
}
Ejemplo n.º 29
0
int dlg_dmq_replicate_action(dlg_dmq_action_t action, dlg_cell_t* dlg,
		int needlock, dmq_node_t *node ) {

	srjson_doc_t jdoc, prof_jdoc;
	dlg_var_t *var;

	LM_DBG("replicating action [%d] on [%u:%u] to dmq peers\n", action,
			dlg->h_entry, dlg->h_id);

	if (action == DLG_DMQ_UPDATE) {
		if (!node && (dlg->iflags & DLG_IFLAG_DMQ_SYNC)
				&& ((dlg->dflags & DLG_FLAG_CHANGED_PROF) == 0)) {
			LM_DBG("dlg not changed, no sync\n");
			return 1;
		}
	} else if ( (dlg->iflags & DLG_IFLAG_DMQ_SYNC) == 0 ) {
		LM_DBG("dlg not synced, no sync\n");
		return 1;
	}
	if (action == DLG_DMQ_STATE && (dlg->state != DLG_STATE_CONFIRMED
				&& dlg->state != DLG_STATE_DELETED
				&& dlg->state != DLG_STATE_EARLY)) {
		LM_DBG("not syncing state %u\n", dlg->state);
		return 1;
	}

	srjson_InitDoc(&jdoc, NULL);

	jdoc.root = srjson_CreateObject(&jdoc);
	if(jdoc.root==NULL) {
		LM_ERR("cannot create json root\n");
		goto error;
	}

	if (needlock)
		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));

	srjson_AddNumberToObject(&jdoc, jdoc.root, "action", action);
	srjson_AddNumberToObject(&jdoc, jdoc.root, "h_entry", dlg->h_entry);
	srjson_AddNumberToObject(&jdoc, jdoc.root, "h_id", dlg->h_id);

	switch(action) {
		case DLG_DMQ_UPDATE:
			dlg->iflags |= DLG_IFLAG_DMQ_SYNC;
			dlg->dflags &= ~DLG_FLAG_CHANGED_PROF;
			srjson_AddNumberToObject(&jdoc, jdoc.root, "init_ts",
					dlg->init_ts);
			srjson_AddStrToObject(&jdoc, jdoc.root, "callid",
					dlg->callid.s, dlg->callid.len);

			srjson_AddStrToObject(&jdoc, jdoc.root, "from_uri",
					dlg->from_uri.s, dlg->from_uri.len);
			srjson_AddStrToObject(&jdoc, jdoc.root, "to_uri",
					dlg->to_uri.s, dlg->to_uri.len);
			srjson_AddStrToObject(&jdoc, jdoc.root, "req_uri",
					dlg->req_uri.s, dlg->req_uri.len);
			srjson_AddStrToObject(&jdoc, jdoc.root, "tag1",
					dlg->tag[0].s, dlg->tag[0].len);
			srjson_AddStrToObject(&jdoc, jdoc.root, "cseq1",
					dlg->cseq[0].s, dlg->cseq[0].len);
			srjson_AddStrToObject(&jdoc, jdoc.root, "route_set1",
					dlg->route_set[0].s, dlg->route_set[0].len);
			srjson_AddStrToObject(&jdoc, jdoc.root, "contact1",
					dlg->contact[0].s, dlg->contact[0].len);

			if (dlg->vars != NULL) {
				srjson_t *pj = NULL;
				pj = srjson_CreateObject(&jdoc);
                for(var=dlg->vars ; var ; var=var->next) {
					srjson_AddStrToObject(&jdoc, pj, var->key.s,
							var->value.s, var->value.len);
                }
                srjson_AddItemToObject(&jdoc, jdoc.root, "vars", pj);
			}

			if (dlg->profile_links) {
				srjson_InitDoc(&prof_jdoc, NULL);
				dlg_profiles_to_json(dlg, &prof_jdoc);
				if(prof_jdoc.buf.s!=NULL) {
					LM_DBG("adding profiles: [%.*s]\n",
							prof_jdoc.buf.len, prof_jdoc.buf.s);
					srjson_AddStrToObject(&jdoc, jdoc.root, "profiles",
							prof_jdoc.buf.s, prof_jdoc.buf.len);
					prof_jdoc.free_fn(prof_jdoc.buf.s);
					prof_jdoc.buf.s = NULL;
				}
				srjson_DestroyDoc(&prof_jdoc);
			}
			/* intentional fallthrough */

		case DLG_DMQ_STATE:
			srjson_AddNumberToObject(&jdoc, jdoc.root, "state", dlg->state);
			switch (dlg->state) {
				case DLG_STATE_EARLY:
					srjson_AddNumberToObject(&jdoc, jdoc.root, "start_ts",
							dlg->start_ts);
					srjson_AddNumberToObject(&jdoc, jdoc.root, "lifetime",
							dlg->lifetime);

					srjson_AddStrToObject(&jdoc, jdoc.root, "tag1",
							dlg->tag[0].s, dlg->tag[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "cseq1",
							dlg->cseq[0].s, dlg->cseq[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "route_set1",
							dlg->route_set[0].s, dlg->route_set[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "contact1",
							dlg->contact[0].s, dlg->contact[0].len);
					break;
				case DLG_STATE_CONFIRMED:
					srjson_AddNumberToObject(&jdoc, jdoc.root, "start_ts",
							dlg->start_ts);
					srjson_AddNumberToObject(&jdoc, jdoc.root, "lifetime",
							dlg->lifetime);

					srjson_AddStrToObject(&jdoc, jdoc.root, "tag1",
							dlg->tag[0].s, dlg->tag[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "tag2",
							dlg->tag[1].s, dlg->tag[1].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "cseq1",
							dlg->cseq[0].s, dlg->cseq[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "cseq2",
							dlg->cseq[1].s, dlg->cseq[1].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "route_set1",
							dlg->route_set[0].s, dlg->route_set[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "route_set2",
							dlg->route_set[1].s, dlg->route_set[1].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "contact1",
							dlg->contact[0].s, dlg->contact[0].len);
					srjson_AddStrToObject(&jdoc, jdoc.root, "contact2",
							dlg->contact[1].s, dlg->contact[1].len);

					break;
				case DLG_STATE_DELETED:
					//dlg->iflags &= ~DLG_IFLAG_DMQ_SYNC;
					break;
				default:
					LM_DBG("not syncing state %u\n", dlg->state);
			}
			break;

		case DLG_DMQ_RM:
			srjson_AddNumberToObject(&jdoc, jdoc.root, "state", dlg->state);
			dlg->iflags &= ~DLG_IFLAG_DMQ_SYNC;
			break;

		case DLG_DMQ_NONE:
		case DLG_DMQ_SYNC:
			break;
	}
	if (needlock)
		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));

	jdoc.buf.s = srjson_PrintUnformatted(&jdoc, jdoc.root);
	if(jdoc.buf.s==NULL) {
		LM_ERR("unable to serialize data\n");
		goto error;
	}
	jdoc.buf.len = strlen(jdoc.buf.s);
	LM_DBG("sending serialized data %.*s\n", jdoc.buf.len, jdoc.buf.s);
	if (dlg_dmq_send(&jdoc.buf, node)!=0) {
		goto error;
	}

	jdoc.free_fn(jdoc.buf.s);
	jdoc.buf.s = NULL;
	srjson_DestroyDoc(&jdoc);
	return 0;

error:
	if(jdoc.buf.s!=NULL) {
		jdoc.free_fn(jdoc.buf.s);
		jdoc.buf.s = NULL;
	}
	srjson_DestroyDoc(&jdoc);
	return -1;
}
Ejemplo n.º 30
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;
}