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

	dlg = get_dlg_tl_payload(tl);

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

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

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

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

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

	if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
		LM_DBG("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n",
			dlg->callid.len, dlg->callid.s,
			dlg->legs[DLG_CALLER_LEG].tag.len,
			dlg->legs[DLG_CALLER_LEG].tag.s,
			dlg->legs[callee_idx(dlg)].tag.len,
			ZSW(dlg->legs[callee_idx(dlg)].tag.s));

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

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

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

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

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

	return;
}
Beispiel #2
0
void dlg_ping_routine(unsigned int ticks , void * attr)
{
	struct dlg_ping_list *expired,*it,*curr;
	struct dlg_cell *dlg;

	expired = get_timeout_dlgs();

	it = expired;
	while (it) {
		dlg = it->dlg;
		LM_DBG("dialog %p has expired\n",dlg);
		curr = it->next;
		shm_free(it);
		dlg->pl = 0;
		it = curr;

		/* no longer reffed in list */
		unref_dlg(dlg,1);
		/* dlg is still reffed in TM callback. deletion from memory
		 * will happen only on 408 timeout */

		/* FIXME - maybe better not to send BYE both ways as we know for sure one
		 * end in down . */
		dlg_end_dlg(dlg,0);
	}

	/* ping_timer->first now contains all active dialogs */
	it = ping_timer->first;
	while (it) {
		dlg = it->dlg;

		/* do not ping ended dialogs */
		if (dlg->state != DLG_STATE_DELETED) {
			if (dlg->flags & DLG_FLAG_PING_CALLER) {
				ref_dlg(dlg,1);
				if (send_leg_msg(dlg,&options_str,callee_idx(dlg),
				DLG_CALLER_LEG,0,0,reply_from_caller,dlg,unref_dlg_cb) < 0) {
					LM_ERR("failed to ping caller\n");
					unref_dlg(dlg,1);
				}
			}

			if (dlg->flags & DLG_FLAG_PING_CALLEE) {
				ref_dlg(dlg,1);
				if (send_leg_msg(dlg,&options_str,DLG_CALLER_LEG,
				callee_idx(dlg),0,0,reply_from_callee,dlg,unref_dlg_cb) < 0) {
					LM_ERR("failed to ping callee\n");
					unref_dlg(dlg,1);
				}
			}
		}
		it = it->next;
	}
}
Beispiel #3
0
/* Wrapper for terminating dialog from API - from other modules */
static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
    unsigned int h_entry, h_id;
    struct dlg_cell * 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 = lookup_dlg(h_entry, h_id);//increments ref count!
    if(dlg==NULL) {
	    rpc->fault(c, 404, "Dialog not found");
	    return;
    }

    unref_dlg(dlg, 1);

    dlg_terminate(dlg, NULL, NULL/*reason*/, 2, NULL);

}
/**
 * replicates the remote deletion of a dialog locally
 * by reading the relevant information using the Binary Packet Interface
 */
int dlg_replicated_delete(void)
{
	str call_id, from_tag, to_tag;
	unsigned int dir, dst_leg;
	struct dlg_cell *dlg;
	int old_state, new_state, unref, ret;

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

	LM_DBG("Deleting dialog with callid: %.*s\n", call_id.len, call_id.s);

	dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg);
	if (!dlg) {
	        LM_ERR("dialog not found (callid: |%.*s| ftag: |%.*s|\n",
	                call_id.len, call_id.s, from_tag.len, from_tag.s);
	        return -1;
	}

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

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

	if (old_state == new_state) {
		LM_ERR("duplicate dialog delete request (callid: |%.*s|"
		       "ftag: |%.*s|\n", call_id.len, call_id.s, from_tag.len, from_tag.s);
		return -1;
	}

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

	unref_dlg(dlg, 1 + unref);
	if_update_stat(dlg_enable_stats, active_dlgs, -1);

	return 0;
}
Beispiel #5
0
void unreference_dialog(void *dialog)
{
	/* if the dialog table is gone, it means the system is shutting down.*/
	if (!d_table)
		return;
	unref_dlg((struct dlg_cell*)dialog, 1);
}
Beispiel #6
0
/*!
 * \brief Timer function that removes expired dialogs, run timeout route
 * \param tl dialog timer list
 */
void dlg_ontimeout(struct dlg_tl *tl) {
    struct dlg_cell *dlg;
    int new_state, old_state, unref;
    struct sip_msg *fmsg;

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

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

    if ((dlg->dflags & DLG_FLAG_TOBYE)
            && (dlg->state == DLG_STATE_CONFIRMED)) {
        //TODO: dlg_bye_all(dlg, NULL);
        unref_dlg(dlg, 1);
        return;
    }

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

    if (new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED) {
        LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s'\n",
                dlg->callid.len, dlg->callid.s,
                dlg->from_tag.len, dlg->from_tag.s);


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

        unref_dlg(dlg, unref + 1);
    } else {
        unref_dlg(dlg, 1);
    }

    return;
}
Beispiel #7
0
int dialog_cleanup( struct sip_msg *msg, void *param )
{
	if (current_processing_ctx && ctx_dialog_get()) {
		unref_dlg( ctx_dialog_get(), 1);
		ctx_dialog_set(NULL);
	}

	return SCB_RUN_ALL;
}
Beispiel #8
0
/* cell- pointer to a struct dlg_cell
 * leg - a dialog leg to be BYE'ed :
 *     = 0: caller leg
 *     > 0: callee legs
 */
static inline int send_leg_bye(struct dlg_cell *cell, int dst_leg, int src_leg,
														str *extra_hdrs)
{
	context_p old_ctx;
	context_p *new_ctx;
	dlg_t* dialog_info;
	str met = {"BYE", 3};
	int result;

	if ((dialog_info = build_dlg_t(cell, dst_leg, src_leg)) == 0){
		LM_ERR("failed to create dlg_t\n");
		goto err;
	}

	LM_DBG("sending BYE to %s (%d)\n",
		(dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg);

	/* set new processing context */
	if (push_new_processing_context( cell, &old_ctx, &new_ctx, NULL)!=0)
		goto err;

	ctx_lastdstleg_set(dst_leg);

	ref_dlg(cell, 1);

	result = d_tmb.t_request_within
		(&met,         /* method*/
		extra_hdrs,    /* extra headers*/
		NULL,          /* body*/
		dialog_info,   /* dialog structure*/
		bye_reply_cb,  /* callback function*/
		(void*)cell,   /* callback parameter*/
		NULL);         /* release function*/

	/* reset the processing contect */
	if (current_processing_ctx == NULL)
		*new_ctx = NULL;
	else
		context_destroy(CONTEXT_GLOBAL, *new_ctx);
	current_processing_ctx = old_ctx;

	if(result < 0){
		LM_ERR("failed to send the BYE request\n");
		goto err1;
	}

	free_tm_dlg(dialog_info);

	LM_DBG("BYE sent to %s\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee");
	return 0;

err1:
	unref_dlg(cell, 1);
err:
	return -1;
}
Beispiel #9
0
static void unreference_dialog_cseq(void *cseq_wrap)
{
	/* if the dialog table is gone, it means the system is shutting down.*/
	if (!d_table)
		return;

	dlg_cseq_wrapper *wrap = (dlg_cseq_wrapper *)cseq_wrap;
	unref_dlg(wrap->dlg, 1);
	shm_free(wrap);
}
Beispiel #10
0
static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
{
	struct dlg_cell *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;

        unref_dlg(dlg, 1);
        set_current_dialog(msg, dlg);
        _dlg_ctx.dlg = dlg;
        _dlg_ctx.dir = dir;
	return 1;
}
Beispiel #11
0
int dialog_cleanup( struct sip_msg *msg, void *param )
{
	if (current_dlg_pointer) {
		unref_dlg( current_dlg_pointer, 1);
		current_dlg_pointer = NULL;
	}
	last_dst_leg = -1;

	/* need to return non-zero - 0 will break the exec of the request */
	return 1;
}
Beispiel #12
0
int dlg_th_onroute(struct dlg_cell *dlg, struct sip_msg *req, int dir)
{
	struct hdr_field *it;
	char* buf = req->buf;

	/* delete vias */
	if(dlg_del_vias(req) < 0) {
		LM_ERR("Failed to remove via headers\n");
		return -1;
	}

	/* delete record route */
	for (it=req->record_route;it;it=it->sibling) {
		if (del_lump(req, it->name.s - buf, it->len,HDR_RECORDROUTE_T) == 0) {
			LM_ERR("del_lump failed\n");
			return -1;
		}
		LM_DBG("Delete record route: [%.*s]\n", it->len, it->name.s);
	}

	/* add route headers */
	fix_route_dialog(req, dlg);

	/* replace contact*/
	if(dlg_replace_contact(req, dlg) < 0) {
		LM_ERR("Failed to replace contact\n");
		return -1;
	}

	/* register tm callback for response in  */
	ref_dlg( dlg , 1);
	if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
			(dir==DLG_DIR_UPSTREAM)?dlg_th_down_onreply:dlg_th_up_onreply,
			(void*)dlg, unreference_dialog)<0 ) {
		LM_ERR("failed to register TMCB\n");
		unref_dlg( dlg , 1);
	}

	if (dir == DLG_DIR_UPSTREAM) {
		/* destination leg is the caller - force the send socket
		 * as the one the caller was inited from */
		req->force_send_socket = dlg->legs[DLG_CALLER_LEG].bind_addr;
		LM_DBG("forcing send socket for req going to caller\n");
	} else {
		/* destination leg is the callee - force the send socket
		 * as the one the callee was inited from */
		req->force_send_socket = dlg->legs[callee_idx(dlg)].bind_addr;
		LM_DBG("forcing send socket for req going to callee\n");
	}

	return 0;
}
Beispiel #13
0
/*!
 * \brief Cleanup a profile
 * \param msg SIP message
 * \param flags unused
 * \param unused
 * \return 1
 */
int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
{
    dlg_cell_t *dlg;

    current_dlg_msg_id = 0;
    current_dlg_msg_pid = 0;
    dlg = dlg_get_ctx_dialog();
    if (dlg != NULL) {
        if (dlg->dflags & DLG_FLAG_TM) {
            unref_dlg(dlg, 1);
        } else {
            /* dialog didn't make it to tm */
            unref_dlg(dlg, 2);
        }
    }
    if (current_pending_linkers) {
        destroy_linkers(current_pending_linkers);
        current_pending_linkers = NULL;
    }

    /* need to return non-zero - 0 will break the exec of the request */
    return 1;
}
Beispiel #14
0
/* Wrapper for terminating dialog from API - from other modules */
int w_api_lookup_terminate_dlg(unsigned int h_entry, unsigned int h_id, str *hdrs) {
    struct dlg_cell *dlg;

    dlg = lookup_dlg(h_entry, h_id); //increments ref count!

    if (!dlg) {
        LM_ERR("Asked to tear down non existent dialog\n");
        return -1;
    }

    unref_dlg(dlg, 1);

    return dlg_terminate(dlg, NULL, NULL/*reason*/, 2, hdrs);

}
Beispiel #15
0
str * api_get_dlg_variable(str *callid, str *ftag, str *ttag, str *key) {
    struct dlg_cell *dlg;
    
    unsigned int dir = DLG_DIR_NONE;
    dlg = get_dlg(callid, ftag, ttag, &dir); //increments ref count!
    
    if (!dlg) {
        LM_ERR("Asked to tear down non existent dialog\n");
        return NULL;
    }
    
    unref_dlg(dlg, 1);
    
    return get_dlg_variable(dlg, key);
}
Beispiel #16
0
/* Wrapper for terminating dialog from API - from other modules */
int w_api_terminate_dlg(str *callid, str *ftag, str *ttag, str *hdrs, str* reason) {
    struct dlg_cell *dlg;

    unsigned int dir = DLG_DIR_NONE;
    dlg = get_dlg(callid, ftag, ttag, &dir); //increments ref count!

    if (!dlg) {
        LM_ERR("Asked to tear down non existent dialog\n");
        return -1;
    }

    unref_dlg(dlg, 1);

    return dlg_terminate(dlg, NULL, NULL/*reason*/, 2, hdrs);

}
Beispiel #17
0
/* cell- pointer to a struct dlg_cell
 * leg - a dialog leg to be BYE'ed :
 *     = 0: caller leg
 *     > 0: callee legs
 */
static inline int send_leg_bye(struct dlg_cell *cell, int dst_leg, int src_leg,
														str *extra_hdrs)
{
	dlg_t* dialog_info;
	struct dlg_cell *old_cell;
	str met = {"BYE", 3};
	int result;

	if ((dialog_info = build_dlg_t(cell, dst_leg, src_leg)) == 0){
		LM_ERR("failed to create dlg_t\n");
		goto err;
	}

	LM_DBG("sending BYE to %s (%d)\n",
		(dst_leg==DLG_CALLER_LEG)?"caller":"callee", dst_leg);

	ref_dlg(cell, 1);

	old_cell = current_dlg_pointer;
	current_dlg_pointer = cell;

	result = d_tmb.t_request_within
		(&met,         /* method*/
		extra_hdrs,    /* extra headers*/
		NULL,          /* body*/
		dialog_info,   /* dialog structure*/
		bye_reply_cb,  /* callback function*/
		(void*)cell,   /* callback parameter*/
		NULL);         /* release function*/

	current_dlg_pointer = old_cell;

	if(result < 0){
		LM_ERR("failed to send the BYE request\n");
		goto err1;
	}

	free_tm_dlg(dialog_info);

	LM_DBG("BYE sent to %s\n", (dst_leg==DLG_CALLER_LEG)?"caller":"callee");
	return 0;

err1:
	unref_dlg(cell, 1);
err:
	return -1;
}
Beispiel #18
0
int dlg_th_onroute(struct dlg_cell *dlg, struct sip_msg *req, int dir)
{
	struct hdr_field *it;
	char* buf = req->buf;
	int leg_id;

	if(dir == DLG_DIR_UPSTREAM)
		leg_id = callee_idx(dlg);
	else
		leg_id = DLG_CALLER_LEG;

	/* delete vias */
	if(dlg_save_del_vias(req, &dlg->legs[leg_id]) < 0) {
		LM_ERR("Failed to save and remove via headers\n");
		return -1;
	}

	/* delete record route */
	for (it=req->record_route;it;it=it->sibling) {
		if (del_lump(req, it->name.s - buf, it->len,HDR_RECORDROUTE_T) == 0) {
			LM_ERR("del_lump failed \n");
			return -1;
		}
		LM_DBG("Delete record route: [%.*s]\n", it->len, it->name.s);
	}

	/* add route headers */
	fix_route_dialog(req, dlg);

	/* replace contact*/
	if(dlg_replace_contact(req, dlg) < 0) {
		LM_ERR("Failed to replace contact\n");
		return -1;
	}

	/* register tm callback for response in  */
	ref_dlg( dlg , 1);
	if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_FWDED,
			(dir==DLG_DIR_UPSTREAM)?dlg_th_down_onreply:dlg_th_up_onreply,
			(void*)dlg, unreference_dialog)<0 ) {
		LM_ERR("failed to register TMCB\n");
		unref_dlg( dlg , 1);
	}

	return 0;
}
Beispiel #19
0
/* cell- pointer to a struct dlg_cell
 * dir- direction: the request will be sent to:
 * 		DLG_CALLER_LEG (0): caller
 * 		DLG_CALLEE_LEG (1): callee
 */
static inline int send_bye(struct dlg_cell * cell, int dir, str *hdrs) {
    uac_req_t uac_r;
    dlg_t* dialog_info;
    str met = {"BYE", 3};
    int result;
    /* do not send BYE request for non-confirmed dialogs (not supported) */
    if (cell->state != DLG_STATE_CONFIRMED) {
        LM_ERR("terminating only 1 side of non-confirmed dialogs not supported by this function\n");
        return -1;
    }

    /*verify direction*/
    if ((dialog_info = build_dlg_t(cell, dir)) == 0) {
        LM_ERR("failed to create dlg_t\n");
        goto err;
    }

    LM_DBG("sending BYE to %s\n", (dir == DLG_CALLER_LEG) ? "caller" : "callee");

    ref_dlg(cell, 1);

    memset(&uac_r, '\0', sizeof (uac_req_t));
    set_uac_req(&uac_r, &met, hdrs, NULL, dialog_info, TMCB_LOCAL_COMPLETED,
            bye_reply_cb, (void*) cell);

    result = d_tmb.t_request_within(&uac_r);

    if (result < 0) {
        LM_ERR("failed to send the BYE request\n");
        goto err1;
    }

    free_tm_dlg(dialog_info);

    LM_DBG("BYE sent to %s\n", (dir == 0) ? "caller" : "callee");
    return 0;

err1:
    unref_dlg(cell, 1);
err:
    if (dialog_info)
        free_tm_dlg(dialog_info);
    return -1;
}
Beispiel #20
0
int register_dlgcb_nodlg(str *callid, str *ftag, str *ttag, 
                        int types, dialog_cb f,
                        void *param, param_free_cb ff )
{
    struct dlg_cell *dlg;
    
    unsigned int dir = DLG_DIR_NONE;
    dlg = get_dlg(callid, ftag, ttag, &dir); //increments ref count!
    
    if (!dlg) {
        LM_ERR("Can't find dialog to register callback\n");
        return -1;
    }
    
    int ret = register_dlgcb(dlg, types, f, param, ff);
    unref_dlg(dlg, 1);
    
    return ret;
}
Beispiel #21
0
int terminate_dlg(unsigned int h_entry, unsigned int h_id,str *reason)
{
	struct dlg_cell * dlg = NULL;
	int ret = 0;

	dlg = lookup_dlg(h_entry, h_id);

	if(!dlg)
		return 0;

	init_dlg_term_reason(dlg,reason->s,reason->len);

	if ( dlg_end_dlg( dlg, 0) ) {
		LM_ERR("Failed to end dialog");
		ret = -1;
	}

	unref_dlg(dlg, 1);
	return ret;
}
Beispiel #22
0
static int w_get_dlg_info(struct sip_msg *msg, char *attr, char *attr_val,
													char *key, char *key_val)
{
	struct dlg_cell *dlg;
	pv_elem_t *pve = (pv_elem_t *)key_val;
	pv_spec_t *dst = (pv_spec_t *)attr_val;
	pv_value_t val;
	str val_s;
	int n;

	if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
	val_s.len == 0 || val_s.s == NULL) {
		LM_WARN("cannot get string for value\n");
		return -1;
	}

	dlg = get_dlg_by_val( (str*)key, &val_s);

	if (dlg==NULL) {
		/* nothing found */
		LM_DBG("no dialog found\n");
		return -1;
	}

	/* dlg found - NOTE you have a ref! */
	LM_DBG("dialog found, fetching variable\n");

	if (fetch_dlg_value( dlg, (str*)attr, &val.rs, 0) ) {
		LM_DBG("failed to fetch dialog value <%.*s>\n",
			((str*)attr)->len, ((str*)attr)->s);
		n = -1 ;
	} else {
		val.flags = PV_VAL_STR;
		n = (dst->setf( msg, &dst->pvp, 0, &val )==0)?1:-1;
	}

	unref_dlg(dlg, 1);

	return n;
}
Beispiel #23
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 msg SIP message
 * \param t transaction
 * \return 0 on success, -1 on failure
 */
int dlg_new_dialog(struct sip_msg *req, struct cell *t, const int run_initial_cbs) {
    struct dlg_cell *dlg;
    str s;
    str callid;
    str ftag;
    str ttag;
    str req_uri;
    unsigned int dir;

    LM_DBG("starting dlg_new_dialog and method is [%.*s]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s);

    if (current_dlg_pointer != NULL)
        return -1;

    if (req->first_line.u.request.method_value == METHOD_CANCEL)
        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);

    if (detect_spirals) {
        if (spiral_detected == 1)
            return 0;

        dir = DLG_DIR_NONE;

        dlg = get_dlg(&callid, &ftag, &ttag, &dir);
        if (dlg) {
            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);

            //Add did to rr header for all spiralled requested INVITEs
            if (req->first_line.u.request.method_value == METHOD_INVITE) {
                if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) {
                    LM_ERR("failed to add RR param\n");

                }
            }

            // get_dlg has incremented the ref count by 1
            unref_dlg(dlg, 1);
            goto finish;
        }
    }
    spiral_detected = 0;


    LM_DBG("Building new Dialog for call-id %.*s\n", callid.len, callid.s);
    LM_DBG("SIP Method: %.*s  \n", req->first_line.u.request.method.len, req->first_line.u.request.method.s);
    dlg = build_new_dlg(&callid /*callid*/,
            &(get_from(req)->uri) /*from uri*/,
            &ftag/*from_tag*/,
            &req_uri /*r-uri*/);

    if (dlg == 0) {
        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) {
        LM_ERR("could not add further info to the dialog\n");
        lock_destroy(dlg->dlg_out_entries_lock);
        lock_dealloc(dlg->dlg_out_entries_lock);
        shm_free(dlg);
        return -1;
    }

    dlg->transaction = t;

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

    link_dlg(dlg, 0);
    if (run_initial_cbs) run_create_callbacks(dlg, req);

    //Dialog will *always* use DID cookie so no need for match mode anymore
    if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) {
        LM_ERR("failed to add RR param\n");
        goto error;
    }

    if (d_tmb.register_tmcb(req, t,
            TMCB_RESPONSE_READY | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_OUT,
            dlg_onreply, (void*) dlg, unref_new_dialog) < 0) {
        LM_ERR("failed to register TMCB\n");
        goto error;
    }
    // increase reference counter because of registered callback
    ref_dlg(dlg, 1);

    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;

    if (_dlg_ctx.to_bye != 0)
        dlg->dflags |= DLG_FLAG_TOBYE;

finish:
    if (t) {
        // transaction exists ==> keep ref counter large enough to
        // avoid premature cleanup and ensure proper dialog referencing
        if (store_dlg_in_tm(req, t, dlg) < 0) {
            LM_ERR("failed to store dialog in transaction\n");
            goto error;
        }
    } else {
        // no transaction exists ==> postpone work until we see the
        // request being forwarded statefully
        if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED,
                store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) {
            LM_ERR("failed to register callback for storing dialog in transaction\n");
            goto error;
        }
    }

    LM_DBG("Setting current dialog\n");
    set_current_dialog(req, dlg);
    _dlg_ctx.dlg = dlg;
    ref_dlg(dlg, 1);
    return 0;

error:
    LM_DBG("Error in build_new_dlg");
    if (!spiral_detected)
        unref_dlg(dlg, 1); // undo ref regarding linking
    return -1;
}
Beispiel #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) {
    struct dlg_cell *dlg;
    struct dlg_cell_out *dlg_out = 0;

    int new_state, old_state, unref, event;
    str to_tag, to_uri;
    struct sip_msg *req = param->req;
    struct sip_msg *rpl = param->rpl;
    struct dlg_entry_out* dlg_entry_out = 0;

    if (t && t->fwded_totags)
        LM_DBG("ONREPLY CALL_BACK from TM received and type is [%i] and TO is [%.*s]\n", type, t->fwded_totags->tag.len, t->fwded_totags->tag.s);
    else
        LM_DBG("ONREPLY CALL_BACK from TM received and type is [%i]\n", type);

    dlg = (struct dlg_cell *) (*param->param);
    if (shutdown_done || dlg == 0)
        return;

    if (t) {
        dlg->transaction = t;
    }

    LM_DBG("DLG dialogid is entry:id [%i:%i]\n", dlg->h_entry, dlg->h_id);

    if (type == TMCB_RESPONSE_FWDED) {
        // The state does not change, but the msg is mutable in this callback
        LM_DBG("TMCB_RESPONSE_FWDED from TM received");
        run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
        return;
    }

    if (type == TMCB_RESPONSE_OUT) {
        LM_DBG("TMCB_RESPONSE_OUT\n");
        return;
    }

    if (type == TMCB_RESPONSE_READY) {
        if (rpl == FAKED_REPLY) {
            LM_DBG("Faked reply\n");
            return;
        }

        // get to tag
        LM_DBG("Extracting to-tag from reply");
        if (!rpl->to && ((parse_headers(rpl, HDR_TO_F, 0) < 0) || !rpl->to)) {
            LM_ERR("bad reply or missing TO hdr :-/\n");
            to_tag.s = 0;
            to_tag.len = 0;
        } else {
            //populate to uri for this branch.
            to_uri = get_to(rpl)->uri;

            to_tag = get_to(rpl)->tag_value;
            if (to_tag.s == 0 || to_tag.len == 0) {
                LM_ERR("missing TAG param in TO hdr :-/\n");
                to_tag.s = 0;
                to_tag.len = 0;
                //Here we assume that the transaction module timer will remove any early dialogs
                return;
            }
        }

        LM_DBG("Got to-tag from response: %.*s \n", to_tag.len, to_tag.s);
    }

    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;

    LM_DBG("Calling next_state_dlg and event is %i\n", event);
    next_state_dlg(dlg, event, &old_state, &new_state, &unref, &to_tag);

    if (type == TMCB_RESPONSE_READY) {
        LM_DBG("Checking if there is an existing dialog_out entry with same to-tag");

        dlg_entry_out = &dlg->dlg_entry_out;

        lock_get(dlg->dlg_out_entries_lock);
        dlg_out = dlg_entry_out->first;

        LM_DBG("Scanning dlg_entry_out list for dlg_out");
        while (dlg_out) {
            //Check if there is an already dialog_out entry with same To-tag
            if (dlg_out->to_tag.len == to_tag.len &&
                    memcmp(dlg_out->to_tag.s, to_tag.s, dlg_out->to_tag.len) == 0) {
                //Found a dialog_out entry with same to_tag!
                LM_DBG("Found dlg_out for to-tag: %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s);
                break;
            }
            dlg_out = dlg_out->next;
        }
        lock_release(dlg->dlg_out_entries_lock);

        if (!dlg_out) {
            LM_DBG("No dlg_out entry found - creating a new dialog_out entry on dialog [%p]\n", dlg);
            dlg_out = build_new_dlg_out(dlg, &to_uri, &to_tag);

            link_dlg_out(dlg, dlg_out, 0);

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

            if (!dlg_out) {
                LM_ERR("failed to create new dialog out structure\n");
                //TODO do something on this error!

            }
        } else {
            //This dlg_out already exists, update cseq and contact if present

            LM_DBG("dlg_out entry found - updating cseq's for dialog out [%p] for to-tag [%.*s] \n", dlg_out, dlg_out->to_tag.len, dlg_out->to_tag.s);

            if ((!rpl->cseq && parse_headers(rpl, HDR_CSEQ_F, 0) < 0) || !rpl->cseq ||
                    !rpl->cseq->parsed) {
                LM_ERR("bad sip message or missing CSeq hdr :-/\n");
            }
            dlg_update_cseq(dlg, DLG_CALLEE_LEG, &((get_cseq(rpl))->number), &(dlg_out->to_tag));


            /* extract the contact address to update if present*/
            if (!rpl->contact && (parse_headers(rpl, HDR_CONTACT_F, 0) < 0 || !rpl->contact)) {
                LM_ERR("Can not update callee contact: bad sip message or missing Contact hdr\n");
            }
            else if (parse_contact(rpl->contact) < 0 ||
                    ((contact_body_t *) rpl->contact->parsed)->contacts == NULL ||
                    ((contact_body_t *) rpl->contact->parsed)->contacts->next != NULL) {
                LM_ERR("Can not update callee contact: bad Contact HDR\n");
            }
            else
            {
                str contact;
                contact = ((contact_body_t *) rpl->contact->parsed)->contacts->uri;
                dlg_update_contact(dlg, DLG_CALLEE_LEG, &contact, &(dlg_out->to_tag));
            }

        }
    }

    if (new_state == DLG_STATE_EARLY) {
        run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
        return;
    }

    LM_DBG("new state is %i and old state is %i\n", new_state, old_state);

    if ((new_state == DLG_STATE_CONFIRMED) && (event == DLG_EVENT_RPL2xx)) {
        LM_DBG("dialog %p confirmed \n", dlg);
        //Remove all the other entries in dialog_out for the same dialog after TM expires the transaction
        //(not before in order to absorb late in-early-dialog requests).

        //remove all other dlg_out objects
        if (dlg_out) {
            if (d_tmb.register_tmcb(req, NULL, TMCB_DESTROY, unlink_dlgouts_from_cb, (void*) dlg, NULL) < 0) {
                LM_ERR("failed to register deletion delay function\n");
                LM_DBG("Removing all other DLGs");
                dlg_remove_dlg_out(dlg_out, dlg, 0);
            } else {
                //mark the outs for deletion
                dlg_remove_dlg_out(dlg_out, dlg, 1);

            }
        } else {
            LM_ERR("There is no dlg_out structure - this is bad\n");
            //TODO: add error handling here
        }

        /* 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 (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' \n",
                    dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state,
                    dlg->callid.len, dlg->callid.s,
                    dlg->from_tag.len, dlg->from_tag.s);

        } else {
            ref_dlg(dlg, 1);
        }

        run_dlg_callbacks(DLGCB_CONFIRMED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);

        if (unref) unref_dlg(dlg, unref);
        return;
    }

    if (new_state == DLG_STATE_CONCURRENTLY_CONFIRMED && (old_state == DLG_STATE_CONFIRMED || old_state == DLG_STATE_CONCURRENTLY_CONFIRMED)) {
        //This is a concurrently confirmed call
        LM_DBG("This is a concurrently confirmed call.");
        //Create a new Dialog ID token “X”
        //Not sure how to do this so just going to use existing Did and add an X character to it
        str new_did;
        create_concurrent_did(dlg, &new_did);

        //assign new did to the created or updated dialog_out entry.
        update_dlg_out_did(dlg_out, &new_did);

        //Then, duplicate the dialog_in entry and set its Dialog ID value to new_did
        //for now rather just create new dlg structure with the correct params - this should be fixed if future use requires

        struct dlg_cell *new_dlg = 0;
        new_dlg = build_new_dlg(&(dlg->callid) /*callid*/,
                &(dlg->from_uri) /*from uri*/,
                &(dlg->from_tag)/*from_tag*/,
                &(dlg->req_uri) /*r-uri*/);

        //assign new did to dlg_in
        update_dlg_did(new_dlg, &new_did);

        if (new_dlg == 0) {
            LM_ERR("failed to create new dialog\n");
            return;
        }

        //link the new_dlg with dlg_out object
        link_dlg_out(new_dlg, dlg_out, 0);

    }

    if (old_state != DLG_STATE_DELETED && new_state == DLG_STATE_DELETED) {
        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);
        /* do unref */
        if (unref)
            unref_dlg(dlg, unref);

        return;
    }

    if (unref) unref_dlg(dlg, unref);

    return;
}
Beispiel #25
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) {
    struct dlg_cell *dlg;
    str val, callid, ftag, ttag;
    int h_entry, h_id, new_state, old_state, unref, event, timeout;
    unsigned int dir;
    int ret = 0;

    if (current_dlg_pointer != NULL)
        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 = lookup_dlg(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
                    unref_dlg(dlg, 1);
                    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\n",
                            dlg->callid.len, dlg->callid.s, dlg->callid.len,
                            dlg->from_tag.len, dlg->from_tag.s,
                            dlg->from_tag.len);
                    // lookup_dlg has incremented the ref count by 1
                    unref_dlg(dlg, 1);

                    // 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) {
            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.dlg = dlg;

    if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED,
            store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) {
        LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n");
    }

    /* 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, 0);

    LM_DBG("unref after next state is %i\n", unref);
    CURR_DLG_ID = req->id;
    CURR_DLG_LIFETIME = (unsigned int) (time(0)) - dlg->start_ts;
    CURR_DLG_STATUS = new_state;

    /* 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'\n",
                    dlg, dlg->h_entry, dlg->h_id,
                    dlg->callid.len, dlg->callid.s,
                    dlg->from_tag.len, dlg->from_tag.s);

        } else if (ret > 0) {
            LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
                    "with clid '%.*s' and tags '%.*s' \n",
                    dlg, dlg->h_entry, dlg->h_id,
                    dlg->callid.len, dlg->callid.s,
                    dlg->from_tag.len, dlg->from_tag.s);

        } else {
            unref++;
        }
        /* dialog terminated (BYE) */
        dlg_terminated(req, dlg, dir);
        unref_dlg(dlg, unref);

        return;
    }

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

        timeout = get_dlg_timeout(req);
        if (timeout != default_timeout) {
            dlg->lifetime = timeout;
        }
        if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) {
            LM_ERR("failed to update dialog lifetime\n");
        }
        if (update_cseqs(dlg, req, dir, &ttag) != 0) {
            LM_ERR("cseqs update failed\n");
        } else {
            dlg->dflags |= DLG_FLAG_CHANGED;
        }

        if (old_state != DLG_STATE_CONFIRMED) {
            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) {
                /* ref the dialog as registered into the transaction callback.
                 * unref will be done when the callback will be destroyed */
                ref_dlg(dlg, 1);
                /* 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*) dlg, unreference_dialog) < 0) {
                    LM_ERR("failed to register TMCB (2)\n");
                    unref_dlg(dlg, 1);
                }
            }
        }
    }

    if (new_state == DLG_STATE_CONFIRMED && old_state != DLG_STATE_CONFIRMED) {
        dlg->dflags |= DLG_FLAG_CHANGED;
    }
    return;
}
Beispiel #26
0
/**
 * replicates a confirmed dialog from another OpenSIPS instance
 * by reading the relevant information using the Binary Packet Interface
 */
int dlg_replicated_create(struct dlg_cell *cell, str *ftag, str *ttag, int safe)
{
	int next_id, h_entry;
	unsigned int dir, dst_leg;
	str callid, from_uri, to_uri, from_tag, to_tag;
	str cseq1,cseq2,contact1,contact2,rroute1,rroute2,mangled_fu,mangled_tu;
	str sock, vars, profiles;
	struct dlg_cell *dlg = NULL;
	struct socket_info *caller_sock, *callee_sock;
	struct dlg_entry *d_entry;

	if_update_stat(dlg_enable_stats, processed_dlgs, 1);

	LM_DBG("Received replicated dialog!\n");
	if (!cell) {
		bin_pop_str(&callid);
		bin_pop_str(&from_tag);
		bin_pop_str(&to_tag);
		bin_pop_str(&from_uri);
		bin_pop_str(&to_uri);

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

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

		if (safe)
			dlg_lock(d_table, d_entry);

		if (dlg) {
			LM_DBG("Dialog with ci '%.*s' is already created\n",
			       callid.len, callid.s);
			unref_dlg_unsafe(dlg, 1, d_entry);
			dlg_unlock(d_table, d_entry);
			return 0;
		}

		dlg = build_new_dlg(&callid, &from_uri, &to_uri, &from_tag);
		if (!dlg) {
			LM_ERR("Failed to create replicated dialog!\n");
			goto pre_linking_error;
		}
	} else {
		h_entry = dlg_hash(&cell->callid);
		d_entry = &d_table->entries[h_entry];

		if (safe)
			dlg_lock(d_table, d_entry);

		from_tag = *ftag;
		to_tag = *ttag;
		dlg = cell;
	}

	bin_pop_int(&dlg->h_id);
	bin_pop_int(&dlg->start_ts);
	bin_pop_int(&dlg->state);

	next_id = d_table->entries[dlg->h_entry].next_id;

	d_table->entries[dlg->h_entry].next_id =
		(next_id <= dlg->h_id) ? (dlg->h_id + 1) : next_id;

	if (bin_pop_str(&sock))
		goto pre_linking_error;

	caller_sock = fetch_socket_info(&sock);

	if (bin_pop_str(&sock))
		goto pre_linking_error;

	callee_sock = fetch_socket_info(&sock);

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

	bin_pop_str(&cseq1);
	bin_pop_str(&cseq2);
	bin_pop_str(&rroute1);
	bin_pop_str(&rroute2);
	bin_pop_str(&contact1);
	bin_pop_str(&contact2);
	bin_pop_str(&mangled_fu);
	bin_pop_str(&mangled_tu);

	/* add the 2 legs */
	if (dlg_add_leg_info(dlg, &from_tag, &rroute1, &contact1,
				&cseq1, caller_sock, 0, 0) != 0 ||
		dlg_add_leg_info(dlg, &to_tag, &rroute2, &contact2,
				&cseq2, callee_sock, &mangled_fu, &mangled_tu) != 0) {
		LM_ERR("dlg_set_leg_info failed\n");
		goto pre_linking_error;
	}

	dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG;

	/* link the dialog into the hash */
	dlg->h_id = d_entry->next_id++;
	if (!d_entry->first)
		d_entry->first = d_entry->last = dlg;
	else {
		d_entry->last->next = dlg;
		dlg->prev = d_entry->last;
		d_entry->last = dlg;
	}
	dlg->ref++;
	d_entry->cnt++;

	bin_pop_str(&vars);
	bin_pop_str(&profiles);
	bin_pop_int(&dlg->user_flags);
	bin_pop_int(&dlg->flags);
	bin_pop_int((void *)&dlg->tl.timeout);
	bin_pop_int(&dlg->legs[DLG_CALLER_LEG].last_gen_cseq);
	bin_pop_int(&dlg->legs[callee_idx(dlg)].last_gen_cseq);

	if (dlg->tl.timeout <= (unsigned int)time(0))
		dlg->tl.timeout = 0;
	else
		dlg->tl.timeout -= (unsigned int)time(0);

	/* restore the timer values */
	if (insert_dlg_timer(&dlg->tl, (int)dlg->tl.timeout) != 0) {
		LM_CRIT("Unable to insert dlg %p [%u:%u] "
			"with clid '%.*s' and tags '%.*s' '%.*s'\n",
			dlg, dlg->h_entry, dlg->h_id,
			dlg->callid.len, dlg->callid.s,
			dlg->legs[DLG_CALLER_LEG].tag.len,
			dlg->legs[DLG_CALLER_LEG].tag.s,
			dlg->legs[callee_idx(dlg)].tag.len,
			ZSW(dlg->legs[callee_idx(dlg)].tag.s));
		goto error;
	}

	if (dlg->state == DLG_STATE_CONFIRMED_NA ||
	    dlg->state == DLG_STATE_CONFIRMED)
		active_dlgs_cnt++;

	/* reference the dialog as kept in the timer list */
	ref_dlg_unsafe(dlg, 1);

	LM_DBG("Received initial timeout of %d for dialog %.*s, safe = %d\n",dlg->tl.timeout,callid.len,callid.s,safe);

	dlg->lifetime = 0;

	/*
	Do not replicate the pinging - we might terminate dialogs badly when running
	as backup 
	if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) {
		if (insert_ping_timer(dlg) != 0)
			LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg);
		else {
			ref_dlg_unsafe(dlg, 1);
		}
	}
	*/

	if (dlg_db_mode == DB_MODE_DELAYED) {
		/* to be later removed by timer */
		ref_dlg_unsafe(dlg, 1);
	}

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

	dlg_unlock(d_table, d_entry);

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

	if_update_stat(dlg_enable_stats, active_dlgs, 1);

	run_load_callback_per_dlg(dlg);

	return 0;

pre_linking_error:
	dlg_unlock(d_table, d_entry);
	if (dlg)
		destroy_dlg(dlg);
	return -1;

error:
	dlg_unlock(d_table, d_entry);
	if (dlg)
		unref_dlg(dlg, 1);

	return -1;
}
Beispiel #27
0
void unref_dlg_cb(void *dlg)
{
	if (!d_table)
		return;
	unref_dlg((struct dlg_cell*)dlg,1);
}
Beispiel #28
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;
	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 = lookup_dlg(h_entry, h_id);

	/* lookup_dlg has incremented the reference count !! */

	if(dlg){
		init_dlg_term_reason(dlg,"MI Termination",sizeof("MI Termination")-1);

		if ( dlg_end_dlg( dlg, mi_extra_hdrs) ) {
			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;
		}

		unref_dlg(dlg, 1);

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

}
Beispiel #29
0
/* TODO: add reason parameter to mi interface */
struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param) {

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

    str callid = {NULL, 0};
    str ftag = {NULL, 0};
    str ttag = {NULL, 0};

    if (d_table == NULL)
        goto end;

    node = cmd_tree->node.kids;

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

    if (!node->value.s || !node->value.len) {
        goto error;
    } else {
        callid = node->value;
    }
    node = node->next;
    if (!node->value.s || !node->value.len) {
        goto error;
    } else {
        ftag = node->value;
    }
    node = node->next;
    if (!node->value.s || !node->value.len) {
        goto error;
    } else {
        ttag = node->value;
    }

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

    unsigned int dir = DLG_DIR_NONE;
    LM_DBG("Looking for callid [%.*s]\n", callid.len, callid.s);
    dlg = get_dlg(&callid, &ftag, &ttag, &dir); //increments ref count!

    if (dlg) {
        LM_DBG("Found dialog to terminate and it is in state [%i]\n", dlg->state);

        if (dlg_terminate(dlg, 0, NULL/*reson*/, /* all sides of a dialog*/ 2, &mi_extra_hdrs) < 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;
        }
        unref_dlg(dlg, 1);

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

}
Beispiel #30
0
/*callback function to handle responses to the BYE request */
void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps) {

    struct dlg_cell* dlg;
    int event, old_state, new_state, unref, ret;
    struct dlg_cell_out *dlg_out = 0;

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

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

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

    dlg = (struct dlg_cell *) (*(ps->param));
    event = DLG_EVENT_REQBYE;

    //get the corresponding dlg out structure for this REQ
    struct dlg_entry_out *dlg_entry_out = &dlg->dlg_entry_out;
    lock_get(dlg->dlg_out_entries_lock);
    dlg_out = dlg_entry_out->first; //TODO check for concurrent call
    if (!dlg_out)
        return;

    next_state_dlg(dlg, event, &old_state, &new_state, &unref, &dlg_out->to_tag);

    lock_release(dlg->dlg_out_entries_lock);

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

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

        /* remove from timer */
        ret = remove_dialog_timer(&dlg->tl);
        if (ret < 0) {
            LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
                    "with clid '%.*s'\n",
                    dlg, dlg->h_entry, dlg->h_id,
                    dlg->callid.len, dlg->callid.s);
        } else if (ret > 0) {
            LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
                    "with clid '%.*s'\n",
                    dlg, dlg->h_entry, dlg->h_id,
                    dlg->callid.len, dlg->callid.s);
        } else {
            unref++;
        }
        /* dialog terminated (BYE) */
        run_dlg_callbacks(DLGCB_TERMINATED, dlg, ps->req, ps->rpl, DLG_DIR_NONE, 0);

        /* derefering the dialog */
        unref_dlg(dlg, unref + 1);
    }

    if (new_state == DLG_STATE_DELETED && old_state == DLG_STATE_DELETED) {
        /* trash the dialog from DB and memory */
        if (dlg_db_mode)
        	remove_dialog_in_from_db(dlg);

        /* force delete from mem */
        unref_dlg(dlg, 1);
    }

}