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); }
/* 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 }
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; } }
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; } } }
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 }
/* 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; } }
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; } } } }
/* 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; } }
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; } } } }
/* 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; } } }
/* 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); } }