acc_mod.c
来自「性能优秀的SIP Proxy」· C语言 代码 · 共 853 行 · 第 1/2 页
C
853 行
attrs[A_SIP_METHOD].n = "Sip-Method"; attrs[A_USER_NAME].n = "User-Name"; attrs[A_TIME_STAMP].n = "Event-Timestamp"; if (multileg_enabled) { attrs[A_SRC_LEG].n = "Sip-Leg-Source"; attrs[A_DST_LEG].n = "Sip-Leg-Destination"; } vals[V_STATUS_START].n = "Start"; vals[V_STATUS_STOP].n = "Stop"; vals[V_STATUS_FAILED].n = "Failed"; vals[V_SIP_SESSION].n = "Sip-Session"; /* add and count the extras as attributes */ nr_extra_rad = extra2attrs( rad_extra, attrs, A_MAX); /* read config */ if ((rh = rc_read_config(radius_config)) == NULL) { LOG(L_ERR, "ERROR: acc: error opening radius config file: %s\n", radius_config ); return -1; } /* read dictionary */ if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))!=0) { LOG(L_ERR, "ERROR: acc: error reading radius dictionary\n"); return -1; } INIT_AV(rh, attrs, A_MAX+nr_extra_rad, vals, "acc", -1, -1); if (service_type != -1) vals[V_SIP_SESSION].v = service_type;#endif#ifdef DIAM_ACC /* parse the extra string, if any */ if (dia_extra_str && (dia_extra=parse_acc_extra(dia_extra_str))==0 ) { LOG(L_ERR,"ERROR:acc:mod_init: failed to parse dia_extra param\n"); return -1; } if (extra2int(dia_extra)!=0) { LOG(L_ERR,"ERROR:acc:mod_init: extar names for DIAMTER must be " " integer AVP codes\n"); return -1; }#endif return 0;}static int child_init(int rank){#ifdef SQL_ACC if (db_url && acc_db_init(db_url)<0) return -1;#endif /* DIAMETER */#ifdef DIAM_ACC /* open TCP connection */ DBG(M_NAME": Initializing TCP connection\n"); sockfd = init_mytcp(diameter_client_host, diameter_client_port); if(sockfd==-1) { DBG(M_NAME": TCP connection not established\n"); return -1; } DBG(M_NAME": TCP connection established on sockfd=%d\n", sockfd); /* every child with its buffer */ rb = (rd_buf_t*)pkg_malloc(sizeof(rd_buf_t)); if(!rb) { DBG("acc: mod_child_init: no more free memory\n"); return -1; } rb->buf = 0;#endif return 0;}static void destroy(void){ if (log_extra) destroy_extras( log_extra);#ifdef SQL_ACC acc_db_close(); if (db_extra) destroy_extras( db_extra);#endif#ifdef RAD_ACC if (rad_extra) destroy_extras( rad_extra);#endif#ifdef DIAM_ACC close_tcp_connection(sockfd); if (dia_extra) destroy_extras( dia_extra);#endif}static inline void acc_preparse_req(struct sip_msg *rq){ /* try to parse from for From-tag for accounted transactions; * don't be worried about parsing outcome -- if it failed, * we will report N/A */ parse_headers(rq, HDR_CALLID_F| HDR_FROM_F| HDR_TO_F, 0 ); parse_from_header(rq); if (strchr(log_fmt, 'p') || strchr(log_fmt, 'D')) { parse_orig_ruri(rq); }}/* prepare message and transaction context for later accounting */static void acc_onreq( struct cell* t, int type, struct tmcb_params *ps ){ int tmcb_types; if (is_acc_on(ps->req) || is_mc_on(ps->req)) { /* install additional handlers */ tmcb_types = /* report on completed transactions */ TMCB_RESPONSE_OUT | /* account e2e acks if configured to do so */ (report_ack?TMCB_E2EACK_IN:0) | /* get incoming replies ready for processing */ TMCB_RESPONSE_IN | /* report on missed calls */ ((ps->req->REQ_METHOD!=METHOD_CANCEL && is_mc_on(ps->req))? TMCB_ON_FAILURE:0) ; if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0 )<=0) { LOG(L_ERR,"ERROR:acc:acc_onreq: cannot register additional " "callbacks\n"); return; } /* do some parsing in advance */ acc_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; } /* if required, determine request direction */ if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) { DBG("DBUG:acc:acc_onreq: UPSTREAM req detected -> flaging it\n"); ps->req->msg_flags |= FL_REQ_UPSTREAM; } }}/* is this reply of interest for accounting ? */static inline int should_acc_reply(struct sip_msg *req, int code){ /* validation */ if (req==0) { LOG(L_ERR, "ERROR: acc: should_acc_reply: 0 request\n"); return 0; } /* negative transactions reported otherwise only if explicitly * demanded */ if (!is_failed_acc_on(req) && code >=300) return 0; if (!is_acc_on(req)) return 0; if (skip_cancel(req)) return 0; if (code < 200 && ! (early_media && code==183)) return 0; return 1; /* seed is through, we will account this reply */}/* parse incoming replies before cloning */static inline void acc_onreply_in(struct cell *t, struct sip_msg *req, struct sip_msg *reply, int code){ /* validation */ if (req==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 ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,code) || (is_invite(t) && code>=300 && is_mc_on(req))) ) { parse_headers(reply, HDR_TO_F, 0 ); }}/* initiate a report if we previously enabled MC accounting for this t */static inline void on_missed(struct cell *t, struct sip_msg *req, struct sip_msg *reply, int code){ int reset_lmf; #ifdef SQL_ACC int reset_dmf;#endif#ifdef RAD_ACC int reset_rmf;#endif/* DIAMETER */#ifdef DIAM_ACC int reset_dimf;#endif str new_uri_bk; /* validation */ if (req==0) { DBG("DBG: acc: on_missed: no request, local t; skipping\n"); return; } if (is_invite(t) && code>=300) { /* set as new_uri the last branch */ new_uri_bk = req->new_uri; req->new_uri = t->uac[t->nr_of_outgoings-1].uri; if (is_log_mc_on(req)) { acc_log_missed( t, req, reply, code); reset_lmf=1; } else reset_lmf=0;#ifdef SQL_ACC if (db_url && is_db_mc_on(req)) { acc_db_missed( t, req, reply, code); reset_dmf=1; } else reset_dmf=0;#endif#ifdef RAD_ACC if (is_rad_mc_on(req)) { acc_rad_missed(t, req, reply, code ); reset_rmf=1; } else reset_rmf=0;#endif/* DIAMETER */#ifdef DIAM_ACC if (is_diam_mc_on(req)) { acc_diam_missed(t, req, reply, code ); reset_dimf=1; } else reset_dimf=0;#endif req->new_uri = new_uri_bk; /* we report on missed calls when the first * forwarding attempt fails; we do not wish to * report on every attempt; so we clear the flags; * we do it after all reporting is over to be sure * that all reporting functions got a fair chance */ if (reset_lmf) resetflag(req, log_missed_flag);#ifdef SQL_ACC if (reset_dmf) resetflag(req, db_missed_flag);#endif#ifdef RAD_ACC if (reset_rmf) resetflag(req, radius_missed_flag);#endif/* DIAMETER */#ifdef DIAM_ACC if (reset_dimf) resetflag(req, diameter_missed_flag);#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; /* validation */ if (req==0) { DBG("DBG: acc: onreply: no 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, req, reply, code); /* for reply processing, set as new_uri the winning branch */ if (t->relaied_reply_branch>=0) { new_uri_bk = req->new_uri; req->new_uri = t->uac[t->relaied_reply_branch].uri; } else { new_uri_bk.len = -1; new_uri_bk.s = 0; } if (!should_acc_reply(req, code)) return; if ( is_log_acc_on(req) ) acc_log_reply(t, req, reply, code);#ifdef SQL_ACC if (db_url && is_db_acc_on(req)) acc_db_reply(t, req, reply, code);#endif#ifdef RAD_ACC if (is_rad_acc_on(req)) acc_rad_reply(t, req, reply, code);#endif/* DIAMETER */#ifdef DIAM_ACC if (is_diam_acc_on(req)) acc_diam_reply(t, req, reply, code);#endif if (new_uri_bk.len>=0) req->new_uri = new_uri_bk;}static inline void acc_onack( struct cell* t, struct sip_msg *req, struct sip_msg *ack, int code){ /* 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(req)) { acc_preparse_req(ack); acc_log_ack(t, req, ack); }#ifdef SQL_ACC if (db_url && is_db_acc_on(req)) { acc_preparse_req(ack); acc_db_ack(t, req, ack); }#endif#ifdef RAD_ACC if (is_rad_acc_on(req)) { acc_preparse_req(ack); acc_rad_ack(t, req, ack); }#endif/* DIAMETER */#ifdef DIAM_ACC if (is_diam_acc_on(req)) { acc_preparse_req(ack); acc_diam_ack(t,ack); }#endif }static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps ){ if (type&TMCB_RESPONSE_OUT) { acc_onreply( t, ps->req, ps->rpl, ps->code); } else if (type&TMCB_E2EACK_IN) { acc_onack( t, t->uas.request, ps->req, ps->code); } else if (type&TMCB_ON_FAILURE) { on_missed( t, ps->req, ps->rpl, ps->code); } else if (type&TMCB_RESPONSE_IN) { acc_onreply_in( t, ps->req, ps->rpl, ps->code); }}/* these wrappers parse all what may be needed; they don't care about * the result -- accounting functions just display "unavailable" if there * is nothing meaningful */static int w_acc_log_request(struct sip_msg *rq, char *comment, char *foo){ str txt; txt.s=ACC_REQUEST; txt.len=ACC_REQUEST_LEN; acc_preparse_req(rq); return acc_log_request(rq, rq->to, &txt, (str*)comment);}#ifdef SQL_ACCstatic int w_acc_db_request(struct sip_msg *rq, char *comment, char *table){ if (!db_url) { LOG(L_ERR,"ERROR:acc:w_acc_db_request: DB support not configured\n"); return -1; } acc_preparse_req(rq); return acc_db_request(rq, rq->to, (str*)comment, table, SQL_MC_FMT );}#endif#ifdef RAD_ACCstatic int w_acc_rad_request(struct sip_msg *rq, char *comment, char *foo){ acc_preparse_req(rq); return acc_rad_request(rq, rq->to, (str*)comment);}#endif/* DIAMETER */#ifdef DIAM_ACCstatic int w_acc_diam_request(struct sip_msg *rq, char *comment, char *foo){ str phrase; phrase.s=comment; phrase.len=strlen(comment); /* fix_param would be faster! */ acc_preparse_req(rq); return acc_diam_request(rq, rq->to, (str*)comment);}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?