int pv_get_acc_current_leg(struct sip_msg *msg, pv_param_t *param, pv_value_t *val) { acc_ctx_t* ctx=try_fetch_ctx(); if (ctx == NULL) { /* if we don't have a context then create it */ if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } ACC_PUT_CTX(ctx); } if (ctx->leg_values == NULL) { LM_ERR("no legs defined!\n"); return -1; } accX_lock(&ctx->lock); val->ri = ctx->legs_no - 1; val->rs.s = int2str(ctx->legs_no - 1, &val->rs.len); accX_unlock(&ctx->lock); val->flags = PV_VAL_INT | PV_VAL_STR | PV_TYPE_INT; return 0; }
int w_drop_acc_2(struct sip_msg* msg, char* type_p, char* flags_p) { unsigned long long type=0; /* if not set, we reset all flags for the type of accounting requested */ unsigned long long flags=ALL_ACC_FLAGS; unsigned long long flag_mask; acc_type_param_t* acc_param; acc_ctx_t* acc_ctx=try_fetch_ctx(); str in; if (acc_ctx == NULL) { LM_ERR("do_accounting() not used! This function resets flags in " "do_accounting()!\n"); return -1; } if (type_p != NULL) { 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 (flags_p != NULL) { flags= *(unsigned long long*)flags_p; } flag_mask = type * flags; /* reset all flags */ if (flag_mask == 0) { /* * we use this flag in order make the difference between * 0 value (do_accounting never called, callbacks never registered) and * ACC_FLAGS_RESET (do_accounting called, callbacks registered, flag value * changing during script execution) */ acc_ctx->flags = ACC_FLAGS_RESET; } else { reset_flags(acc_ctx->flags, flag_mask); } return 1; }
int w_drop_acc_2(struct sip_msg* msg, char* type_p, char* flags_p) { unsigned long long type=0; /* if not set, we reset all flags for the type of accounting requested */ unsigned long long flags=ALL_ACC_FLAGS; unsigned long long flag_mask; acc_type_param_t* acc_param; acc_ctx_t* acc_ctx=try_fetch_ctx(); str in; if (acc_ctx == NULL) { LM_ERR("do_accounting() not used! This function resets flags in " "do_accounting()!\n"); return -1; } if (type_p != NULL) { 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; } } } else type = DO_ACC_LOG | DO_ACC_AAA | DO_ACC_DB | DO_ACC_EVI; if (flags_p != NULL) flags= *(unsigned long long*)flags_p; flag_mask = type * flags; reset_flags(acc_ctx->flags, flag_mask); return 1; }
/* * setter function for $acc_extra */ int pv_set_acc_extra(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) { int tag_idx; acc_ctx_t* ctx=try_fetch_ctx(); if (param == NULL || val == NULL) { LM_ERR("bad params!\n"); return -1; } if (ctx == NULL) { /* if we don't have a context then create it */ if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } ACC_PUT_CTX(ctx); } tag_idx = param->pvn.u.isname.name.n; /* sanity checks for the tag; it should be valid since * we found it in the parse name function */ if (tag_idx < 0 || tag_idx >= extra_tgs_len) { LM_BUG("invalid tag value! probably a memory corruption issue!\n"); return -1; } /* go through all extras and fetch first value you find * all the extras with the same tag will have the same * value */ accX_lock(&ctx->lock); if (set_value_shm(val, &ctx->extra_values[tag_idx]) < 0) { LM_ERR("failed to set extra <%.*s> value!\n", extra_tags[tag_idx].len, extra_tags[tag_idx].s); accX_unlock(&ctx->lock); return -1; } accX_unlock(&ctx->lock); return 0; }
/* * getter function for $acc_extra */ int pv_get_acc_extra(struct sip_msg *msg, pv_param_t *param, pv_value_t *val) { int tag_idx; acc_ctx_t* ctx=try_fetch_ctx(); if (param == NULL || val == NULL) { LM_ERR("bad input params!\n"); return -1; } if (ctx == NULL) { /* if we don't have a context then create it */ if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } ACC_PUT_CTX(ctx); } tag_idx = param->pvn.u.isname.name.n; /* sanity checks for the tag; it should be valid since * we found it in the parse name function */ if (tag_idx < 0 || tag_idx >= extra_tgs_len) { LM_BUG("invalid tag value! probably a memory corruption issue!\n"); return -1; } accX_lock(&ctx->lock); if (ctx->extra_values[tag_idx].value.s == NULL) { val->flags = PV_VAL_NULL; } else { val->rs = ctx->extra_values[tag_idx].value; val->flags = PV_VAL_STR; } accX_unlock(&ctx->lock); return 0; }
int w_new_leg(struct sip_msg* msg) { acc_ctx_t* ctx = try_fetch_ctx(); if (ctx == NULL) { if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } } accX_lock(&ctx->lock); if (push_leg(ctx) < 0) { LM_ERR("failed to create new leg!\n"); accX_unlock(&ctx->lock); return -1; } accX_unlock(&ctx->lock); return 1; }
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; }
int pv_set_acc_leg(struct sip_msg *msg, pv_param_t *param, int flag, pv_value_t *val) { int tag_idx, leg_idx; acc_ctx_t* ctx = try_fetch_ctx(); pv_value_t idx_value; if (ctx == NULL) { /* if we don't have a context then create it */ if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } ACC_PUT_CTX(ctx); } if (ctx->leg_values == NULL) { LM_ERR("no legs defined!\n"); return -1; } tag_idx = param->pvn.u.isname.name.n; if (param->pvi.type == PV_IDX_PVAR) { if (pv_get_spec_value(msg, param->pvi.u.dval, &idx_value) < 0) { LM_ERR("failed to fetch index value!\n"); return -1; } if (idx_value.flags&PV_VAL_INT) { leg_idx = idx_value.ri; } else if (idx_value.flags&PV_VAL_STR) { if (str2sint(&idx_value.rs, &leg_idx) < 0) { goto invalid_leg; } } else { goto invalid_leg; } } else if(param->pvi.type == PV_IDX_INT) { leg_idx = param->pvi.u.ival; } else { /* if not provided consider the value of the last leg */ leg_idx = ctx->legs_no - 1; } if (leg_idx >= (int)ctx->legs_no) { LM_ERR("there aren't that many legs!\n"); return -1; } if (leg_idx < 0) { if ((int)ctx->legs_no + leg_idx < 0) { LM_ERR("invalid leg index %d!\n", leg_idx); return -1; } /* -1 will be the last element and so on */ leg_idx += ctx->legs_no; } accX_lock(&ctx->lock); if (set_value_shm(val, &ctx->leg_values[leg_idx][tag_idx]) < 0) { LM_ERR("failed to set leg <%.*s> value for leg number %d!\n", extra_tags[tag_idx].len, leg_tags[tag_idx].s, leg_idx); accX_unlock(&ctx->lock); return -1; } accX_unlock(&ctx->lock); return 0; invalid_leg: LM_ERR("cannot fetch leg index value!\n"); return -1; }