int log_request(struct sip_msg *rq, str* ouri, struct hdr_field *to, char *table, unsigned int code, time_t req_timestamp) { int cnt; if (skip_cancel(rq)) return 1; cnt = fmt2strar(log_fmt, rq, ouri, to, code, req_timestamp); if (cnt == 0) { LOG(L_ERR, "ERROR:acc:log_request: fmt2strar failed\n"); return -1; } if (!db_url.len) { LOG(L_ERR, "ERROR:acc:log_request: can't log -- no db_url set\n"); return -1; } if (acc_dbf.use_table(db_handle, table) < 0) { LOG(L_ERR, "ERROR:acc:log_request:Error in use_table\n"); return -1; } if (acc_dbf.insert(db_handle, keys, vals, cnt) < 0) { LOG(L_ERR, "ERROR:acc:log_request:acc_request: Error while inserting to database\n"); return -1; } return 1; }
/* 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; } } }
/******************************************** * acc_request ********************************************/ int acc_log_request( struct sip_msg *rq, struct hdr_field *to, str *txt, str *phrase) { int len; char *log_msg; char *p; int attr_cnt; int attr_len; str* val_arr[ALL_LOG_FMT_LEN]; str atr_arr[ALL_LOG_FMT_LEN]; int i; if (skip_cancel(rq)) return 1; attr_cnt=fmt2strar( log_fmt, rq, to, phrase, &len, &attr_len, val_arr, atr_arr); if (!attr_cnt) { LOG(L_ERR, "ERROR: acc_log_request: fmt2strar failed\n"); return -1; } len+=attr_len+ACC_LEN+txt->len+A_EOL_LEN +attr_cnt*(A_SEPARATOR_LEN+A_EQ_LEN)-A_SEPARATOR_LEN; log_msg=pkg_malloc(len); if (!log_msg) { LOG(L_ERR, "ERROR: acc_log_request: no mem\n"); return -1; } /* skip leading text and begin with first item's * separator ", " which will be overwritten by the * leading text later * */ p=log_msg+(ACC_LEN+txt->len-A_SEPARATOR_LEN); for (i=0; i<attr_cnt; i++) { memcpy(p, A_SEPARATOR, A_SEPARATOR_LEN ); p+=A_SEPARATOR_LEN; memcpy(p, atr_arr[i].s, atr_arr[i].len); p+=atr_arr[i].len; memcpy(p, A_EQ, A_EQ_LEN); p+=A_EQ_LEN; memcpy(p, val_arr[i]->s, val_arr[i]->len); p+=val_arr[i]->len; } /* terminating text */ memcpy(p, A_EOL, A_EOL_LEN); p+=A_EOL_LEN; /* leading text */ p=log_msg; memcpy(p, ACC, ACC_LEN ); p+=ACC_LEN; memcpy(p, txt->s, txt->len); p+=txt->len; LOG(log_level, "%s", log_msg ); pkg_free(log_msg); return 1; }
/* 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; } } }
/* skip leading text and begin with first item's * separator ", " which will be overwritten by the * leading text later * */ static int log_request(struct sip_msg* rq, str* ouri, struct hdr_field* to, unsigned int code, time_t req_time) { VALUE_PAIR *send; UINT4 av_type; send = NULL; if (skip_cancel(rq)) return 1; if (fmt2rad(log_fmt, rq, ouri, to, code, &send, req_time) < 0) goto error; /* Add Acct-Status-Type attribute */ av_type = rad_status(rq, code); if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_ACCT_STATUS_TYPE].v), &av_type, -1, VENDOR(attrs[A_ACCT_STATUS_TYPE].v))) { ERR("Add Status-Type\n"); goto error; } /* Add Service-Type attribute */ av_type = (service_type != -1) ? service_type : vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SERVICE_TYPE].v), &av_type, -1, VENDOR(attrs[A_SERVICE_TYPE].v))) { ERR("add STATUS_TYPE\n"); goto error; } /* Add User-Name attribute */ if (add_user_name(rq, rh, &send) < 0) goto error; /* Send the request out */ if (rc_acct(rh, SIP_PORT, send) != OK_RC) { ERR("RADIUS accounting request failed\n"); goto error; } rc_avpair_free(send); return 1; error: rc_avpair_free(send); return -1; }
/* is this reply of interest for accounting ? */ static inline int should_acc_reply(struct cell* t, int code) { struct sip_msg *r; r = t->uas.request; /* validation */ if (r == 0) { LOG(L_ERR, "ERROR:acc:should_acc_reply: 0 request\n"); return 0; } /* negative transactions reported otherwise only if explicitly * demanded */ if (!failed_transactions && code >= 300) return 0; if (!is_acc_on(r)) return 0; if (skip_cancel(r)) return 0; if (code < 200 && ! (early_media && code == 183)) return 0; return 1; /* seed is through, we will account this reply */ }
int log_request(struct sip_msg *rq, str* ouri, struct hdr_field *to, db_cmd_t* cmd, unsigned int code, time_t req_timestamp) { int cnt; if (skip_cancel(rq)) return 1; cnt = fmt2strar(log_fmt, rq, ouri, to, code, req_timestamp, cmd->vals); if (cnt == 0) { LOG(L_ERR, "ERROR:acc:log_request: fmt2strar failed\n"); return -1; } if (!db_url.len) { LOG(L_ERR, "ERROR:acc:log_request: can't log -- no db_url set\n"); return -1; } if (db_exec(NULL, cmd) < 0) { ERR("Error while inserting to database\n"); return -1; } return 1; }
int acc_diam_request( struct sip_msg *rq, struct hdr_field *to, str *phrase ) { str* val_arr[ALL_LOG_FMT_LEN+1]; str atr_arr[ALL_LOG_FMT_LEN+1]; int attr_cnt; AAAMessage *send = NULL; AAA_AVP *avp; int i; int dummy_len; str* user; str* realm; str user_name; str value; str *uri; struct sip_uri puri; struct to_body* from; int ret, free_user_name; int status; char tmp[2]; unsigned int mid; if (skip_cancel(rq)) return 1; attr_cnt=fmt2strar( DIAM_ACC_FMT, rq, to, phrase, &dummy_len, &dummy_len, val_arr, atr_arr); if (attr_cnt!=(sizeof(DIAM_ACC_FMT)-1)) { LOG(L_ERR, "ERROR: acc_diam_request: fmt2strar failed\n"); return -1; } if ( (send=AAAInMessage(ACCOUNTING_REQUEST, AAA_APP_NASREQ))==NULL) { LOG(L_ERR, "ERROR: acc_diam_request: new AAA message not created\n"); return -1; } /* AVP_ACCOUNTIG_RECORD_TYPE */ if( (status = diam_status(rq, phrase))<0) { LOG(L_ERR, "ERROR: acc_diam_request: status unknown\n"); goto error; } tmp[0] = status+'0'; tmp[1] = 0; if( (avp=AAACreateAVP(AVP_Accounting_Record_Type, 0, 0, tmp, 1, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP_MSGID AVP */ DBG("**ACC***** m_id=%d\n", rq->id); mid = rq->id; if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid), sizeof(mid), AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR, M_NAME":diameter_authorize(): no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, M_NAME":diameter_authorize(): avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP Service AVP */ if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING, SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP_STATUS avp */ if( (avp=AAACreateAVP(AVP_SIP_STATUS, 0, 0, phrase->s, phrase->len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* SIP_METHOD avp */ value = rq->first_line.u.request.method; if( (avp=AAACreateAVP(AVP_SIP_METHOD, 0, 0, value.s, value.len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* Handle AVP_USER_NAME as a special case */ free_user_name = 0; user=cred_user(rq); /* try to take it from credentials */ if (user) { realm = cred_realm(rq); if (realm) { user_name.len = user->len+1+realm->len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_diam_request: no memory\n"); goto error; } memcpy(user_name.s, user->s, user->len); user_name.s[user->len] = '@'; memcpy(user_name.s+user->len+1, realm->s, realm->len); free_user_name = 1; } else { user_name.len = user->len; user_name.s = user->s; } } else { /* from from uri */ if (rq->from && (from=get_from(rq)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "ERROR: acc_diam_request: Bad From URI\n"); goto error; } user_name.len = puri.user.len+1+puri.host.len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_diam_request: no memory\n"); goto error; } memcpy(user_name.s, puri.user.s, puri.user.len); user_name.s[puri.user.len] = '@'; memcpy(user_name.s+puri.user.len+1, puri.host.s, puri.host.len); free_user_name = 1; } else { user_name.len = na.len; user_name.s = na.s; } } if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, user_name.len, free_user_name?AVP_FREE_DATA:AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); if(free_user_name) pkg_free(user_name.s); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* Remaining attributes from diam_attr vector */ for(i=0; i<attr_cnt; i++) { if((avp=AAACreateAVP(diam_attr[i], 0,0, val_arr[i]->s, val_arr[i]->len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"ERROR: acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } } if (get_uri(rq, &uri) < 0) { LOG(L_ERR, "ERROR: acc_diam_request: From/To URI not found\n"); goto error; } if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, "ERROR: acc_diam_request: Error parsing From/To URI\n"); goto error; } /* Destination-Realm AVP */ if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s, puri.host.len, AVP_DUPLICATE_DATA)) == 0) { LOG(L_ERR,"acc_diam_request: no more free memory!\n"); goto error; } if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) { LOG(L_ERR, "acc_diam_request: avp not added \n"); AAAFreeAVP(&avp); goto error; } /* prepare the message to be sent over the network */ if(AAABuildMsgBuffer(send) != AAA_ERR_SUCCESS) { LOG(L_ERR, "ERROR: acc_diam_request: message buffer not created\n"); goto error; } if(sockfd==AAA_NO_CONNECTION) { sockfd = init_mytcp(diameter_client_host, diameter_client_port); if(sockfd==AAA_NO_CONNECTION) { LOG(L_ERR, M_NAME":acc_diam_request: failed to reconnect" " to Diameter client\n"); goto error; } } /* send the message to the DIAMETER client */ ret = tcp_send_recv(sockfd, send->buf.s, send->buf.len, rb, rq->id); if(ret == AAA_CONN_CLOSED) { LOG(L_NOTICE, M_NAME":acc_diam_request: connection to Diameter" " client closed.It will be reopened by the next request\n"); close(sockfd); sockfd = AAA_NO_CONNECTION; goto error; } if(ret != ACC_SUCCESS) /* a transmission error occurred */ { LOG(L_ERR, M_NAME":acc_diam_request: message sending to the" " DIAMETER backend authorization server failed\n"); goto error; } AAAFreeMessage(&send); return 1; error: AAAFreeMessage(&send); return -1; }
int acc_rad_request( struct sip_msg *rq, struct hdr_field *to, str *phrase ) { str* val_arr[ALL_LOG_FMT_LEN+1]; str atr_arr[ALL_LOG_FMT_LEN+1]; int attr_cnt; VALUE_PAIR *send; UINT4 av_type; int i; int dummy_len; str* user; str* realm; str user_name; struct sip_uri puri; struct to_body* from; #ifdef _OBSO char nullcode="00000"; char ccode[6]; char *c; #endif send=NULL; if (skip_cancel(rq)) return 1; attr_cnt=fmt2strar( RAD_ACC_FMT, rq, to, phrase, &dummy_len, &dummy_len, val_arr, atr_arr); if (attr_cnt!=(sizeof(RAD_ACC_FMT)-1)) { LOG(L_ERR, "ERROR: acc_rad_request: fmt2strar failed\n"); goto error; } av_type=rad_status(rq, phrase); if (!rc_avpair_add(rh, &send, attrs[A_ACCT_STATUS_TYPE].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add STATUS_TYPE\n"); goto error; } av_type=vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add STATUS_TYPE\n"); goto error; } av_type=phrase2code(phrase); /* status=integer */ /* if (phrase.len<3) c=nullcode; else { memcpy(ccode, phrase.s, 3); ccode[3]=0;c=nullcode;} */ if (!rc_avpair_add(rh, &send, attrs[A_SIP_RESPONSE_CODE].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add RESPONSE_CODE\n"); goto error; } av_type=rq->REQ_METHOD; if (!rc_avpair_add(rh, &send, attrs[A_SIP_METHOD].v, &av_type, -1, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: add SIP_METHOD\n"); goto error; } /* Handle User-Name as a special case */ user=cred_user(rq); /* try to take it from credentials */ if (user) { realm = cred_realm(rq); if (realm) { user_name.len = user->len+1+realm->len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_rad_request: no memory\n"); goto error; } memcpy(user_name.s, user->s, user->len); user_name.s[user->len] = '@'; memcpy(user_name.s+user->len+1, realm->s, realm->len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); pkg_free(user_name.s); goto error; } pkg_free(user_name.s); } else { user_name.len = user->len; user_name.s = user->s; if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); goto error; } } } else { /* from from uri */ if (rq->from && (from=get_from(rq)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "ERROR: acc_rad_request: Bad From URI\n"); goto error; } user_name.len = puri.user.len+1+puri.host.len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR: acc_rad_request: no memory\n"); goto error; } memcpy(user_name.s, puri.user.s, puri.user.len); user_name.s[puri.user.len] = '@'; memcpy(user_name.s+puri.user.len+1, puri.host.s, puri.host.len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); pkg_free(user_name.s); goto error; } pkg_free(user_name.s); } else { user_name.len = na.len; user_name.s = na.s; if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %d\n", attrs[A_USER_NAME].v ); goto error; } } } /* Remaining attributes from rad_attr vector */ for(i=0; i<attr_cnt; i++) { if (!rc_avpair_add(rh, &send, attrs[rad_attr[i]].v, val_arr[i]->s,val_arr[i]->len, 0)) { LOG(L_ERR, "ERROR: acc_rad_request: rc_avpaid_add " "failed for %s\n", attrs[rad_attr[i]].n ); goto error; } } if (rc_acct(rh, SIP_PORT, send)!=OK_RC) { LOG(L_ERR, "ERROR: acc_rad_request: radius-ing failed\n"); goto error; } rc_avpair_free(send); return 1; error: rc_avpair_free(send); return -1; }
int acc_db_request( struct sip_msg *rq, struct hdr_field *to, str *phrase, char *table, char *fmt) { db_val_t vals[ALL_LOG_FMT_LEN+1]; str* val_arr[ALL_LOG_FMT_LEN+1]; str atr_arr[ALL_LOG_FMT_LEN+1]; /* caution: keys need to be aligned to formatting strings */ db_key_t keys[] = {acc_from_uri, acc_to_uri, acc_sip_method_col, acc_i_uri_col, acc_o_uri_col, acc_sip_from_col, acc_sip_callid_col, acc_sip_to_col, acc_sip_status_col, acc_user_col, acc_totag_col, acc_fromtag_col, acc_domain_col, acc_time_col }; struct tm *tm; time_t timep; char time_s[20]; int attr_cnt; int i; int dummy_len; if (skip_cancel(rq)) return 1; /* database columns: * "sip_method", "i_uri", "o_uri", "sip_from", "sip_callid", * "sip_to", "sip_status", "user", "time" */ attr_cnt=fmt2strar( fmt, rq, to, phrase, &dummy_len, &dummy_len, val_arr, atr_arr); if (!attr_cnt) { LOG(L_ERR, "ERROR: acc_db_request: fmt2strar failed\n"); return -1; } if (!acc_db_url) { LOG(L_ERR, "ERROR: can't log -- no db_url set\n"); return -1; } timep = time(NULL); tm = db_localtime ? localtime(&timep) : gmtime(&timep); strftime(time_s, 20, "%Y-%m-%d %H:%M:%S", tm); for(i=0; i<attr_cnt; i++) { VAL_TYPE(vals+i)=DB_STR; VAL_NULL(vals+i)=0; VAL_STR(vals+i)=*val_arr[i]; } /* time */ VAL_TYPE(vals+i)=DB_STRING; VAL_NULL(vals+i)=0; VAL_STRING(vals+i)=time_s; if (acc_dbf.use_table(db_handle, table) < 0) { LOG(L_ERR, "ERROR: acc_request: " "Error in use_table\n"); return -1; } if (acc_dbf.insert(db_handle, keys, vals, i+1) < 0) { LOG(L_ERR, "ERROR: acc_request: " "Error while inserting to database\n"); return -1; } 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_p, flag_mask; acc_type_param_t* acc_param; str in; str table_name; int tmcb_types; int is_invite; int_str _avp_created_value; 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)) < 0) { 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 + 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 ? */ if ((flag_mask_p=try_fetch_flags()) != NULL) { /* no the first time ; check now if CDRs are requested now * for the first time */ if (!cdr_values_registered(*flag_mask_p) && 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)) { _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 -1; } if (msg->REQ_METHOD == METHOD_INVITE && create_acc_dlg(msg) < 0) { LM_ERR("cannot use dialog accounting module\n"); return -1; } } } *flag_mask_p |= flag_mask; return 1; } /* setting accouting for the first time, allocate the flags holder */ flag_mask_p=shm_malloc(sizeof(unsigned long long)); if (flag_mask_p==NULL) { LM_ERR("No more shm mem!\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 */ *flag_mask_p = flag_mask; ACC_PUT_FLAGS(flag_mask_p); 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 ( msg && !skip_cancel(msg) && (is_acc_on(*flag_mask_p) || is_mc_acc_on(*flag_mask_p)) ) { /* 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 | /* register it manually; see explanation below * get incoming replies ready for processing */ /* TMCB_RESPONSE_OUT | */ /* report on missed calls */ ((is_invite && is_mc_acc_on(*flag_mask_p))?TMCB_ON_FAILURE:0) ; /* if cdr accounting is enabled */ if (is_cdr_acc_on(*flag_mask_p) && !has_totag(msg)) { _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 -1; } 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 wan't to register the free * fucntion only once */ if (tmb.register_tmcb( msg, 0, TMCB_RESPONSE_OUT, tmcb_func, flag_mask_p, tm_free_acc_mask)<=0) { LM_ERR("cannot register additional callbacks\n"); return -1; } if (tmb.register_tmcb( msg, 0, tmcb_types, tmcb_func, flag_mask_p, 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 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; }