Ejemplo n.º 1
0
/*!
 * \brief add dlg structure to tm callbacks to wait for negative ACK
 * \param t current transaction
 * \param dlg current dialog
 * \return 0 on success, -1 on failure
 */
int dlg_set_tm_waitack(tm_cell_t *t, dlg_cell_t *dlg)
{
	dlg_iuid_t *iuid = NULL;
	if(t==NULL)
		return -1;

	LM_DBG("registering TMCB to wait for negative ACK\n");
	iuid = dlg_get_iuid_shm_clone(dlg);
	if(iuid==NULL)
	{
		LM_ERR("failed to create dialog unique id clone\n");
		goto error;
	}
	dlg_ref(dlg, 1);
	if ( d_tmb.register_tmcb( NULL, t,
			TMCB_DESTROY,
			dlg_ontdestroy, (void*)iuid, dlg_iuid_sfree)<0 ) {
		LM_ERR("failed to register TMCB to wait for negative ACK\n");
		dlg_unref(dlg, 1);
		goto error;
	}

	return 0;
error:
	dlg_iuid_sfree(iuid);
	return -1;
}
Ejemplo n.º 2
0
/*!
 * \brief add dlg structure to tm callbacks
 * \param t current transaction
 * \param req current sip request
 * \param dlg current dialog
 * \param smode if the sip request was spiraled
 * \return 0 on success, -1 on failure
 */
int dlg_set_tm_callbacks(tm_cell_t *t, sip_msg_t *req, dlg_cell_t *dlg,
		int smode)
{
	dlg_iuid_t *iuid = NULL;
	if(t==NULL)
		return -1;

	if(smode==0) {
		iuid = dlg_get_iuid_shm_clone(dlg);
		if(iuid==NULL)
		{
			LM_ERR("failed to create dialog unique id clone\n");
			goto error;
		}
		if ( d_tmb.register_tmcb( req, t,
				TMCB_RESPONSE_IN|TMCB_RESPONSE_READY|TMCB_RESPONSE_FWDED|TMCB_ON_FAILURE,
				dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) {
			LM_ERR("failed to register TMCB\n");
			goto error;
		}
	}

	dlg->dflags |= DLG_FLAG_TM;

	return 0;
error:
	dlg_iuid_sfree(iuid);
	return -1;
}
Ejemplo n.º 3
0
/*!
 * \brief Execute callback for the BYE request and register callback for the BYE reply
 * \param req request message
 * \param dlg corresponding dialog
 * \param dir message direction
 */
static void dlg_terminated(sip_msg_t *req, dlg_cell_t *dlg, unsigned int dir)
{
	dlg_iuid_t *iuid = NULL;

    if(!req) {
        LM_ERR("request is empty!");
        return;
    }

    if(!dlg) {
        LM_ERR("dialog is empty!");
        return;
    }

    /* dialog terminated (BYE) */
    run_dlg_callbacks(DLGCB_TERMINATED, dlg, req, NULL, dir, 0);

	iuid = dlg_get_iuid_shm_clone(dlg);
	if(iuid==NULL)
		return;

    /* register callback for the coresponding reply */
    if (d_tmb.register_tmcb(req,
                            0,
                            TMCB_RESPONSE_OUT,
                            dlg_terminated_confirmed,
                            (void*)iuid,
                            dlg_iuid_sfree) <= 0 ) {
        LM_ERR("cannot register response callback for BYE request\n");
        return;
    }
}
Ejemplo n.º 4
0
/* send keep-alive
 * dlg - pointer to a struct dlg_cell
 * dir - direction: the request will be sent to:
 * 		DLG_CALLER_LEG (0): caller
 * 		DLG_CALLEE_LEG (1): callee
 */
int dlg_send_ka(dlg_cell_t *dlg, int dir, str *hdrs)
{
	uac_req_t uac_r;
	dlg_t* di;
	str met = {"OPTIONS", 7};
	int result;
	dlg_iuid_t *iuid = NULL;

	/* do not send KA request for non-confirmed dialogs (not supported) */
	if (dlg->state != DLG_STATE_CONFIRMED) {
		LM_DBG("skipping non-confirmed dialogs\n");
		return 0;
	}

	/* build tm dlg by direction */
	if ((di = build_dlg_t(dlg, dir)) == 0){
		LM_ERR("failed to create dlg_t\n");
		goto err;
	}

	/* tm increases cseq value, decrease it no to make it invalid
	 * - dialog is ended on timeout (408) or C/L does not exist (481) */
	if(di->loc_seq.value>1)
		di->loc_seq.value -= 2;
	else
		di->loc_seq.value -= 1;

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

	iuid = dlg_get_iuid_shm_clone(dlg);
	if(iuid==NULL)
	{
		LM_ERR("failed to create dialog unique id clone\n");
		goto err;
	}

	memset(&uac_r,'\0', sizeof(uac_req_t));
	set_uac_req(&uac_r, &met, hdrs, NULL, di, TMCB_LOCAL_COMPLETED,
				dlg_ka_cb, (void*)iuid);
	result = d_tmb.t_request_within(&uac_r);

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

	free_tm_dlg(di);

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

err:
	if(di)
		free_tm_dlg(di);
	return -1;
}
Ejemplo n.º 5
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;
	dlg_iuid_t *iuid = NULL;

	/* do not send BYE request for non-confirmed dialogs (not supported) */
	if (cell->state != DLG_STATE_CONFIRMED_NA && cell->state != DLG_STATE_CONFIRMED) {
		LM_ERR("terminating non-confirmed dialogs not supported\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");

	iuid = dlg_get_iuid_shm_clone(cell);
	if(iuid==NULL)
	{
		LM_ERR("failed to create dialog unique id clone\n");
		goto err;
	}

	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*)iuid);
	result = d_tmb.t_request_within(&uac_r);

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

	free_tm_dlg(dialog_info);

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

err:
	if(dialog_info)
		free_tm_dlg(dialog_info);
	return -1;
}
Ejemplo n.º 6
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;
}