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 + -
显示快捷键?