示例#1
0
int dlg_cfg_cb(sip_msg_t *msg, unsigned int flags, void *cbp)
{
	dlg_cell_t *dlg;
	if(flags&POST_SCRIPT_CB) {
		dlg = dlg_get_ctx_dialog();
		if(dlg!=NULL) {
			if(_dlg_ctx.t==0 && (dlg->state==DLG_STATE_UNCONFIRMED
						|| _dlg_ctx.expect_t==1)) {
				if(_dlg_ctx.cpid!=0 && _dlg_ctx.cpid==my_pid()) {
					/* release to destroy dialog if created by this process
					 * and request was not forwarded */
					if(dlg->state==DLG_STATE_UNCONFIRMED) {
						LM_DBG("new dialog with no transaction after config"
									" execution\n");
					} else {
						LM_DBG("dialog with no expected transaction after"
								" config execution\n");
					}
					dlg_release(dlg);
				}
			}
			/* get ctx dlg increased ref count - release now */
			dlg_release(dlg);
		}
	}
	memset(&_dlg_ctx, 0, sizeof(dlg_ctx_t));

	return 1;
}
示例#2
0
static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
{
	dlg_cell_t *dlg = NULL;
	int n;

	dlg = dlg_get_ctx_dialog();
	if(dlg==NULL)
		return -1;
	
	n = (int)(long)side;
	if(n==1)
	{
		if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
			goto error;
		goto done;
	} else if(n==2) {
		if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
			goto error;
		goto done;
	} else {
		if(dlg_bye_all(dlg, NULL)!=0)
			goto error;
		goto done;
	}

done:
	dlg_release(dlg);
	return 1;

error:
	dlg_release(dlg);
	return -1;
}
示例#3
0
/*!
 * \brief Unset a dialog profile
 * \param msg SIP message
 * \param value value
 * \param profile dialog profile table
 * \return 1 on success, -1 on failure
 */
int unset_dlg_profile(sip_msg_t *msg, str *value,
		dlg_profile_table_t *profile)
{
	dlg_cell_t *dlg;
	dlg_profile_link_t *linker;
	dlg_profile_link_t *linker_prev;
	dlg_entry_t *d_entry;

	if (is_route_type(REQUEST_ROUTE)) {
		LM_ERR("dialog delete profile cannot be used in request route\n");
		return -1;
	}

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

	if (dlg==NULL) {
		LM_WARN("dialog is NULL for delete profile\n");
		return -1;
	}

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

found:
	/* table still locked */
	/* remove the linker element from dialog */
	if (linker_prev==NULL) {
		dlg->profile_links = linker->next;
	} else {
		linker_prev->next = linker->next;
	}
	linker->next = NULL;
	dlg_unlock( d_table, d_entry);
	/* remove linker from profile table and free it */
	destroy_linkers(linker);
	dlg_release(dlg);
	return 1;
}
示例#4
0
int	update_dlg_timeout(dlg_cell_t *dlg, int timeout)
{
	if(update_dlg_timer(&dlg->tl, timeout) < 0) {
		LM_ERR("failed to update dialog lifetime\n");
		dlg_release(dlg);
		return -1;
	} 

	dlg->lifetime = timeout;
	dlg->dflags |= DLG_FLAG_CHANGED;

	dlg_release(dlg);

	return 0;
}
示例#5
0
/*!
 * \brief Function that is registered as TM callback and called on requests
 * \see dlg_new_dialog
 * \param t transaction, used to created the dialog
 * \param type type of the entered callback
 * \param param saved dialog structure in the callback
 */
void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
{
	sip_msg_t *req = param->req;
	dlg_cell_t *dlg = NULL;

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

	dlg = dlg_get_ctx_dialog();

	if (dlg!=NULL) {
		if (!initial_cbs_inscript) {
			if (spiral_detected == 1)
				run_dlg_callbacks( DLGCB_SPIRALED, dlg,
						req, NULL, DLG_DIR_DOWNSTREAM, 0);
			else if (spiral_detected == 0)
				run_create_callbacks(dlg, req);
		}
	}
	if (dlg==NULL) {
		if((req->flags&dlg_flag)!=dlg_flag)
			return;
		dlg_new_dialog(req, t, 1);
		dlg = dlg_get_ctx_dialog();
	}
	if (dlg!=NULL) {
		dlg_set_tm_callbacks(t, req, dlg, spiral_detected);
		dlg_release(dlg);
	}
}
示例#6
0
static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
{
	dlg_ctx_t *dctx;
	dlg_cell_t *d;
	int val;
	int ret;

	if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
	{
		LM_ERR("no flag value\n");
		return -1;
	}
	if(val<0 || val>31)
		return -1;

	if ( (dctx=dlg_get_dlg_ctx())==NULL )
		return -1;

	d = dlg_get_by_iuid(&dctx->iuid);
	if(d!=NULL) {
		ret = (d->sflags&(1<<val))?1:-1;
		dlg_release(d);
		return ret;
	}
	return (dctx->flags&(1<<val))?1:-1;
}
示例#7
0
/**
 * run keep-alive list
 *
 */
int dlg_ka_run(ticks_t ti)
{
	dlg_ka_t *dka;
	dlg_cell_t *dlg;

	if(dlg_ka_interval<=0)
		return 0;

	while(1) {
		/* get head item */
		lock_get(dlg_ka_list_lock);
		if(*dlg_ka_list_head==NULL) {
			lock_release(dlg_ka_list_lock);
			return 0;
		}
		dka = *dlg_ka_list_head;
#if 0
		LM_DBG("dlg ka timer at %lu for"
				" dlg[%u,%u] on %lu\n", (unsigned long)ti,
				dka->iuid.h_entry, dka->iuid.h_id,
				(unsigned long)dka->katime);
#endif
		if(dka->katime>ti) {
			lock_release(dlg_ka_list_lock);
			return 0;
		}
		if(*dlg_ka_list_head == *dlg_ka_list_tail) {
			*dlg_ka_list_head = NULL;
			*dlg_ka_list_tail = NULL;
		}
		*dlg_ka_list_head = dka->next;
		lock_release(dlg_ka_list_lock);

		/* send keep-alive for dka */
		dlg = dlg_get_by_iuid(&dka->iuid);
		if(dlg==NULL) {
			shm_free(dka);
			dka = NULL;
		} else {
			if(dka->iflags & DLG_IFLAG_KA_SRC)
				dlg_send_ka(dlg, DLG_CALLER_LEG, 0);
			if(dka->iflags & DLG_IFLAG_KA_DST)
				dlg_send_ka(dlg, DLG_CALLEE_LEG, 0);
			dlg_release(dlg);
		}
		/* append to tail */
		if(dka!=NULL)
		{
			lock_get(dlg_ka_list_lock);
			if(*dlg_ka_list_tail!=NULL)
				(*dlg_ka_list_tail)->next = dka;
			if(*dlg_ka_list_head==NULL)
				*dlg_ka_list_head = dka;
			*dlg_ka_list_tail = dka;
			lock_release(dlg_ka_list_lock);
		}
	}

	return 0;
}
示例#8
0
/*!
 * \brief Helper function that run dialog callbacks on forwarded requests
 * \see dlg_seq_up_onreply
 * \see dlg_seq_down_onreply
 * \param t transaction, unused
 * \param type type of the callback, should be TMCB_RESPONSE_FWDED
 * \param param saved dialog structure inside the callback
 * \param direction direction of the request
 */
static void dlg_seq_onreply_helper(struct cell* t, int type,
		struct tmcb_params *param, const int direction)
{
	dlg_cell_t *dlg = NULL;
	dlg_iuid_t *iuid = NULL;

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

	if (type==TMCB_RESPONSE_FWDED)
	{
		run_dlg_callbacks( DLGCB_RESPONSE_WITHIN,
		                   dlg,
		                   param->req,
		                   param->rpl,
		                   direction,
		                   0);
	}
	dlg_release(dlg);

	return;
}
示例#9
0
int dlg_manage(sip_msg_t *msg)
{
	str tag;
	int backup_mode;
	dlg_cell_t *dlg = NULL;
	tm_cell_t *t = NULL;

	if( (msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL )
	{
		LM_ERR("bad TO header\n");
		return -1;
	}
	tag = get_to(msg)->tag_value;
	if(tag.s!=0 && tag.len!=0)
	{
		backup_mode = seq_match_mode;
		seq_match_mode = SEQ_MATCH_NO_ID;
		dlg_onroute(msg, NULL, NULL);
		seq_match_mode = backup_mode;
	} else {
		t = d_tmb.t_gett();
		if(t==T_UNDEFINED)
			t = NULL;
		if(dlg_new_dialog(msg, t, initial_cbs_inscript)!=0)
			return -1;
		dlg = dlg_get_ctx_dialog();
		if(dlg==NULL)
			return -1;
		if(t!=NULL)
			dlg_set_tm_callbacks(t, msg, dlg, spiral_detected);
		dlg_release(dlg);
	}
	return 1;
}
示例#10
0
/*!
 * \brief Function that executes BYE reply callbacks
 * \param t transaction, unused
 * \param type type of the callback, should be TMCB_RESPONSE_FWDED
 * \param params saved dialog structure inside the callback
 */
static void dlg_terminated_confirmed(tm_cell_t *t, int type,
                                     struct tmcb_params* params)
{
    dlg_cell_t *dlg = NULL;
	dlg_iuid_t *iuid = NULL;

    if(!params || !params->req || !params->param)
    {
        LM_ERR("invalid parameters!\n");
        return;
    }

	iuid = (dlg_iuid_t*)*params->param;
	if(iuid==NULL)
		return;

    dlg = dlg_get_by_iuid(iuid);

    if(dlg==NULL)
    {
        LM_ERR("failed to get dialog from params!\n");
        return;
    }
    /* dialog termination confirmed (BYE reply) */
    run_dlg_callbacks(DLGCB_TERMINATED_CONFIRMED,
                      dlg,
                      params->req,
                      params->rpl,
                      DLG_DIR_UPSTREAM,
                      0);
	dlg_release(dlg);
}
示例#11
0
static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
	unsigned int h_entry, h_id;
	dlg_cell_t * dlg = NULL;
	str rpc_extra_hdrs = {NULL,0};
	int n;

	n = rpc->scan(c, "dd", &h_entry, &h_id);
	if (n < 2) {
		LM_ERR("unable to read the parameters (%d)\n", n);
		rpc->fault(c, 500, "Invalid parameters");
		return;
	}
	if(rpc->scan(c, "*S", &rpc_extra_hdrs)<1)
	{
		rpc_extra_hdrs.s = NULL;
		rpc_extra_hdrs.len = 0;
	}

	dlg = dlg_lookup(h_entry, h_id);
	if(dlg==NULL) {
		rpc->fault(c, 404, "Dialog not found");
		return;
	}

	dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
	dlg_release(dlg);
}
示例#12
0
static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2)
{
	dlg_ctx_t *dctx;
	dlg_cell_t *d;
	str val;

	if(fixup_get_svalue(msg, (gparam_t*)prop, &val)!=0)
	{
		LM_ERR("no property value\n");
		return -1;
	}
	if(val.len<=0)
	{
		LM_ERR("empty property value\n");
		return -1;
	}
	if ( (dctx=dlg_get_dlg_ctx())==NULL )
		return -1;

	if(val.len==6 && strncmp(val.s, "ka-src", 6)==0) {
		dctx->iflags |= DLG_IFLAG_KA_SRC;
		d = dlg_get_by_iuid(&dctx->iuid);
		if(d!=NULL) {
			d->iflags |= DLG_IFLAG_KA_SRC;
			dlg_release(d);
		}
	} else if(val.len==6 && strncmp(val.s, "ka-dst", 6)==0) {
		dctx->iflags |= DLG_IFLAG_KA_DST;
		d = dlg_get_by_iuid(&dctx->iuid);
		if(d!=NULL) {
			d->iflags |= DLG_IFLAG_KA_DST;
			dlg_release(d);
		}
	} else if(val.len==15 && strncmp(val.s, "timeout-noreset", 15)==0) {
		dctx->iflags |= DLG_IFLAG_TIMER_NORESET;
		d = dlg_get_by_iuid(&dctx->iuid);
		if(d!=NULL) {
			d->iflags |= DLG_IFLAG_TIMER_NORESET;
			dlg_release(d);
		}
	} else {
		LM_ERR("unknown property value [%.*s]\n", val.len, val.s);
		return -1;
	}

	return 1;
}
示例#13
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);
}
示例#14
0
static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
{
	dlg_cell_t *dlg = NULL;
	str sc = {0,0};
	str sf = {0,0};
	str st = {0,0};
	unsigned int dir = 0;

	if(ci==0 || ft==0 || tt==0)
	{
		LM_ERR("invalid parameters\n");
		return -1;
	}

	if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
	{
		LM_ERR("unable to get Call-ID\n");
		return -1;
	}
	if(sc.s==NULL || sc.len == 0)
	{
		LM_ERR("invalid Call-ID parameter\n");
		return -1;
	}
	if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
	{
		LM_ERR("unable to get From tag\n");
		return -1;
	}
	if(sf.s==NULL || sf.len == 0)
	{
		LM_ERR("invalid From tag parameter\n");
		return -1;
	}
	if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
	{
		LM_ERR("unable to get To Tag\n");
		return -1;
	}
	if(st.s==NULL || st.len == 0)
	{
		LM_ERR("invalid To tag parameter\n");
		return -1;
	}

	dlg = get_dlg(&sc, &sf, &st, &dir);
	if(dlg==NULL)
		return -1;
    /* set shorcut to dialog internal unique id */
	_dlg_ctx.iuid.h_entry = dlg->h_entry;
	_dlg_ctx.iuid.h_id = dlg->h_id;
	_dlg_ctx.dir = dir;
	dlg_release(dlg);
	return 1;
}
示例#15
0
/*
 * Determine if message is in a dialog currently being tracked
 */
int	is_known_dlg(struct sip_msg *msg) {
	dlg_cell_t *dlg;

	dlg = dlg_get_msg_dialog(msg);
	
	if(dlg == NULL)
		return -1;

	dlg_release(dlg);

	return 1;
}
示例#16
0
static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
{
	dlg_cell_t *dlg;
	int n;
	str st = {0,0};

	dlg = dlg_get_ctx_dialog();
	if(dlg==NULL)
		return -1;
	
	n = (int)(long)side;

	if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
	{
		LM_ERR("unable to get To\n");
		goto error;
	}
	if(st.s==NULL || st.len == 0)
	{
		LM_ERR("invalid To parameter\n");
		goto error;
	}
	if(n==1)
	{
		if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
			goto error;
	} else {
		if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
			goto error;
	}

	dlg_release(dlg);
	return 1;

error:
	dlg_release(dlg);
	return -1;
}
示例#17
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;

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

	if (dlg == NULL) {
		LM_DBG("Error: Current dlg is null");

		return -1;
	}
	LM_DBG("Current dlg found");

        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) {
		LM_DBG("Running through linkers");
		if (linker->profile == profile) {
			LM_DBG("Profile matches");
			if (profile->has_value == 0) {
				LM_DBG("Profile has value is zero returning true");
				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) {
				LM_DBG("Profile has value equal to passed value returning true");
				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;
}
示例#18
0
/*!
 *
 */
dlg_cell_t *dlg_lookup_msg_dialog(sip_msg_t *msg, unsigned int *dir)
{
	dlg_cell_t *dlg = NULL;
	str callid;
	str ftag;
	str ttag;
	unsigned int vdir;

	/* Retrieve the current dialog */
	dlg = dlg_get_ctx_dialog();
	if(dlg!=NULL) {
		if(dir) {
			if (pre_match_parse(msg, &callid, &ftag, &ttag, 0)<0) {
				dlg_release(dlg);
				return NULL;
			}
			if (dlg->tag[DLG_CALLER_LEG].len == ftag.len &&
					   strncmp(dlg->tag[DLG_CALLER_LEG].s, ftag.s, ftag.len)==0 &&
					   strncmp(dlg->callid.s, callid.s, callid.len)==0) {
				*dir = DLG_DIR_DOWNSTREAM;
			} else {
				if (ttag.len>0 && dlg->tag[DLG_CALLER_LEG].len == ttag.len &&
						   strncmp(dlg->tag[DLG_CALLER_LEG].s, ttag.s, ttag.len)==0 &&
						   strncmp(dlg->callid.s, callid.s, callid.len)==0) {
					*dir = DLG_DIR_UPSTREAM;
				}
			}
		}
		return dlg;
	}
	
	if (pre_match_parse(msg, &callid, &ftag, &ttag, 0)<0)
		return NULL;
	vdir = DLG_DIR_NONE;
	dlg = get_dlg(&callid, &ftag, &ttag, &vdir);
	if (dlg==NULL){
		LM_DBG("dlg with callid '%.*s' not found\n",
				msg->callid->body.len, msg->callid->body.s);
		return NULL;
	}
	if(dir) *dir = vdir;
	return dlg;
}
示例#19
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;
}
示例#20
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;
}
示例#21
0
int	dlg_set_timeout_by_profile(struct dlg_profile_table *profile, 
				   str *value, int timeout) 
{
	unsigned int		i = 0;
	dlg_cell_t		*this_dlg = NULL;
	struct dlg_profile_hash	*ph = NULL;

	/* Private structure necessary for manipulating dialog 
         * timeouts outside of profile locks.  Admittedly, an
         * ugly hack, but avoids some concurrency issues.
         */

	struct dlg_map_list {
		unsigned int		h_id;
		unsigned int		h_entry;
		struct dlg_map_list	*next;
	} *map_head, *map_scan, *map_scan_next;

	map_head = NULL;

	/* If the profile has no value, iterate through every 
	 * node and set its timeout.
	 */

	if(profile->has_value == 0 || value == NULL) {
		lock_get(&profile->lock);

		for(i = 0; i < profile->size; i ++) {
			ph = profile->entries[i].first;

			if(!ph) continue;
			
			do { 
				struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list));

				if(!d)
					return -1;

				memset(d, 0, sizeof(struct dlg_map_list));

				d->h_id = ph->dlg->h_id;
				d->h_entry = ph->dlg->h_entry;

				if(map_head == NULL)
					map_head = d;
				else {
					d->next = map_head;
					map_head = d;
				}
	
				ph = ph->next;
			} while(ph != profile->entries[i].first);
		} 

		lock_release(&profile->lock);
	}

	else {
		i = calc_hash_profile(value, NULL, profile);

		lock_get(&profile->lock);

		ph = profile->entries[i].first;

		if(ph) {
			do {
				if(ph && value->len == ph->value.len &&
				   memcmp(value->s, ph->value.s, value->len) == 0) {
					struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list));

					if(!d)
						return -1;

					memset(d, 0, sizeof(struct dlg_map_list));

					d->h_id = ph->dlg->h_id;
					d->h_entry = ph->dlg->h_entry;

					if(map_head == NULL)
						map_head = d;
					else {
						d->next = map_head;
						map_head = d;
					}
				}

				ph = ph->next;
			} while(ph && ph != profile->entries[i].first);
		}

		lock_release(&profile->lock);
	}

	/* Walk the list and bulk-set the timeout */
	
	for(map_scan = map_head; map_scan != NULL; map_scan = map_scan_next) {
		map_scan_next = map_scan->next;

		this_dlg = dlg_lookup(map_scan->h_entry, map_scan->h_id);

		if(!this_dlg) {
			LM_CRIT("Unable to find dialog %d:%d\n", map_scan->h_entry, map_scan->h_id);
		} else if(this_dlg->state >= DLG_STATE_EARLY) {	
			if(update_dlg_timeout(this_dlg, timeout) < 0) {
               			LM_ERR("Unable to set timeout on %d:%d\n", map_scan->h_entry,
					map_scan->h_id);
			}

	                dlg_release(this_dlg);
		}

		free(map_scan);
	}

	return 0;
}
示例#22
0
int dlg_cseq_msg_sent(void *data)
{
	sip_msg_t msg;
	str *obuf;
	unsigned int direction;
	dlg_cell_t *dlg = NULL;
	str nval = STR_NULL;
	char tbuf[BUF_SIZE];
	int tbuf_len = 0;
	struct via_body *via;
	hdr_field_t *hfk = NULL;

	obuf = (str*)data;
	memset(&msg, 0, sizeof(sip_msg_t));
	msg.buf = obuf->s;
	msg.len = obuf->len;

	if(dlg_cseq_prepare_msg(&msg)!=0) {
		goto done;
	}

	if(msg.first_line.type==SIP_REPLY) {
		/* nothing to do for outgoing replies */
		goto done;
	}

	LM_DBG("traking cseq updates\n");
	via = (struct via_body*)msg.h_via1->parsed;

	if(via->branch==NULL || via->branch->value.len<=0) {
		LM_DBG("no branch parameter in top via\n");
		goto done;
	}

	direction = DLG_DIR_NONE;
	dlg = dlg_lookup_msg_dialog(&msg, &direction);

	if(dlg == NULL) {
		LM_DBG("no dialog for this request\n");
		goto done;
	}

	/* supported only for downstrem direction */
	if(direction != DLG_DIR_DOWNSTREAM) {
		LM_DBG("request not going downstream (%u)\n", direction);
		goto done;
	}

	/* check if transaction is marked for a new increment */
	if(get_cseq(&msg)->method_id!=METHOD_ACK) {
		parse_headers(&msg, HDR_EOH_F, 0);
		hfk = sr_hdr_get_z(&msg, "P-K-Auth-CSeq");
		if(hfk!=NULL) {
			LM_DBG("uac auth request - cseq inc needed\n");
			nval = hfk->body;
			trim(&nval);
		} else {
			LM_DBG("uac auth request - cseq inc not needed\n");
			goto done;
		}
	}

	if(nval.len<=0) {
		goto done;
	}

	if(msg.len + 3 + 2*nval.len>=BUF_SIZE) {
		LM_ERR("new messages is too big\n");
		goto done;
	}
	LM_DBG("updating cseq to: %.*s\n", nval.len, nval.s);

	/* new cseq value */
	dlg->iflags |= DLG_IFLAG_CSEQ_DIFF;

	if(via->branch->value.s<get_cseq(&msg)->number.s) {
		/* Via is before CSeq */
		/* copy first part till after via branch */
		tbuf_len = via->branch->value.s + via->branch->value.len - msg.buf;
		memcpy(tbuf, msg.buf, tbuf_len);
		/* complete via branch */
		tbuf[tbuf_len++] = '.';
		tbuf[tbuf_len++] = 'c';
		tbuf[tbuf_len++] = 's';
		memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len);
		tbuf_len += get_cseq(&msg)->number.len;
		/* copy till beginning of cseq number */
		memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
				get_cseq(&msg)->number.s - via->branch->value.s
				- via->branch->value.len);
		tbuf_len += get_cseq(&msg)->number.s - via->branch->value.s
					- via->branch->value.len;
		/* add new value */
		memcpy(tbuf+tbuf_len, nval.s, nval.len);
		tbuf_len += nval.len;
		if(hfk && hfk->name.s > get_cseq(&msg)->number.s) {
			/* copy from after cseq number to the beginning of hfk */
			memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
					hfk->name.s - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len);
			tbuf_len += hfk->name.s - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len;
			/* copy from after hfk to the end of sip message */
			memcpy(tbuf+tbuf_len,  hfk->name.s + hfk->len,
					msg.buf + msg.len - hfk->name.s - hfk->len);
			tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len;
		} else {
			/* copy from after cseq number to the end of sip message */
			memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
					msg.buf + msg.len - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len);
			tbuf_len += msg.buf+msg.len - get_cseq(&msg)->number.s
					- get_cseq(&msg)->number.len;
		}
	} else {
		/* CSeq is before Via */
		/* copy till beginning of cseq number */
		tbuf_len = get_cseq(&msg)->number.s - msg.buf;
		memcpy(tbuf, msg.buf, tbuf_len);
		/* add new value */
		memcpy(tbuf+tbuf_len, nval.s, nval.len);
		tbuf_len += nval.len;
		/* copy from after cseq number to the after via branch */
		memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s+get_cseq(&msg)->number.len,
				via->branch->value.s + via->branch->value.len
				- get_cseq(&msg)->number.s - get_cseq(&msg)->number.len);
		tbuf_len += via->branch->value.s + via->branch->value.len
				- get_cseq(&msg)->number.s - get_cseq(&msg)->number.len;
		/* complete via branch */
		tbuf[tbuf_len++] = '.';
		tbuf[tbuf_len++] = 'c';
		tbuf[tbuf_len++] = 's';
		memcpy(tbuf+tbuf_len, get_cseq(&msg)->number.s, get_cseq(&msg)->number.len);
		tbuf_len += get_cseq(&msg)->number.len;
		if(hfk && hfk->name.s > get_cseq(&msg)->number.s) {
			/* copy from after via to the beginning of hfk */
			memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
					hfk->name.s - via->branch->value.s
					- via->branch->value.len);
			tbuf_len += hfk->name.s - via->branch->value.s
					- via->branch->value.len;
			/* copy from after hfk to the end of sip message */
			memcpy(tbuf+tbuf_len,  hfk->name.s + hfk->len,
					msg.buf + msg.len - hfk->name.s - hfk->len);
			tbuf_len += msg.buf + msg.len - hfk->name.s - hfk->len;
		} else {
			/* copy from after via to the end of sip message */
			memcpy(tbuf+tbuf_len, via->branch->value.s + via->branch->value.len,
					msg.buf + msg.len - via->branch->value.s
					- via->branch->value.len);
			tbuf_len += msg.buf+msg.len - via->branch->value.s
					- via->branch->value.len;
		}
	}
	/* replace old msg content */
	obuf->s = pkg_malloc((tbuf_len+1)*sizeof(char));
	if(obuf->s==NULL) {
		LM_ERR("not enough memory for new message\n");
		goto done;
	}
	memcpy(obuf->s, tbuf, tbuf_len);
	obuf->s[tbuf_len] = 0;
	obuf->len = tbuf_len;

done:
	if(dlg!=NULL) dlg_release(dlg);
	free_sip_msg(&msg);
	return 0;
}
示例#23
0
/*parameters from MI: h_entry, h_id of the requested dialog*/
struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param ){

	struct mi_node* node;
	unsigned int h_entry, h_id;
	struct dlg_cell * dlg = NULL;
	str mi_extra_hdrs = {NULL,0};
	int status, msg_len;
	char *msg;


	if( d_table ==NULL)
		goto end;

	node = cmd_tree->node.kids;
	h_entry = h_id = 0;

	if (node==NULL || node->next==NULL)
		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);

	if (!node->value.s|| !node->value.len|| strno2int(&node->value,&h_entry)<0)
		goto error;

	node = node->next;
	if ( !node->value.s || !node->value.len || strno2int(&node->value,&h_id)<0)
		goto error;

	if (node->next) {
		node = node->next;
		if (node->value.len && node->value.s)
			mi_extra_hdrs = node->value;
	}

	LM_DBG("h_entry %u h_id %u\n", h_entry, h_id);

	dlg = dlg_lookup(h_entry, h_id);

	// lookup_dlg has incremented the reference count

	if(dlg){
		if(dlg_bye_all(dlg,(mi_extra_hdrs.len>0)?&mi_extra_hdrs:NULL)<0) {
			status = 500;
			msg = MI_DLG_OPERATION_ERR;
			msg_len = MI_DLG_OPERATION_ERR_LEN;
		} else {
			status = 200;
			msg = MI_OK_S;
			msg_len = MI_OK_LEN;
		}

		dlg_release(dlg);

		return init_mi_tree(status, msg, msg_len);
	}

end:
	return init_mi_tree(404, MI_DIALOG_NOT_FOUND, MI_DIALOG_NOT_FOUND_LEN);
	
error:
	return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);

}
示例#24
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;
}
示例#25
0
/*!
 * \brief Set a dialog profile
 * \param msg SIP message
 * \param value value
 * \param profile dialog profile table
 * \return 0 on success, -1 on failure
 */
int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
{
	dlg_cell_t *dlg = NULL;
	dlg_profile_link_t *linker;

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

	if (dlg==NULL && !is_route_type(REQUEST_ROUTE)) {
		LM_CRIT("BUG - dialog not found in a non REQUEST route (%d)\n",
			REQUEST_ROUTE);
		return -1;
	}

	/* build new linker */
	linker = (struct dlg_profile_link*)shm_malloc(
		sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
	if (linker==NULL) {
		LM_ERR("no more shm memory\n");
		goto error;
	}
	memset(linker, 0, sizeof(struct dlg_profile_link));

	/* set backpointers to profile and linker (itself) */
	linker->profile = profile;
	linker->hash_linker.linker = linker;

	/* set the value */
	if (profile->has_value) {
		linker->hash_linker.value.s = (char*)(linker+1);
		memcpy( linker->hash_linker.value.s, value->s, value->len);
		linker->hash_linker.value.len = value->len;
	}
	sruid_next_safe(&_dlg_profile_sruid);
	strcpy(linker->hash_linker.puid, _dlg_profile_sruid.uid.s);
	linker->hash_linker.puid_len = _dlg_profile_sruid.uid.len;

	if (dlg!=NULL) {
		/* add linker directly to the dialog and profile */
		link_dlg_profile( linker, dlg);
	} else {
		/* if existing linkers are not from current request, just discard them */
		if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
			current_dlg_msg_id = msg->id;
			current_dlg_msg_pid = msg->pid;
			destroy_linkers(current_pending_linkers);
			current_pending_linkers = NULL;
		}
		/* no dialog yet -> set linker as pending */
		if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
			current_dlg_msg_id = msg->id;
			current_dlg_msg_pid = msg->pid;
			destroy_linkers(current_pending_linkers);
		}

		linker->next = current_pending_linkers;
		current_pending_linkers = linker;
	}

	dlg_release(dlg);
	return 0;
error:
	dlg_release(dlg);
	return -1;
}
示例#26
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;
}
示例#27
0
int dlg_cseq_update(sip_msg_t *msg)
{
	dlg_cell_t *dlg = NULL;
	unsigned int direction;
	unsigned int ninc = 0;
	unsigned int vinc = 0;
	str nval;
	str *pval;

	if(dlg_cseq_prepare_msg(msg)!=0) {
		goto error;
	}
	if(msg->first_line.type==SIP_REPLY) {
		/* nothing to do for outgoing replies */
		goto done;
	}

	LM_DBG("initiating cseq updates\n");

	direction = DLG_DIR_NONE;
	dlg = dlg_lookup_msg_dialog(msg, &direction);

	if(dlg == NULL) {
		LM_DBG("no dialog for this request\n");
		goto done;
	}

	/* supported only for downstrem direction */
	if(direction != DLG_DIR_DOWNSTREAM) {
		LM_DBG("request not going downstream (%u)\n", direction);
		goto done;
	}

	ninc = 1;

	/* take the increment value from dialog */
	if((dlg->iflags&DLG_IFLAG_CSEQ_DIFF)==DLG_IFLAG_CSEQ_DIFF) {
		/* get dialog variable holding cseq diff */
		pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name);
		if(pval==NULL || pval->s==NULL || pval->len<=0) {
			LM_DBG("dialog marked with cseq diff but no variable set yet\n");
			goto done;
		}
		if(str2int(pval, &vinc)<0) {
			LM_ERR("invalid dlg cseq diff var value: %.*s\n",
					pval->len, pval->s);
			goto done;
		}
	}
	vinc += ninc;
	if(vinc==0) {
		LM_DBG("nothing to increment\n");
		goto done;
	}
	nval.s = int2str(vinc, &nval.len);
	if(set_dlg_variable(dlg, &_dlg_cseq_diff_var_name, &nval) <0) {
		LM_ERR("failed to set the dlg cseq diff var\n");
		goto done;
	}
	str2int(&get_cseq(msg)->number, &ninc);
	vinc += ninc;
	nval.s = int2str(vinc, &nval.len);
	trim(&nval);

	LM_DBG("adding auth cseq header value: %.*s\n", nval.len, nval.s);
	parse_headers(msg, HDR_EOH_F, 0);
	sr_hdr_add_zs(msg, "P-K-Auth-CSeq", &nval);

done:
	if(dlg!=NULL) dlg_release(dlg);
	return 0;

error:
	if(dlg!=NULL) dlg_release(dlg);
	return -1;
}
示例#28
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;
}
示例#29
0
int pv_get_dlg(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *res)
{
	dlg_cell_t *dlg = NULL;
	int res_type = 0;
	str sv = { 0 };
	unsigned int ui = 0;

	if(param==NULL)
		return -1;

	if(_dlg_ctx.iuid.h_id==0)
	{
		/* Retrieve the dialog for current message */
		dlg=dlg_get_msg_dialog(msg);
	} else {
		/* Retrieve the dialog for current context */
		dlg=dlg_get_by_iuid(&_dlg_ctx.iuid);
	}
	if(dlg == NULL)
		return pv_get_null(msg, param, res);

	switch(param->pvn.u.isname.name.n)
	{
		case 1:
			res_type = 1;
			ui = (unsigned int)dlg->h_id;
			break;
		case 2:
			res_type = 1;
			ui = (unsigned int)dlg->state;
			break;
		case 3:
			if(dlg->route_set[DLG_CALLEE_LEG].s==NULL
					|| dlg->route_set[DLG_CALLEE_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->route_set[DLG_CALLEE_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->route_set[DLG_CALLEE_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 4:
			res_type = 1;
			ui = (unsigned int)dlg->dflags;
			break;
		case 5:
			res_type = 1;
			ui = (unsigned int)dlg->sflags;
			break;
		case 6:
			if(dlg->callid.s==NULL
					|| dlg->callid.len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->callid.len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->callid.s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 7:
			if(dlg->to_uri.s==NULL
					|| dlg->to_uri.len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->to_uri.len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->to_uri.s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 8:
			if(dlg->tag[DLG_CALLEE_LEG].s==NULL
					|| dlg->tag[DLG_CALLEE_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->tag[DLG_CALLEE_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->tag[DLG_CALLEE_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 9:
			res_type = 1;
			ui = (unsigned int)dlg->toroute;
			break;
		case 10:
			if(dlg->cseq[DLG_CALLEE_LEG].s==NULL
					|| dlg->cseq[DLG_CALLEE_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->cseq[DLG_CALLEE_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->cseq[DLG_CALLEE_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 11:
			if(dlg->route_set[DLG_CALLER_LEG].s==NULL
					|| dlg->route_set[DLG_CALLER_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->route_set[DLG_CALLER_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->route_set[DLG_CALLER_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 12:
			if(dlg->from_uri.s==NULL
					|| dlg->from_uri.len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->from_uri.len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->from_uri.s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 13:
			if(dlg->tag[DLG_CALLER_LEG].s==NULL
					|| dlg->tag[DLG_CALLER_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->tag[DLG_CALLER_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->tag[DLG_CALLER_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 14:
			res_type = 1;
			ui = (unsigned int)dlg->lifetime;
			break;
		case 15:
			res_type = 1;
			ui = (unsigned int)dlg->start_ts;
			break;
		case 16:
			if(dlg->cseq[DLG_CALLER_LEG].s==NULL
					|| dlg->cseq[DLG_CALLER_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->cseq[DLG_CALLER_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->cseq[DLG_CALLER_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 17:
			if(dlg->contact[DLG_CALLEE_LEG].s==NULL
					|| dlg->contact[DLG_CALLEE_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->contact[DLG_CALLEE_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->contact[DLG_CALLEE_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 18:
			if(dlg->bind_addr[DLG_CALLEE_LEG]==NULL)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 19:
			if(dlg->contact[DLG_CALLER_LEG].s==NULL
					|| dlg->contact[DLG_CALLER_LEG].len<=0)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->contact[DLG_CALLER_LEG].len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->contact[DLG_CALLER_LEG].s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 20:
			if(dlg->bind_addr[DLG_CALLER_LEG]==NULL)
				goto done;
			sv.s = pv_get_buffer();
			sv.len = dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len;
			if(pv_get_buffer_size()<sv.len)
				goto done;
			res_type = 2;
			strncpy(sv.s, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s, sv.len);
			sv.s[sv.len] = '\0';
			break;
		case 21:
			res_type = 1;
			ui = (unsigned int)dlg->h_entry;
			break;
		default:
			res_type = 1;
			ui = (unsigned int)dlg->ref;
	}

done:
	dlg_release(dlg);

	switch(res_type) {
		case 1:
			return pv_get_uintval(msg, param, res, ui);
		case 2:
			return pv_get_strval(msg, param, res, &sv);
		default:
			return pv_get_null(msg, param, res);
	}
}