Example #1
0
/*
 * This mid-dialog request callback ensures that any extra/leg settings done
 * at script level before dialog matching is performed will get properly
 * transferred into the dialog context, once the dialog is matched
 */
static void acc_merge_contexts(struct dlg_cell *dlg, int type,
		struct dlg_cb_params *_params)
{
	acc_ctx_t *ctx;

	/* if there is already a acc context in the processing
	 * context, be sure to destroy it for now */
	if ((ctx = ACC_GET_CTX())) {
		push_ctx_to_ctx( ctx, (acc_ctx_t *)(*_params->param));
		acc_unref(ctx); /* unref it now beause it will disapear from local ctx */
	}

	ctx = (acc_ctx_t *)(*_params->param);
	acc_ref(ctx);
	ACC_PUT_CTX(ctx);
}
Example #2
0
static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps )
{
	acc_ctx_t* ctx = *ps->param;

	if (ACC_GET_TM_CTX(t) == NULL) {
		acc_ref(ctx);
		ACC_PUT_TM_CTX(t, ctx);
	}

	if (type&TMCB_RESPONSE_OUT) {
		acc_onreply( t, ps->req, ps->rpl, ps->code, ctx);
	} else if (type&TMCB_ON_FAILURE) {
		on_missed( t, ps->req, ps->rpl, ps->code, ctx);
	} else if (type&TMCB_RESPONSE_IN) {
		acc_onreply_in( t, ps->req, ps->rpl, ps->code, ctx);
	}
}
Example #3
0
static void acc_dlg_ctx_cb(struct dlg_cell *dlg, int type,
		struct dlg_cb_params *_params)
{
	acc_ctx_t *ctx;
	/* set the acc context from dialog into the
	 * current processing context */

	/* if there is already a acc context in the processing
	 * context, be sure to destroy it for now */
	if ( (ctx=ACC_GET_CTX)!=NULL) {
		push_ctx_to_ctx( ctx, (acc_ctx_t *)(*_params->param));
		acc_unref(ctx); /* unref it now beause it will disapear from local ctx */
	}

	ctx = (acc_ctx_t *)(*_params->param);
	acc_ref(ctx);
	ACC_PUT_CTX(ctx);
}
Example #4
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 #5
0
acc_ctx_t* try_fetch_ctx(void)
{
	acc_ctx_t* ret=NULL;
	str ctx_s;

	struct cell* t;
	struct dlg_cell* dlg;

	t = tmb.t_gett ? tmb.t_gett() : NULL;
	t = t==T_UNDEFINED ? NULL : t;


	if ((ret = ACC_GET_CTX()) == NULL) {
		t = tmb.t_gett ? tmb.t_gett() : NULL;
		t = (t==T_UNDEFINED) ? NULL : t;
		dlg = dlg_api.get_dlg ? dlg_api.get_dlg() : NULL;

		/* search the flags in transaction context */
		if (t && (ret=ACC_GET_TM_CTX(t))==NULL) {
			/* try fetching the context from dialog  only if dialog exists */
			if (!dlg ||
					dlg_api.fetch_dlg_value(dlg, &acc_ctx_str, &ctx_s, 0) < 0) {
				/* can't find the flags anywhere */
				return NULL;
			} else { /* found them in dialog; set in the processing context
					  * and in the transaction */
				/* set the flags in transaction and processing context */
				memcpy(&ret, ctx_s.s, sizeof(acc_ctx_t *));
				if (!ret)
					return NULL;

				acc_ref_ex(ret, 2);
				ACC_PUT_TM_CTX(t, ret);
				ACC_PUT_CTX(ret);
			}
		} else if (ret) { /* we have the flags in transaction */
			/* in transaction; put them in dialog(if possible) and in processing context */
			acc_ref(ret);
			ACC_PUT_CTX(ret);
			if (dlg) {
				ctx_s.s = (char *)&ret;
				ctx_s.len = sizeof(acc_ctx_t *);
			}
		} else if (dlg) { /* no (flags in) transaction; search only in dialog*/
			if (dlg_api.fetch_dlg_value(dlg, &acc_ctx_str, &ctx_s, 0) < 0) {
				/* can't find the flags anywhere */
				return NULL;
			} else {
				/* found them in dialog; set in processing context */
				memcpy(&ret, ctx_s.s, sizeof(acc_ctx_t *));
				if (!ret)
					return NULL;

				if (t) {
					acc_ref_ex(ret, 2); /* ref twice - for local and tm ctx */
					ACC_PUT_TM_CTX(t, ret);
				} else
					acc_ref(ret); /* ref only once, for local ctx */
				ACC_PUT_CTX(ret);
			}
		}
	}

	return ret;
}
Example #6
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;
	}

	if (!msg) {
		LM_ERR("no SIP message\n");
		return -1;
	}

	if (skip_cancel(msg)) {
		LM_WARN("do_accounting() called on CANCEL but 'report_cancels' modparam"
				" not set - no accounting will be done for this transaction!\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 || ZSTR(acc_ctx->acc_table))) {
			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)) {
			acc_ref(acc_ctx);
			if (tmb.register_tmcb( msg, 0, TMCB_ON_FAILURE, tmcb_func,
					acc_ctx, unref_acc_ctx)<=0) {
				LM_ERR("cannot register missed calls callback\n");
				acc_unref(acc_ctx);
				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;

	if (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|TMCB_RESPONSE_OUT;

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

		acc_ref(acc_ctx);
		if (tmb.register_tmcb( msg, 0, tmcb_types, tmcb_func,
				acc_ctx, unref_acc_ctx)<=0) {
			LM_ERR("cannot register additional callbacks\n");
			acc_unref(acc_ctx);
			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;
}