/* prepare message and transaction context for later accounting */ void acc_onreq( struct cell* t, int type, struct tmcb_params *ps ) { int tmcb_types; int is_invite; if ( ps->req && !skip_cancel(ps->req) && ( is_acc_on(ps->req) || is_mc_on(ps->req) || is_acc_prepare_on(ps->req) ) ) { /* do some parsing in advance */ if (acc_preparse_req(ps->req)<0) return; is_invite = (ps->req->REQ_METHOD==METHOD_INVITE)?1:0; /* install additional handlers */ tmcb_types = /* report on completed transactions */ TMCB_RESPONSE_OUT | /* account e2e acks if configured to do so */ ((report_ack && is_acc_on(ps->req))?TMCB_E2EACK_IN:0) | /* get incoming replies ready for processing */ TMCB_RESPONSE_IN | /* report on missed calls */ ((is_invite && (is_mc_on(ps->req) || is_acc_prepare_on(ps->req)))?TMCB_ON_FAILURE:0); if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0, 0 )<=0) { LM_ERR("cannot register additional callbacks\n"); return; } /* if required, determine request direction */ if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) { LM_DBG("detected an UPSTREAM req -> flaging it\n"); ps->req->msg_flags |= FL_REQ_UPSTREAM; } } }
/* prepare message and transaction context for later accounting */ void acc_onreq( struct cell* t, int type, struct tmcb_params *ps ) { int tmcb_types; int is_invite; int_str _avp_created_value; if ( ps->req && !skip_cancel(ps->req) && (is_acc_on(ps->req) || is_mc_on(ps->req)) ) { /* do some parsing in advance */ if (acc_preparse_req(ps->req)<0) return; is_invite = (ps->req->REQ_METHOD==METHOD_INVITE)?1:0; /* install additional handlers */ tmcb_types = /* report on completed transactions */ TMCB_RESPONSE_OUT | /* get incoming replies ready for processing */ TMCB_RESPONSE_IN | /* report on missed calls */ ((is_invite && is_mc_on(ps->req))?TMCB_ON_FAILURE:0) ; /* if cdr accounting is enabled */ if (is_cdr_acc_on(ps->req) && !has_totag(ps->req)) { _avp_created_value.n = time(NULL); if ( add_avp(0, acc_created_avp_id, _avp_created_value) != 0) { LM_ERR("failed to add created avp value!\n"); return; } if (is_invite && create_acc_dlg(ps->req) < 0) { LM_ERR("cannot use dialog accounting module\n"); return; } } if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0, 0 )<=0) { LM_ERR("cannot register additional callbacks\n"); return; } /* if required, determine request direction */ if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) { LM_DBG("detected an UPSTREAM req -> flaging it\n"); ps->req->msg_flags |= FL_REQ_UPSTREAM; } } }
/* parse incoming replies before cloning */ static inline void acc_onreply_in(struct cell *t, struct sip_msg *req, struct sip_msg *reply, int code) { /* don't parse replies in which we are not interested */ /* missed calls enabled ? */ if ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,reply,code) || (is_invite(t) && code>=300 && is_mc_on(req))) ) { parse_headers(reply, HDR_TO_F, 0 ); } }
/* prepare message and transaction context for later accounting */ static void acc_onreq( struct cell* t, struct sip_msg *msg, int code, void *param ) { if (is_acc_on(msg) || is_mc_on(msg)) { acc_preparse_req(msg); /* also, if that is INVITE, disallow silent t-drop */ if (msg->REQ_METHOD==METHOD_INVITE) { DBG("DEBUG: noisy_timer set for accounting\n"); t->noisy_ctimer=1; } } }
/* initiate a report if we previously enabled MC accounting for this t */ static void failure_handler(struct cell *t, int type, struct tmcb_params* ps) { /* validation */ if (t->uas.request == 0) { DBG("DBG:acc:failure_handler: No uas.request, skipping local transaction\n"); return; } if (is_invite(t) && ps->code >= 300) { if (is_mc_on(t->uas.request)) { log_missed(t, ps->rpl, ps->code, (time_t)*(ps->param)); resetflag(t->uas.request, log_missed_flag); } } }
/* parse incoming replies before cloning */ static void replyin_handler(struct cell *t, int type, struct tmcb_params* ps) { /* validation */ if (t->uas.request == 0) { LOG(L_ERR, "ERROR:acc:replyin_handler:replyin_handler: 0 request\n"); return; } /* don't parse replies in which we are not interested */ /* missed calls enabled ? */ if (((is_invite(t) && ps->code >= 300 && is_mc_on(t->uas.request)) || should_acc_reply(t, ps->code)) && (ps->rpl && ps->rpl != FAKED_REPLY)) { parse_headers(ps->rpl, HDR_TO_F, 0); } }
/* parse incoming replies before cloning */ static void acc_onreply_in(struct cell *t, struct sip_msg *reply, int code, void *param) { /* validation */ if (t->uas.request==0) { LOG(L_ERR, "ERROR: acc: should_acc_reply: 0 request\n"); return; } /* don't parse replies in which we are not interested */ /* missed calls enabled ? */ if (((t->is_invite && code>=300 && is_mc_on(t->uas.request)) || should_acc_reply(t,code)) && (reply && reply!=FAKED_REPLY)) { parse_headers(reply, HDR_TO, 0 ); } }
/* prepare message and transaction context for later accounting */ void on_req(struct cell* t, int type, struct tmcb_params *ps) { time_t req_time; /* Pass the timestamp of the request as a parameter to callbacks */ req_time = time(0); if (is_acc_on(ps->req) || is_mc_on(ps->req)) { if (tmb.register_tmcb(0, t, TMCB_RESPONSE_OUT, replyout_handler, (void*)req_time, 0) <= 0) { LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_RESPONSE_OUT callback\n"); return; } if (report_ack) { if (tmb.register_tmcb(0, t, TMCB_E2EACK_IN, ack_handler, (void*)req_time, 0) <= 0) { LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_E2EACK_IN callback\n"); return; } } if (tmb.register_tmcb(0, t, TMCB_ON_FAILURE_RO, failure_handler, (void*)req_time, 0) <= 0) { LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_ON_FAILURE_RO callback\n"); return; } if (tmb.register_tmcb(0, t, TMCB_RESPONSE_IN, replyin_handler, (void*)req_time, 0) <= 0) { LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_RESPONSE_IN callback\n"); return; } /* do some parsing in advance */ preparse_req(ps->req); /* also, if that is INVITE, disallow silent t-drop */ if (ps->req->REQ_METHOD == METHOD_INVITE) { DBG("DEBUG: noisy_timer set for accounting\n"); t->flags |= T_NOISY_CTIMER_FLAG; } } }
/* 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; } }
/* 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); } }