Ejemplo n.º 1
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);
	}
}
Ejemplo n.º 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;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/*!
 * \brief Cleanup a profile
 * \param msg SIP message
 * \param flags unused
 * \param param unused
 * \return 1
 */
int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
{
	dlg_cell_t *dlg;

	if(get_route_type()==LOCAL_ROUTE) {
		return 1;
	}

	current_dlg_msg_id = 0;
	current_dlg_msg_pid = 0;
	dlg = dlg_get_ctx_dialog();
	if (dlg!=NULL) {
		if(dlg->dflags & DLG_FLAG_TM) {
			dlg_unref(dlg, 1);
		} else {
			/* dialog didn't make it to tm */
			dlg_unref(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;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
struct dlg_cell *dlg_get_msg_dialog(sip_msg_t *msg)
{
	struct dlg_cell *dlg = NULL;
	str callid;
	str ftag;
	str ttag;
	unsigned int dir;

	/* Retrieve the current dialog */
	dlg = dlg_get_ctx_dialog();
	if (dlg != NULL )
		return dlg;

	if (pre_match_parse(msg, &callid, &ftag, &ttag, 0) < 0)
		return NULL ;
	dir = DLG_DIR_NONE;
	dlg = get_dlg(&callid, &ftag, &ttag, &dir);
	if (dlg == NULL ) {
		LM_DBG("dlg with callid '%.*s' not found\n",
				msg->callid->body.len, msg->callid->body.s);
		return NULL ;
	}
	return dlg;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
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;
}