Example #1
0
static inline void acc_onack( struct cell* t, struct sip_msg *req,
		struct sip_msg *ack, int code)
{
	if (acc_preparse_req(ack)<0)
		return;

	/* set env variables */
	env_set_to( ack->to?ack->to:req->to );
	env_set_code_status( t->uas.status, 0 );

	if (is_log_acc_on(req)) {
		env_set_text( ACC_ACKED, ACC_ACKED_LEN);
		acc_log_request( ack );
	}
#ifdef SQL_ACC
	if (is_db_acc_on(req)) {
		if(acc_db_set_table_name(ack, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
			return;
		}
		acc_db_request( ack );
	}
#endif

/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(req)) {
		acc_diam_request(ack);
	}
#endif

	/* run extra acc engines */
	acc_run_engines(ack, 0, NULL);
	
}
Example #2
0
/* initiate a report if we previously enabled accounting for this t */
static void acc_onreply( struct cell* t, struct sip_msg *reply,
	int code, void *param )
{
	/* validation */
	if (t->uas.request==0) {
		DBG("DBG: acc: onreply: no uas.request, local t; skipping\n");
		return;
	}

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either
	*/
	on_missed(t, reply, code, param );

	if (!should_acc_reply(t, code)) return;
	if (is_log_acc_on(t->uas.request))
		acc_log_reply(t, reply, code);
#ifdef SQL_ACC
	if (is_db_acc_on(t->uas.request))
		acc_db_reply(t, reply, code);
#endif
#ifdef RAD_ACC
	if (is_rad_acc_on(t->uas.request))
		acc_rad_reply(t, reply, code);
#endif
}
Example #3
0
/* restore callbacks */
void acc_loaded_callback(struct dlg_cell *dlg, int type,
			struct dlg_cb_params *_params) {
		str flags_s, ctx_s, table_s;
		acc_ctx_t* ctx;

		if (!dlg) {
			LM_ERR("null dialog - cannot fetch message flags\n");
			return;
		}

		if (dlg_api.fetch_dlg_value(dlg, &flags_str, &flags_s, 0) < 0) {
			LM_DBG("flags were not saved in dialog\n");
			return;
		}

		/**
		 * restore acc extra context(extra and leg values)
		 */
		if (restore_dlg_extra(dlg, &ctx)) {
			LM_ERR("failed to rebuild acc context!\n");
			return;
		}

		/* copy flags value into the context */
		memcpy(&ctx->flags, flags_s.s, flags_s.len);

		/* restore accounting table if db accounting is used */
		if (is_db_acc_on(ctx->flags)) {
			if (dlg_api.fetch_dlg_value(dlg, &table_str, &table_s, 0) < 0) {
				LM_DBG("table was not saved in dialog\n");
				return;
			}

			if ((ctx->acc_table.s=shm_malloc(table_s.len)) == NULL) {
				LM_ERR("no more shm!\n");
				return;
			}

			memcpy(ctx->acc_table.s, table_s.s, table_s.len);
			ctx->acc_table.len = table_s.len;
		}



		/* replace the context value with a good pointer */
		ctx_s.s = (char *)&ctx;
		ctx_s.len = sizeof(acc_ctx_t *);
		if (dlg_api.store_dlg_value(dlg, &acc_ctx_str, &ctx_s) < 0) {
			LM_ERR("failed to set new context value!\n");
			return;
		}

		/* register database callbacks */
		if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED |
				DLGCB_EXPIRED, acc_dlg_callback, ctx, dlg_free_acc_ctx)){
			LM_ERR("cannot register callback for database accounting\n");
			return;
		}
}
Example #4
0
static void acc_dlg_onshutdown(struct dlg_cell *dlg, int type,
		struct dlg_cb_params *_params)
{
	str flags_s;
	acc_ctx_t* ctx;

	str created_s;

	if (!_params) {
		LM_ERR("not enough info!\n");
		return;
	}

	ctx = *_params->param;

	if (ctx->extra_values &&
		store_extra_values(ctx->extra_values, &extra_str, dlg) < 0) {
		LM_ERR("cannot store extra values!\n");
		return;
	}

	if (ctx->leg_values &&
		store_leg_values(ctx, &leg_str, dlg) < 0) {
		LM_ERR("cannot store leg values!\n");
		return;
	}

	flags_s.s = (char*)(&ctx->flags);
	flags_s.len = sizeof(unsigned long long);

	/* store flags into dlg */
	if ( dlg_api.store_dlg_value(dlg, &flags_str, &flags_s) < 0) {
		LM_ERR("cannot store flag value into dialog\n");
		return;
	}

	created_s.s = (char*)(&ctx->created);
	created_s.len = sizeof(time_t);

	if ( dlg_api.store_dlg_value(dlg,&created_str,&created_s) < 0) {
		LM_ERR("cannot store created value!\n");
		return;
	}

	if (is_db_acc_on(ctx->flags) && ctx->acc_table.s && ctx->acc_table.len) {
		if ( dlg_api.store_dlg_value(dlg, &table_str, &ctx->acc_table) < 0) {
			LM_ERR("cannot store table name into dialog\n");
			return;
		}
	}
}
Example #5
0
static void acc_dlg_callback(struct dlg_cell *dlg, int type,
		struct dlg_cb_params *_params)
{
	unsigned long long flags;

	if (!_params) {
		LM_ERR("not enough info\n");
		return;
	}

	flags = *((unsigned long long*)(*_params->param));

	if (is_evi_acc_on(flags)) {
		env_set_event(acc_cdr_event);
		if (acc_evi_cdrs(dlg, _params->msg) < 0) {
			LM_ERR("cannot send accounting events\n");
			return;
		}
	}

	if (is_log_acc_on(flags)) {
		env_set_text( ACC_ENDED, ACC_ENDED_LEN);
		if (acc_log_cdrs(dlg, _params->msg) < 0) {
			LM_ERR("Cannot log values\n");
			return;
		}
	}

	if (is_db_acc_on(flags)) {
		env_set_text( db_table_acc.s, db_table_acc.len);
		if (acc_db_cdrs(dlg, _params->msg) < 0) {
			LM_ERR("Cannot insert into database\n");
			return;
		}
	}

	if (is_aaa_acc_on(flags) && acc_aaa_cdrs(dlg, _params->msg) < 0) {
		LM_ERR("Cannot create radius accounting\n");
		return;
	}
}
Example #6
0
static void acc_cdr_cb( struct cell* t, int type, struct tmcb_params *ps )
{
	acc_ctx_t* ctx = *ps->param;
	struct dlg_cell *dlg;

	dlg = dlg_api.get_dlg();

	if (dlg == NULL) {
		LM_DBG("dlg is null!\n");
		return;
	}

	if (is_log_acc_on(ctx->flags)) {
		env_set_text( ACC_ENDED, ACC_ENDED_LEN);
		if (acc_log_cdrs(dlg, ps->req, ctx) < 0) {
			LM_ERR("Cannot log values\n");
			return;
		}
	}

	if (is_db_acc_on(ctx->flags)) {
		env_set_text( db_table_acc.s, db_table_acc.len);
		if (acc_db_cdrs(dlg, ps->req, ctx) < 0) {
			LM_ERR("Cannot insert into database\n");
			return;
		}
	}

	if (is_aaa_acc_on(ctx->flags) && acc_aaa_cdrs(dlg, ps->req, ctx) < 0) {
		LM_ERR("Cannot create radius accounting\n");
		return;
	}

	if (is_evi_acc_on(ctx->flags)) {
		env_set_event(acc_cdr_event);
		if (acc_evi_cdrs(dlg, ps->req, ctx) < 0) {
			LM_ERR("cannot send accounting events\n");
			return;
		}
	}
}
Example #7
0
static void acc_onack( struct cell* t , struct sip_msg *ack,
	int code, void *param )
{
	/* only for those guys who insist on seeing ACKs as well */
	if (!report_ack) return;
	/* if acc enabled for flagged transaction, check if flag matches */
	if (is_log_acc_on(t->uas.request)) {
		acc_preparse_req(ack);
		acc_log_ack(t, ack);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(t->uas.request)) {
		acc_preparse_req(ack);
		acc_db_ack(t, ack);
	}
#endif
#ifdef RAD_ACC
	if (is_rad_acc_on(t->uas.request)) {
		acc_preparse_req(ack);
		acc_rad_ack(t,ack);
	}
#endif
	
}
Example #8
0
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
											struct sip_msg *reply, int code)
{
	str new_uri_bk;
	str dst_uri_bk;
	struct dlg_cell *dlg = NULL;
	str flags_s;
	int_str table;
	struct usr_avp *avp;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	/* for reply processing, set as new_uri the winning branch */
	if (t->relaied_reply_branch>=0) {
		new_uri_bk = req->new_uri;
		dst_uri_bk = req->dst_uri;
		req->new_uri = t->uac[t->relaied_reply_branch].uri;
		req->dst_uri = t->uac[t->relaied_reply_branch].duri;
		req->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = dst_uri_bk.len = -1;
		new_uri_bk.s = dst_uri_bk.s = NULL;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	/* search for table avp */
	table.s = db_table_acc;
	if (db_table_name != -1 && is_db_acc_on(req)) {
		avp = search_first_avp(db_table_name_type, db_table_name, &table, 0);
		if (!avp) {
			LM_DBG("table not set: using default %.*s\n",
					db_table_acc.len, db_table_acc.s);
		} else {
			if (!(avp->flags & AVP_VAL_STR)) {
				LM_WARN("invalid integer table name: using default %.*s\n",
					db_table_acc.len, db_table_acc.s);
				table.s = db_table_acc;
			}
		}
	}

	if (is_invite(t) && is_cdr_acc_on(req) && code >= 200 && code < 300
			&& (dlg=dlg_api.get_dlg()) != NULL) {
		/* if dialog module loaded and INVITE and success reply */
		if (store_core_leg_values(dlg, req) < 0) {
			LM_ERR("cannot store core and leg values\n");
			return;
		}

		if(is_log_acc_on(req) && store_log_extra_values(dlg,req,reply)<0){
			LM_ERR("cannot store string values\n");
			return;
		}

		if(is_aaa_acc_on(req) && store_aaa_extra_values(dlg, req, reply)<0){
			LM_ERR("cannot store aaa extra values\n");
			return;
		}

		if (is_db_acc_on(req) && store_db_extra_values(dlg,req,reply)<0) {
			LM_ERR("cannot store database extra values\n");
			return;
		}

		flags_s.s = (char*)&req->flags;
		flags_s.len = sizeof(unsigned int);
		
		/* store flags into dlg */ 
		if ( dlg_api.store_dlg_value(dlg, &flags_str, &flags_s) < 0) {
			LM_ERR("cannot store flag value into dialog\n");
			return;
		}

		/* store flags into dlg */ 
		if ( dlg_api.store_dlg_value(dlg, &table_str, &table.s) < 0) {
			LM_ERR("cannot store the table name into dialog\n");
			return;
		}
		/* register database callbacks */
		if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED |
				DLGCB_EXPIRED, acc_dlg_callback,(void *)(long)req->flags,0) != 0) {
			LM_ERR("cannot register callback for database accounting\n");
			return;
		}
	} else {
		/* do old accounting */
		if ( is_log_acc_on(req) ) {
			env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
			acc_log_request( req, reply );
		}

		if (is_aaa_acc_on(req))
			acc_aaa_request( req, reply );
	
		if (is_db_acc_on(req)) {
			env_set_text( table.s.s, table.s.len);
			acc_db_request( req, reply, &acc_ins_list);
		}
	}

/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(req))
		acc_diam_request( req, reply );
#endif

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->dst_uri = dst_uri_bk;
		req->parsed_uri_ok = 0;
	}
}
Example #9
0
static void acc_dlg_callback(struct dlg_cell *dlg, int type,
		struct dlg_cb_params *_params)
{
	struct cell* t;
	acc_ctx_t* ctx;

	if (!_params) {
		LM_ERR("not enough info\n");
		return;
	}

	ctx = *_params->param;
	ACC_PUT_CTX(ctx);

	/**
	 * we've read the value of the flags
	 * increase the number of references to the shm memory pointer
	 * we know that this operation is atomic since the dialog callbacks
	 * are executed sequentially
	 */
	ACC_MASK_INC_REF(ctx->flags);
	LM_DBG("flags[%p] ref counter value after referencing [%llu]\n",
				*_params->param,
				ACC_MASK_GET_REF(ctx->flags));
	/*
	 * this way we "enable" the refcount
	 * if opensips shuts down before dialog terminated then the refcount
	 * won't be enabled
	 */
	set_dlg_cb_used(ctx->flags);

	/* this time will be used to set */
	gettimeofday(&ctx->bye_time, NULL);

	/* if it's not a local transaction we do the accounting on the tm callbacks */
	if (((t=tmb.t_gett()) == T_UNDEFINED) || !t ||
			(t != NULL && !tmb.t_is_local(_params->msg))) {
		/* normal dialogs will have to do accounting when the response for
		 * the bye will come since users should be able to populate extra
		 * vars and leg vars */
		if (tmb.register_tmcb( _params->msg, NULL,
						TMCB_RESPONSE_OUT, acc_cdr_cb, ctx, 0) < 0) {
			LM_ERR("failed to register cdr callback!\n");
			return;
		}
	/* for local transactions we do the accounting here since all the messages
	 * have been processed */
	} else if (t != NULL && tmb.t_is_local(_params->msg)) {
		/* expired dialogs will be handled here */
		if (is_log_acc_on(ctx->flags)) {
			env_set_text( ACC_ENDED, ACC_ENDED_LEN);
			if (acc_log_cdrs(dlg, _params->msg, ctx) < 0) {
				LM_ERR("Cannot log values\n");
				return;
			}
		}

		if (is_db_acc_on(ctx->flags)) {
			env_set_text( db_table_acc.s, db_table_acc.len);
			if (acc_db_cdrs(dlg, _params->msg, ctx) < 0) {
				LM_ERR("Cannot insert into database\n");
				return;
			}
		}

		if (is_aaa_acc_on(ctx->flags) && acc_aaa_cdrs(dlg, _params->msg, ctx) < 0) {
			LM_ERR("Cannot create radius accounting\n");
			return;
		}

		if (is_evi_acc_on(ctx->flags)) {
			env_set_event(acc_cdr_event);
			if (acc_evi_cdrs(dlg, _params->msg, ctx) < 0) {
				LM_ERR("cannot send accounting events\n");
				return;
			}
		}
	}

}
Example #10
0
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
					struct sip_msg *reply, int code, acc_ctx_t* ctx)
{
	str new_uri_bk;
	str dst_uri_bk;
	struct dlg_cell *dlg = NULL;
	str ctx_s;
	str table;

	unsigned long long* flags = &ctx->flags;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_acc_on(*flags) ) {
		on_missed(t, req, reply, code, ctx);
	}

	if (!should_acc_reply(req, reply, code, flags))
		return;

	/* for reply processing, set as new_uri the winning branch */
	if (t->relaied_reply_branch>=0) {
		new_uri_bk = req->new_uri;
		dst_uri_bk = req->dst_uri;
		req->new_uri = t->uac[t->relaied_reply_branch].uri;
		req->dst_uri = t->uac[t->relaied_reply_branch].duri;
		req->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = dst_uri_bk.len = -1;
		new_uri_bk.s = dst_uri_bk.s = NULL;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	/* search for table avp */
	if (is_db_acc_on(ctx->flags))
		table = ctx->acc_table;
	else {
		table.s = 0;
		table.len = 0;
	}

	if (is_invite(t) && !has_totag(req) && is_cdr_acc_on(ctx->flags) &&
			code >= 200 && code < 300 && (dlg=dlg_api.get_dlg()) != NULL) {
		/* if dialog module loaded and INVITE and success reply */
		if (store_core_leg_values(dlg, req) < 0) {
			LM_ERR("cannot store core and leg values\n");
			return;
		}

		ctx_s.s = (char*)&ctx;
		ctx_s.len = sizeof(acc_ctx_t *);

		/* store context pointer into dialog */
		if (dlg_api.store_dlg_value(dlg, &acc_ctx_str, &ctx_s) < 0) {
			LM_ERR("cannot store context pointer into dlg val!\n");
			return;
		}

		/* report that flags shall be freed only by dialog module
		 * tm must never free it */
		set_dialog_context(*flags);

		/* register program shutdown callback
		 * won't register free function since TERMINATED|EXPIRED callback
		 * free function will be called to free */
		if (dlg_api.register_dlgcb(dlg, DLGCB_DB_WRITE_VP,
					acc_dlg_onshutdown, ctx, NULL) != 0) {
			LM_ERR("cannot register callback for program shutdown!\n");
			return;
		}

		/* register database callbacks */
		if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED|DLGCB_EXPIRED,
								acc_dlg_callback, ctx, dlg_free_acc_ctx) != 0) {
			LM_ERR("cannot register callback for database accounting\n");
			return;
		}
	} else {
		/* do old accounting */
		if ( is_evi_acc_on(*flags) ) {
			env_set_event(acc_event);
			acc_evi_request( req, reply, 0 );
		}

		if ( is_log_acc_on(*flags) ) {
			env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
			acc_log_request( req, reply, 0 );
		}

		if (is_aaa_acc_on(*flags))
			acc_aaa_request( req, reply, 0 );

		if (is_db_acc_on(*flags)) {
			env_set_text( table.s, table.len);
			acc_db_request( req, reply, &acc_ins_list, 0);
		}
	}

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->dst_uri = dst_uri_bk;
		req->parsed_uri_ok = 0;
	}
}
Example #11
0
int w_do_acc_3(struct sip_msg* msg, char* type_p, char* flags_p, char* table_p)
{
	unsigned long long type=0, flags=0;
	unsigned long long flag_mask;

	acc_ctx_t* acc_ctx;

	acc_type_param_t* acc_param;

	str in;
	str table_name;

	int tmcb_types;
	int is_invite;

	if (type_p == NULL) {
		LM_ERR("accounting type is mandatory!\n");
		return -1;
	}

	acc_param = (acc_type_param_t *)type_p;
	if (acc_param->t == DO_ACC_PARAM_TYPE_VALUE) {
		type = acc_param->u.ival;
	} else {
		if (pv_printf_s(msg, acc_param->u.pval, &in) < 0) {
			LM_ERR("failed to fetch type value!\n");
			return -1;
		}

		if ((type=do_acc_parse(&in, do_acc_type_parser)) == DO_ACC_ERR) {
			LM_ERR("Invalid expression <%.*s> for acc type!\n", in.len, in.s);
			return -1;
		}
	}

	if (table_p != NULL) {
		if (fixup_get_svalue(msg, (gparam_p)table_p, &table_name) < 0) {
			LM_ERR("failed to fetch table name!\n");
			return -1;
		}
	}

	if (flags_p != NULL) {
		flags= *(unsigned long long*)flags_p;
	}

	flag_mask = type + type * flags;
	if (is_cdr_acc_on(flag_mask)) {
		/* setting this flag will allow us to register everything
		 * that is needed for CDR accounting only once */
		set_cdr_values_registered(flag_mask);
	}

	/* is it the first time when the function was called ? */
	acc_ctx = try_fetch_ctx();

	/* we go in here only if do_accounting function was called before;
	 * if accounting context is null or it's created but flags value is
	 * 0(meaning that context was created from somewhere else but do_accounting
	 * wasn't called)  then we need to jump over this and register
	 * all the callbacks we need */
	if (acc_ctx != NULL  && acc_ctx->flags != 0) {
		/* do_accounting already called once */
		/* first check if the accounting table changed  */
		if (is_db_acc_on(flag_mask) &&
				(table_p != NULL ||
				(acc_ctx->acc_table.s==NULL && acc_ctx->acc_table.len == 0))) {
			if (table_p == NULL) {
				table_name = db_table_acc;
			}

			if (store_acc_table( acc_ctx, &table_name) < 0) {
				LM_ERR("failed to store acc table!\n");
				return -1;
			}
		}

		if (!cdr_values_registered(acc_ctx->flags) &&
				cdr_values_registered(flag_mask)) {
			/* CDR support requested for the first time, we need to create
			 * the dialog support, if an initial INVITE */
			if (!has_totag(msg)) {
				acc_ctx->created = time(NULL);

				if (msg->REQ_METHOD == METHOD_INVITE && create_acc_dlg(msg) < 0) {
					LM_ERR("cannot use dialog accounting module\n");
					return -1;
				}
			}
		}

		/* if it's the first time the missed calls flag was used register the callback */
		if (is_mc_acc_on(flag_mask) && !failure_cb_registered(acc_ctx->flags)) {
			if (tmb.register_tmcb( msg, 0, TMCB_ON_FAILURE, tmcb_func, acc_ctx, 0)<=0) {
				LM_ERR("cannot register missed calls callback\n");
				return -1;
			}

			/* don't allow the callback to be registered agian in the future */
			set_failure_cb_registered(acc_ctx->flags);
		}

		acc_ctx->flags |= flag_mask;
		return 1;
	}

	/* initialize accounting context if not created before */
	if (acc_ctx == NULL && init_acc_ctx(&acc_ctx) < 0) {
		LM_ERR("failed to create accounting context!\n");
		return -1;
	}

	/* move acc table in context if we have database accounting */
	if (is_db_acc_on(flag_mask)) {
		if (table_p == NULL) {
			table_name = db_table_acc;
		}

		if (store_acc_table( acc_ctx, &table_name) < 0) {
			LM_ERR("failed to store acc table!\n");
			return -1;
		}
	}


	/*
	 * the first bit in each byte will just tell that we want that type of
	 * accounting
	 * next bits will tell extra options for that type of accounting
	 * so we keep the first bits in each byte and on the following positions
	 * next flags
	 */
	acc_ctx->flags = flag_mask;

	/* make sure that context won't be freed by GLOBAL_CONTEXT free function */
	acc_ctx->flags |= ACC_PROCESSING_CTX_NO_FREE;
	ACC_PUT_CTX(acc_ctx);

	if ( msg && !skip_cancel(msg) &&
	(is_acc_on(acc_ctx->flags) || is_mc_acc_on(acc_ctx->flags)) ) {
		/* do some parsing in advance */
		if (acc_preparse_req(msg)<0)
			return -1;
		is_invite = (msg->REQ_METHOD==METHOD_INVITE)?1:0;
		/* install additional handlers */
		tmcb_types =
			/* report on completed transactions */
			TMCB_RESPONSE_IN;

		if (is_invite && is_mc_acc_on(acc_ctx->flags)) {
			/* register it manually; see explanation below
			 * get incoming replies ready for processing */
			/* TMCB_RESPONSE_OUT | */
			/* report on missed calls */
			tmcb_types |= TMCB_ON_FAILURE;
			/* the flag will help on further do_accounting calls to know
			 * not to register the callback twice */
			set_failure_cb_registered(acc_ctx->flags);
		}

		/* if cdr accounting is enabled */
		if (is_cdr_acc_on(acc_ctx->flags) && !has_totag(msg)) {
			acc_ctx->created = time(NULL);

			if (is_invite && create_acc_dlg(msg) < 0) {
				LM_ERR("cannot use dialog accounting module\n");
				return -1;
			}
		}

		/* we do register_tmcb twice because we want to register the free
		 * function only once */
		if (tmb.register_tmcb( msg, 0, TMCB_RESPONSE_OUT, tmcb_func,
				acc_ctx, tm_free_acc_ctx)<=0) {
			LM_ERR("cannot register additional callbacks\n");
			return -1;
		}

		if (tmb.register_tmcb( msg, 0, tmcb_types, tmcb_func,
				acc_ctx, 0)<=0) {
			LM_ERR("cannot register additional callbacks\n");
			return -1;
		}

		/* if required, determine request direction */
		if( detect_direction && !rrb.is_direction(msg,RR_FLOW_UPSTREAM) ) {
			LM_DBG("detected an UPSTREAM req -> flaging it\n");
			msg->msg_flags |= FL_REQ_UPSTREAM;
		}
	}

	return 1;
}
Example #12
0
static void acc_dlg_ended(struct dlg_cell *dlg, int type,
		struct dlg_cb_params *_params)
{
	struct cell* t;
	acc_ctx_t* ctx;

	if (!_params) {
		LM_ERR("not enough info\n");
		return;
	}

	/* resolve local/dlg ctx conflict by merging them together */
	acc_merge_contexts(dlg, type, _params);
	ctx = (acc_ctx_t *)(*_params->param);

	/*
	 * this way we "enable" the refcount
	 * if opensips shuts down before dialog terminated then the refcount
	 * won't be enabled
	 */
	if (was_dlg_cb_used(ctx->flags)) {
		LM_INFO("CDR callback already registered [%p|%u] - do not run it again!\n",
				*_params->param, ctx->ref_no);
		return;
	}
	set_dlg_cb_used(ctx->flags);

	/* this time will be used to set */
	gettimeofday(&ctx->bye_time, NULL);

	/* if it's not a local transaction we do the accounting on the tm callbacks */
	if (((t=tmb.t_gett()) == T_UNDEFINED) || !t ||
			!tmb.t_is_local(_params->msg)) {
		/* normal dialogs will have to do accounting when the response for
		 * the bye will come since users should be able to populate extra
		 * vars and leg vars */
		acc_ref(ctx);
		if (tmb.register_tmcb( _params->msg, NULL,
						TMCB_RESPONSE_OUT, acc_cdr_cb, ctx, unref_acc_ctx) < 0) {
			acc_unref(ctx);
			LM_ERR("failed to register cdr callback!\n");
			return;
		}
	/* for local transactions we do the accounting here since all the messages
	 * have been processed */
	} else {
		/* expired dialogs will be handled here */
		if (is_log_acc_on(ctx->flags)) {
			env_set_text( ACC_ENDED, ACC_ENDED_LEN);
			if (acc_log_cdrs(dlg, _params->msg, ctx) < 0) {
				LM_ERR("Cannot log values\n");
				return;
			}
		}

		if (is_db_acc_on(ctx->flags)) {
			env_set_text( db_table_acc.s, db_table_acc.len);
			if (acc_db_cdrs(dlg, _params->msg, ctx) < 0) {
				LM_ERR("Cannot insert into database\n");
				return;
			}
		}

		if (is_aaa_acc_on(ctx->flags) && acc_aaa_cdrs(dlg, _params->msg, ctx) < 0) {
			LM_ERR("Cannot create radius accounting\n");
			return;
		}

		if (is_evi_acc_on(ctx->flags)) {
			env_set_event(acc_cdr_event);
			if (acc_evi_cdrs(dlg, _params->msg, ctx) < 0) {
				LM_ERR("cannot send accounting events\n");
				return;
			}
		}
	}

}
Example #13
0
/* restore callbacks */
void acc_loaded_callback(struct dlg_cell *dlg, int type,
			struct dlg_cb_params *_params) {
		str flags_s, ctx_s, table_s, created_s;
		acc_ctx_t* ctx;
		time_t created;
		unsigned long long flags;

		if (!dlg) {
			LM_ERR("null dialog - cannot fetch message flags\n");
			return;
		}

		flags_s.s = (char *)&flags;
		flags_s.len = sizeof(flags);
		if (dlg_api.fetch_dlg_value(dlg, &flags_str, &flags_s, 1) < 0) {
			LM_DBG("flags were not saved in dialog\n");
			return;
		}

		created_s.s = (char *)&created;
		created_s.len = sizeof(created);
		if (dlg_api.fetch_dlg_value(dlg, &created_str, &created_s, 1) < 0) {
			LM_DBG("created time was not saved in dialog\n");
			return;
		}

		/**
		 * restore acc extra context(extra and leg values)
		 */
		if (restore_dlg_extra(dlg, &ctx)) {
			LM_ERR("failed to rebuild acc context!\n");
			return;
		}

		/* copy flags value into the context */
		ctx->flags = flags;

		/* copy created value into the context */
		ctx->created = created;

		/* restore accounting table if db accounting is used */
		if (is_db_acc_on(ctx->flags)) {
			if (dlg_api.fetch_dlg_value(dlg, &table_str, &table_s, 0) < 0) {
				LM_DBG("table was not saved in dialog\n");
				return;
			}

			if ((ctx->acc_table.s=shm_malloc(table_s.len)) == NULL) {
				LM_ERR("no more shm!\n");
				return;
			}

			memcpy(ctx->acc_table.s, table_s.s, table_s.len);
			ctx->acc_table.len = table_s.len;
		}



		/* replace the context value with a good pointer */
		ctx_s.s = (char *)&ctx;
		ctx_s.len = sizeof(acc_ctx_t *);
		if (dlg_api.store_dlg_value(dlg, &acc_ctx_str, &ctx_s) < 0) {
			LM_ERR("failed to set new context value!\n");
			return;
		}

		/* register database callbacks */
		acc_ref_ex(ctx, 2);
		if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED |
				DLGCB_EXPIRED, acc_dlg_ended, ctx, unref_acc_ctx)){
			LM_ERR("cannot register callback for database accounting\n");
			acc_unref_ex(ctx, 2);
			return;
		}

		/* register dlg callbacks for ctx management */
		if (dlg_api.register_dlgcb(dlg, DLGCB_REQ_WITHIN,
				acc_merge_contexts, ctx, unref_acc_ctx) != 0) {
			acc_unref(ctx); /* only one, the other one was successful */
			LM_ERR("cannot register callback ctx management\n");
			return;
		}

}
Example #14
0
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
											struct sip_msg *reply, int code)
{
	str new_uri_bk;
	int br = -1;
	hdr_field_t *hdr;
	sip_msg_t tmsg;
	sip_msg_t *preq;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	if(_acc_clone_msg==1) {
		memcpy(&tmsg, req, sizeof(sip_msg_t));
		preq = &tmsg;
	} else {
		preq = req;
	}

	/* get winning branch index, if set */
	if (t->relayed_reply_branch>=0) {
		br = t->relayed_reply_branch;
	} else {
		if(code>=300) {
			br = tmb.t_get_picked_branch();
		}
	}

	/* for reply processing, set as new_uri the one from selected branch */
	if (br>=0) {
		new_uri_bk = preq->new_uri;
		preq->new_uri = t->uac[br].uri;
		preq->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = -1;
		new_uri_bk.s = 0;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	if ( is_log_acc_on(preq) ) {
		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
		acc_log_request(preq);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(preq)) {
		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
		} else {
			acc_db_request(preq);
		}
	}
#endif
#ifdef RAD_ACC
	if (is_rad_acc_on(preq))
		acc_rad_request(preq);
#endif
/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(preq))
		acc_diam_request(preq);
#endif

	/* run extra acc engines */
	acc_run_engines(preq, 0, NULL);

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->parsed_uri_ok = 0;
	}

	/* free header's parsed structures that were added by resolving acc attributes */
	for( hdr=req->headers ; hdr ; hdr=hdr->next ) {
		if ( hdr->parsed && hdr_allocs_parse(hdr) &&
					(hdr->parsed<(void*)t->uas.request ||
					hdr->parsed>=(void*)t->uas.end_request)) {
			/* header parsed filed doesn't point inside uas.request memory
			 * chunck -> it was added by resolving acc attributes -> free it as pkg */
			DBG("removing hdr->parsed %d\n", hdr->type);
			clean_hdr_field(hdr);
			hdr->parsed = 0;
		}
	}
}
Example #15
0
/* initiate a report if we previously enabled accounting for this t */
static void acc_onreply(tm_cell_t *t, sip_msg_t *req, sip_msg_t *reply, int code)
{
	str new_uri_bk;
	int br = -1;
	hdr_field_t *hdr;
	sip_msg_t *cmsg = 0;
	int cmsg_len = 0;
	sip_msg_t *preq = 0;
	void *mstart;
	void *mend;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	if(_acc_clone_msg==1) {
		/* make a clone so eventual new parsed headers in pkg are not visible
		 * to other processes -- other attributes should be already parsed,
		 * available in the req structure and propagated by cloning */
		cmsg = sip_msg_shm_clone(req, &cmsg_len, 1);
		if(cmsg==NULL) {
			LM_ERR("failed to clone the request - acc aborted\n");
			return;
		}
		mstart = cmsg;
		mend = ((char*)cmsg) + cmsg_len;
		preq = cmsg;
	} else {
		mstart = t->uas.request;
		mend = t->uas.end_request;
		preq = req;
	}

	/* get winning branch index, if set */
	if (t->relayed_reply_branch>=0) {
		br = t->relayed_reply_branch;
	} else {
		if(code>=300) {
			br = tmb.t_get_picked_branch();
		}
	}

	/* for reply processing, set as new_uri the one from selected branch */
	if (br>=0) {
		new_uri_bk = preq->new_uri;
		preq->new_uri = t->uac[br].uri;
		preq->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = -1;
		new_uri_bk.s = 0;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	if ( is_log_acc_on(preq) ) {
		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
		acc_log_request(preq);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(preq)) {
		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
		} else {
			acc_db_request(preq);
		}
	}
#endif

/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(preq))
		acc_diam_request(preq);
#endif

	/* run extra acc engines */
	acc_run_engines(preq, 0, NULL);

	if (new_uri_bk.len>=0) {
		preq->new_uri = new_uri_bk;
		preq->parsed_uri_ok = 0;
	}

	/* free header's parsed structures that were added by resolving acc attributes */
	for( hdr=preq->headers ; hdr ; hdr=hdr->next ) {
		if (hdr->parsed && hdr_allocs_parse(hdr) &&
					(hdr->parsed<mstart || hdr->parsed>=mend)) {
			/* header parsed filed doesn't point inside cloned request memory
			 * chunck -> it was added by resolving acc attributes -> free it as pkg */
			DBG("removing hdr->parsed %d\n", hdr->type);
			clean_hdr_field(hdr);
			hdr->parsed = 0;
		}
	}
	if(cmsg!=NULL) {
		shm_free(cmsg);
	}
}