acc.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  * Copyright (C) 2006 Voice Sistem SRL
00006  * Copyright (C) 2008 Juha Heinanen
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  * 2003-04-04  grand acc cleanup (jiri)
00027  * 2003-11-04  multidomain support for mysql introduced (jiri)
00028  * 2004-06-06  updated to the new DB api, cleanup: acc_db_{bind, init,close)
00029  *              added (andrei)
00030  * 2005-05-30  acc_extra patch commited (ramona)
00031  * 2005-06-28  multi leg call support added (bogdan)
00032  * 2006-01-13  detect_direction (for sequential requests) added (bogdan)
00033  * 2006-09-08  flexible multi leg accounting support added,
00034  *             code cleanup for low level functions (bogdan)
00035  * 2006-09-19  final stage of a masive re-structuring and cleanup (bogdan)
00036  * 2008-09-03  added support for integer type Radius attributes (jh)
00037  */
00038 
00046 #include <stdio.h>
00047 #include <time.h>
00048 
00049 #include "../../dprint.h"
00050 #include "../../error.h"
00051 #include "../../mem/mem.h"
00052 #include "../../usr_avp.h"
00053 #include "../../lib/srdb1/db.h"
00054 #include "../../parser/hf.h"
00055 #include "../../parser/msg_parser.h"
00056 #include "../../parser/parse_from.h"
00057 #include "../../parser/digest/digest.h"
00058 #include "../../modules/tm/t_funcs.h"
00059 #include "acc_mod.h"
00060 #include "acc.h"
00061 #include "acc_extra.h"
00062 #include "acc_logic.h"
00063 #include "acc_api.h"
00064 
00065 #ifdef RAD_ACC
00066 #include "../../lib/kcore/radius.h"
00067 #endif
00068 
00069 #ifdef DIAM_ACC
00070 #include "diam_dict.h"
00071 #include "diam_message.h"
00072 #include "diam_tcp.h"
00073 #endif
00074 
00075 extern struct acc_extra *log_extra;
00076 extern struct acc_extra *leg_info;
00077 extern struct acc_enviroment acc_env;
00078 
00079 #ifdef RAD_ACC
00080 extern struct acc_extra *rad_extra;
00081 #endif
00082 
00083 #ifdef DIAM_ACC
00084 extern char *diameter_client_host;
00085 extern int diameter_client_port;
00086 extern struct acc_extra *dia_extra;
00087 #endif
00088 
00089 #ifdef SQL_ACC
00090 static db_func_t acc_dbf;
00091 static db1_con_t* db_handle=0;
00092 extern struct acc_extra *db_extra;
00093 extern int acc_db_insert_mode;
00094 #endif
00095 
00096 /* arrays used to collect the values before being
00097  * pushed to the storage backend (whatever used) */
00098 static str val_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
00099 static int int_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
00100 static char type_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
00101 
00102 /********************************************
00103  *        acc CORE function
00104  ********************************************/
00105 #define get_ft_body( _ft_hdr) \
00106         ((struct to_body*)_ft_hdr->parsed)
00107 
00108 #define SET_EMPTY_VAL(_i) \
00109         do { \
00110                 c_vals[_i].s = 0; \
00111                 c_vals[_i].len = 0; \
00112         } while(0)
00113 
00114 /* returns:
00115  *              method name
00116  *              from TAG
00117  *              to TAG
00118  *              callid
00119  *              sip_code
00120  *              sip_status
00121  *              */
00122 int core2strar(struct sip_msg *req, str *c_vals, int *i_vals, char *t_vals)
00123 {
00124         struct to_body *ft_body;
00125         struct hdr_field *from;
00126         struct hdr_field *to;
00127 
00128         /* method : request/reply - cseq parsed in acc_preparse_req() */
00129         c_vals[0] = get_cseq(req)->method;
00130         t_vals[0] = TYPE_STR;
00131 
00132         /* from/to URI and TAG */
00133         if (req->msg_flags&FL_REQ_UPSTREAM) {
00134                 LM_DBG("the flag UPSTREAM is set -> swap F/T\n"); \
00135                 from = acc_env.to;
00136                 to = req->from;
00137         } else {
00138                 from = req->from;
00139                 to = acc_env.to;
00140         }
00141 
00142         if (from && (ft_body=get_ft_body(from)) && ft_body->tag_value.len) {
00143                 c_vals[1] = ft_body->tag_value;
00144                 t_vals[1] = TYPE_STR;
00145         } else {
00146                 SET_EMPTY_VAL(1);
00147                 t_vals[1] = TYPE_NULL;
00148         }
00149 
00150         if (to && (ft_body=get_ft_body(to)) && ft_body->tag_value.len) {
00151                 c_vals[2] = ft_body->tag_value;
00152                 t_vals[2] = TYPE_STR;
00153         } else {
00154                 SET_EMPTY_VAL(2);
00155                 t_vals[2] = TYPE_NULL;
00156         }
00157 
00158         /* Callid */
00159         if (req->callid && req->callid->body.len) {
00160                 c_vals[3] = req->callid->body;
00161                 t_vals[3] = TYPE_STR;
00162         } else {
00163                 SET_EMPTY_VAL(3);
00164                 t_vals[3] = TYPE_NULL;
00165         }
00166 
00167         /* SIP code */
00168         c_vals[4] = acc_env.code_s;
00169         i_vals[4] = acc_env.code;
00170         t_vals[4] = TYPE_INT;
00171 
00172         /* SIP status */
00173         c_vals[5] = acc_env.reason;
00174         t_vals[5] = TYPE_STR;
00175 
00176         acc_env.ts = time(NULL);
00177         return ACC_CORE_LEN;
00178 }
00179 
00180 
00181 
00182 /********************************************
00183  *        LOG  ACCOUNTING
00184  ********************************************/
00185 static str log_attrs[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
00186 
00187 #define SET_LOG_ATTR(_n,_atr)  \
00188         do { \
00189                 log_attrs[_n].s=A_##_atr; \
00190                 log_attrs[_n].len=A_##_atr##_LEN; \
00191                 n++; \
00192         } while(0)
00193 
00194 void acc_log_init(void)
00195 {
00196         struct acc_extra *extra;
00197         int n;
00198 
00199         n = 0;
00200 
00201         /* fixed core attributes */
00202         SET_LOG_ATTR(n,METHOD);
00203         SET_LOG_ATTR(n,FROMTAG);
00204         SET_LOG_ATTR(n,TOTAG);
00205         SET_LOG_ATTR(n,CALLID);
00206         SET_LOG_ATTR(n,CODE);
00207         SET_LOG_ATTR(n,STATUS);
00208 
00209         /* init the extra db keys */
00210         for(extra=log_extra; extra ; extra=extra->next)
00211                 log_attrs[n++] = extra->name;
00212 
00213         /* multi leg call columns */
00214         for( extra=leg_info ; extra ; extra=extra->next)
00215                 log_attrs[n++] = extra->name;
00216 }
00217 
00218 
00219 int acc_log_request( struct sip_msg *rq)
00220 {
00221         static char log_msg[MAX_SYSLOG_SIZE];
00222         static char *log_msg_end=log_msg+MAX_SYSLOG_SIZE-2;
00223         char *p;
00224         int n;
00225         int m;
00226         int i;
00227 
00228         /* get default values */
00229         m = core2strar( rq, val_arr, int_arr, type_arr);
00230 
00231         /* get extra values */
00232         m += extra2strar( log_extra, rq, val_arr+m, int_arr+m, type_arr+m);
00233 
00234         for ( i=0,p=log_msg ; i<m ; i++ ) {
00235                 if (p+1+log_attrs[i].len+1+val_arr[i].len >= log_msg_end) {
00236                         LM_WARN("acc message too long, truncating..\n");
00237                         p = log_msg_end;
00238                         break;
00239                 }
00240                 *(p++) = A_SEPARATOR_CHR;
00241                 memcpy(p, log_attrs[i].s, log_attrs[i].len);
00242                 p += log_attrs[i].len;
00243                 *(p++) = A_EQ_CHR;
00244                 memcpy(p, val_arr[i].s, val_arr[i].len);
00245                 p += val_arr[i].len;
00246         }
00247 
00248         /* get per leg attributes */
00249         if ( leg_info ) {
00250                 n = legs2strar(leg_info,rq,val_arr+m,int_arr+m,type_arr+m, 1);
00251                 do {
00252                         for (i=m; i<m+n; i++) {
00253                                 if (p+1+log_attrs[i].len+1+val_arr[i].len >= log_msg_end) {
00254                                         LM_WARN("acc message too long, truncating..\n");
00255                                         p = log_msg_end;
00256                                         break;
00257                                 }
00258                                 *(p++) = A_SEPARATOR_CHR;
00259                                 memcpy(p, log_attrs[i].s, log_attrs[i].len);
00260                                 p += log_attrs[i].len;
00261                                 *(p++) = A_EQ_CHR;
00262                                 memcpy(p, val_arr[i].s, val_arr[i].len);
00263                                 p += val_arr[i].len;
00264                         }
00265                 }while (p!=log_msg_end && (n=legs2strar(leg_info,rq,val_arr+m,
00266                                                         int_arr+m,type_arr+m,
00267                                                         0))!=0);
00268         }
00269 
00270         /* terminating line */
00271         *(p++) = '\n';
00272         *(p++) = 0;
00273 
00274         LM_GEN2(log_facility, log_level, "%.*stimestamp=%lu%s",
00275                 acc_env.text.len, acc_env.text.s,(unsigned long) acc_env.ts, log_msg);
00276 
00277         return 1;
00278 }
00279 
00280 
00281 /********************************************
00282  *        SQL  ACCOUNTING
00283  ********************************************/
00284 
00285 #ifdef SQL_ACC
00286 
00287 /* caution: keys need to be aligned to core format */
00288 static db_key_t db_keys[ACC_CORE_LEN+1+MAX_ACC_EXTRA+MAX_ACC_LEG];
00289 static db_val_t db_vals[ACC_CORE_LEN+1+MAX_ACC_EXTRA+MAX_ACC_LEG];
00290 
00291 
00292 static void acc_db_init_keys(void)
00293 {
00294         struct acc_extra *extra;
00295         int time_idx;
00296         int i;
00297         int n;
00298 
00299         /* init the static db keys */
00300         n = 0;
00301         /* caution: keys need to be aligned to core format */
00302         db_keys[n++] = &acc_method_col;
00303         db_keys[n++] = &acc_fromtag_col;
00304         db_keys[n++] = &acc_totag_col;
00305         db_keys[n++] = &acc_callid_col;
00306         db_keys[n++] = &acc_sipcode_col;
00307         db_keys[n++] = &acc_sipreason_col;
00308         db_keys[n++] = &acc_time_col;
00309         time_idx = n-1;
00310 
00311         /* init the extra db keys */
00312         for(extra=db_extra; extra ; extra=extra->next)
00313                 db_keys[n++] = &extra->name;
00314 
00315         /* multi leg call columns */
00316         for( extra=leg_info ; extra ; extra=extra->next)
00317                 db_keys[n++] = &extra->name;
00318 
00319         /* init the values */
00320         for(i=0; i<n; i++) {
00321                 VAL_TYPE(db_vals+i)=DB1_STR;
00322                 VAL_NULL(db_vals+i)=0;
00323         }
00324         VAL_TYPE(db_vals+time_idx)=DB1_DATETIME;
00325 }
00326 
00327 
00328 /* binds to the corresponding database module
00329  * returns 0 on success, -1 on error */
00330 int acc_db_init(const str* db_url)
00331 {
00332         if (db_bind_mod(db_url, &acc_dbf)<0){
00333                 LM_ERR("bind_db failed\n");
00334                 return -1;
00335         }
00336 
00337         /* Check database capabilities */
00338         if (!DB_CAPABILITY(acc_dbf, DB_CAP_INSERT)) {
00339                 LM_ERR("database module does not implement insert function\n");
00340                 return -1;
00341         }
00342 
00343         acc_db_init_keys();
00344 
00345         return 0;
00346 }
00347 
00348 
00349 /* initialize the database connection
00350  * returns 0 on success, -1 on error */
00351 int acc_db_init_child(const str *db_url)
00352 {
00353         db_handle=acc_dbf.init(db_url);
00354         if (db_handle==0){
00355                 LM_ERR("unable to connect to the database\n");
00356                 return -1;
00357         }
00358         return 0;
00359 }
00360 
00361 
00362 /* close a db connection */
00363 void acc_db_close(void)
00364 {
00365         if (db_handle && acc_dbf.close)
00366                 acc_dbf.close(db_handle);
00367 }
00368 
00369 
00370 int acc_db_request( struct sip_msg *rq)
00371 {
00372         int m;
00373         int n;
00374         int i;
00375 
00376         /* formated database columns */
00377         m = core2strar( rq, val_arr, int_arr, type_arr );
00378 
00379         for(i=0; i<m; i++)
00380                 VAL_STR(db_vals+i) = val_arr[i];
00381         /* time value */
00382         VAL_TIME(db_vals+(m++)) = acc_env.ts;
00383 
00384         /* extra columns */
00385         m += extra2strar( db_extra, rq, val_arr+m, int_arr+m, type_arr+m);
00386 
00387         for( i++ ; i<m; i++)
00388                 VAL_STR(db_vals+i) = val_arr[i];
00389 
00390         if (acc_dbf.use_table(db_handle, &acc_env.text/*table*/) < 0) {
00391                 LM_ERR("error in use_table\n");
00392                 return -1;
00393         }
00394 
00395         /* multi-leg columns */
00396         if ( !leg_info ) {
00397                 if(acc_db_insert_mode==1 && acc_dbf.insert_delayed!=NULL) {
00398                         if (acc_dbf.insert_delayed(db_handle, db_keys, db_vals, m) < 0) {
00399                                 LM_ERR("failed to insert delayed into database\n");
00400                                 return -1;
00401                         }
00402                 } else {
00403                         if (acc_dbf.insert(db_handle, db_keys, db_vals, m) < 0) {
00404                                 LM_ERR("failed to insert into database\n");
00405                                 return -1;
00406                         }
00407                 }
00408         } else {
00409                 n = legs2strar(leg_info,rq,val_arr+m,int_arr+m,type_arr+m,1);
00410                 do {
00411                         for (i=m; i<m+n; i++)
00412                                 VAL_STR(db_vals+i)=val_arr[i];
00413                         if(acc_db_insert_mode==1 && acc_dbf.insert_delayed!=NULL) {
00414                                 if(acc_dbf.insert_delayed(db_handle,db_keys,db_vals,m+n)<0) {
00415                                         LM_ERR("failed to insert delayed into database\n");
00416                                         return -1;
00417                                 }
00418                         } else {
00419                                 if (acc_dbf.insert(db_handle, db_keys, db_vals, m+n) < 0) {
00420                                         LM_ERR("failed to insert into database\n");
00421                                         return -1;
00422                                 }
00423                         }
00424                 }while ( (n=legs2strar(leg_info,rq,val_arr+m,int_arr+m,
00425                                        type_arr+m,0))!=0 );
00426         }
00427 
00428         return 1;
00429 }
00430 
00431 #endif
00432 
00433 
00434 /************ RADIUS & DIAMETER helper functions **************/
00435 #if defined(RAD_ACC) || defined (DIAM_ACC)
00436 #ifndef UINT4
00437 #define UINT4 uint32_t
00438 #endif
00439 inline static UINT4 phrase2code(str *phrase)
00440 {
00441         UINT4 code;
00442         int i;
00443 
00444         if (phrase->len<3) return 0;
00445         code=0;
00446         for (i=0;i<3;i++) {
00447                 if (!(phrase->s[i]>='0' && phrase->s[i]<'9'))
00448                                 return 0;
00449                 code=code*10+phrase->s[i]-'0';
00450         }
00451         return code;
00452 }
00453 #endif
00454 
00455 
00456 /********************************************
00457  *        RADIUS  ACCOUNTING
00458  ********************************************/
00459 #ifdef RAD_ACC
00460 enum { RA_ACCT_STATUS_TYPE=0, RA_SERVICE_TYPE, RA_SIP_RESPONSE_CODE,
00461         RA_SIP_METHOD, RA_TIME_STAMP, RA_STATIC_MAX};
00462 enum {RV_STATUS_START=0, RV_STATUS_STOP, RV_STATUS_ALIVE, RV_STATUS_FAILED,
00463         RV_SIP_SESSION, RV_STATIC_MAX};
00464 static struct attr
00465         rd_attrs[RA_STATIC_MAX+ACC_CORE_LEN-2+MAX_ACC_EXTRA+MAX_ACC_LEG];
00466 static struct val rd_vals[RV_STATIC_MAX];
00467 
00468 int init_acc_rad(char *rad_cfg, int srv_type)
00469 {
00470         int n;
00471 
00472         memset(rd_attrs, 0, sizeof(rd_attrs));
00473         memset(rd_vals, 0, sizeof(rd_vals));
00474         rd_attrs[RA_ACCT_STATUS_TYPE].n  = "Acct-Status-Type";
00475         rd_attrs[RA_SERVICE_TYPE].n      = "Service-Type";
00476         rd_attrs[RA_SIP_RESPONSE_CODE].n = "Sip-Response-Code";
00477         rd_attrs[RA_SIP_METHOD].n        = "Sip-Method";
00478         rd_attrs[RA_TIME_STAMP].n        = "Event-Timestamp";
00479         n = RA_STATIC_MAX;
00480         /* caution: keep these aligned to core acc output */
00481         rd_attrs[n++].n                  = "Sip-From-Tag";
00482         rd_attrs[n++].n                  = "Sip-To-Tag";
00483         rd_attrs[n++].n                  = "Acct-Session-Id";
00484 
00485         rd_vals[RV_STATUS_START].n        = "Start";
00486         rd_vals[RV_STATUS_STOP].n         = "Stop";
00487         rd_vals[RV_STATUS_ALIVE].n        = "Alive";
00488         rd_vals[RV_STATUS_FAILED].n       = "Failed";
00489         rd_vals[RV_SIP_SESSION].n         = "Sip-Session";
00490 
00491         /* add and count the extras as attributes */
00492         n += extra2attrs( rad_extra, rd_attrs, n);
00493         /* add and count the legs as attributes */
00494         n += extra2attrs( leg_info, rd_attrs, n);
00495 
00496         /* read config */
00497         if ((rh = rc_read_config(rad_cfg)) == NULL) {
00498                 LM_ERR("failed to open radius config file: %s\n", rad_cfg );
00499                 return -1;
00500         }
00501         /* read dictionary */
00502         if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))!=0) {
00503                 LM_ERR("failed to read radius dictionary\n");
00504                 return -1;
00505         }
00506 
00507         INIT_AV(rh, rd_attrs, n, rd_vals, RV_STATIC_MAX, "acc", -1, -1);
00508 
00509         if (srv_type != -1)
00510                 rd_vals[RV_SIP_SESSION].v = srv_type;
00511 
00512         return 0;
00513 }
00514 
00515 
00516 static inline UINT4 rad_status( struct sip_msg *req, int code )
00517 {
00518         str tag;
00519         unsigned int in_dialog_req = 0;
00520 
00521         tag = get_to(req)->tag_value;
00522         if(tag.s!=0 && tag.len!=0)
00523                 in_dialog_req = 1;
00524 
00525         if (req->REQ_METHOD==METHOD_INVITE && in_dialog_req == 0
00526                     && code>=200 && code<300)
00527                 return rd_vals[RV_STATUS_START].v;
00528         if ((req->REQ_METHOD==METHOD_BYE || req->REQ_METHOD==METHOD_CANCEL))
00529                 return rd_vals[RV_STATUS_STOP].v;
00530         if (in_dialog_req != 0)
00531                 return rd_vals[RV_STATUS_ALIVE].v;
00532         return rd_vals[RV_STATUS_FAILED].v;
00533  }
00534 
00535 #define ADD_RAD_AVPAIR(_attr,_val,_len)         \
00536     do {                                                                \
00537         if (!rc_avpair_add(rh, &send, rd_attrs[_attr].v, _val, _len, 0)) { \
00538             LM_ERR("failed to add %s, %d\n", rd_attrs[_attr].n, _attr); \
00539             goto error;                                                 \
00540         } \
00541     }while(0)
00542 
00543 int acc_rad_request( struct sip_msg *req )
00544 {
00545         int attr_cnt;
00546         VALUE_PAIR *send;
00547         UINT4 av_type;
00548         int offset;
00549         int i;
00550 
00551         send=NULL;
00552 
00553         attr_cnt = core2strar( req, val_arr, int_arr, type_arr );
00554         /* not interested in the last 2 values */
00555         attr_cnt -= 2;
00556 
00557         av_type = rad_status( req, acc_env.code); /* RADIUS status */
00558         ADD_RAD_AVPAIR( RA_ACCT_STATUS_TYPE, &av_type, -1);
00559 
00560         av_type = rd_vals[RV_SIP_SESSION].v; /* session*/
00561         ADD_RAD_AVPAIR( RA_SERVICE_TYPE, &av_type, -1);
00562 
00563         av_type = (UINT4)acc_env.code; /* status=integer */
00564         ADD_RAD_AVPAIR( RA_SIP_RESPONSE_CODE, &av_type, -1);
00565 
00566         av_type = req->REQ_METHOD; /* method */
00567         ADD_RAD_AVPAIR( RA_SIP_METHOD, &av_type, -1);
00568 
00569         /* unix time */
00570         av_type = (UINT4)acc_env.ts;
00571         ADD_RAD_AVPAIR( RA_TIME_STAMP, &av_type, -1);
00572 
00573         /* add extra also */
00574         attr_cnt += extra2strar(rad_extra, req, val_arr+attr_cnt,
00575                                 int_arr+attr_cnt, type_arr+attr_cnt);
00576 
00577         /* add the values for the vector - start from 1 instead of
00578          * 0 to skip the first value which is the METHOD as string */
00579         offset = RA_STATIC_MAX-1;
00580         for( i=1; i<attr_cnt; i++) {
00581             switch (type_arr[i]) {
00582             case TYPE_STR:
00583                 ADD_RAD_AVPAIR(offset+i, val_arr[i].s, val_arr[i].len);
00584                 break;
00585             case TYPE_INT:
00586                 ADD_RAD_AVPAIR(offset+i, &(int_arr[i]), -1);
00587                 break;
00588             default:
00589                 break;
00590             }
00591         }
00592 
00593         /* call-legs attributes also get inserted */
00594         if ( leg_info ) {
00595                 offset += attr_cnt;
00596                 attr_cnt = legs2strar(leg_info,req,val_arr,int_arr,type_arr,1);
00597                 do {
00598                         for (i=0; i<attr_cnt; i++)
00599                                 ADD_RAD_AVPAIR( offset+i, val_arr[i].s, val_arr[i].len );
00600                 }while ( (attr_cnt=legs2strar(leg_info,req,val_arr,int_arr,
00601                                               type_arr, 0))!=0 );
00602         }
00603 
00604         if (rc_acct(rh, SIP_PORT, send)!=OK_RC) {
00605                 LM_ERR("radius-ing failed\n");
00606                 goto error;
00607         }
00608         rc_avpair_free(send);
00609         return 1;
00610 
00611 error:
00612         rc_avpair_free(send);
00613         return -1;
00614 }
00615 
00616 #endif
00617 
00618 
00619 /********************************************
00620  *        DIAMETER  ACCOUNTING
00621  ********************************************/
00622 #ifdef DIAM_ACC
00623 
00624 #define AA_REQUEST 265
00625 #define AA_ANSWER  265
00626 
00627 #define ACCOUNTING_REQUEST 271
00628 #define ACCOUNTING_ANSWER  271
00629 
00630 static int diam_attrs[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
00631 
00632 int acc_diam_init()
00633 {
00634         int n;
00635         int m;
00636 
00637         n = 0;
00638         /* caution: keep these aligned to core acc output */
00639         diam_attrs[n++] = AVP_SIP_METHOD;
00640         diam_attrs[n++] = AVP_SIP_FROM_TAG;
00641         diam_attrs[n++] = AVP_SIP_TO_TAG;
00642         diam_attrs[n++] = AVP_SIP_CALLID;
00643         diam_attrs[n++] = AVP_SIP_STATUS;
00644 
00645         m = extra2int( dia_extra, diam_attrs+n);
00646         if (m<0) {
00647                 LM_ERR("extra names for DIAMETER must be integer AVP codes\n");
00648                 return -1;
00649         }
00650         n += m;
00651 
00652         m = extra2int( leg_info, diam_attrs+n);
00653         if (m<0) {
00654                 LM_ERR("leg info names for DIAMTER must be integer AVP codes\n");
00655                 return -1;
00656         }
00657         n += m;
00658 
00659         return 0;
00660 }
00661 
00662 
00663 inline unsigned long diam_status(struct sip_msg *rq, int code)
00664 {
00665         if ((rq->REQ_METHOD==METHOD_INVITE || rq->REQ_METHOD==METHOD_ACK)
00666                                 && code>=200 && code<300) 
00667                 return AAA_ACCT_START;
00668 
00669         if ((rq->REQ_METHOD==METHOD_BYE || rq->REQ_METHOD==METHOD_CANCEL))
00670                 return AAA_ACCT_STOP;
00671 
00672         if (code>=200 && code <=300)  
00673                 return AAA_ACCT_EVENT;
00674 
00675         return -1;
00676 }
00677 
00678 
00679 int acc_diam_request( struct sip_msg *req )
00680 {
00681         int attr_cnt;
00682         int cnt;
00683         AAAMessage *send = NULL;
00684         AAA_AVP *avp;
00685         struct sip_uri puri;
00686         str *uri;
00687         int ret;
00688         int i;
00689         int status;
00690         char tmp[2];
00691         unsigned int mid;
00692 
00693         attr_cnt = core2strar( req, val_arr, int_arr, type_arr );
00694         /* last value is not used */
00695         attr_cnt--;
00696 
00697         if ( (send=AAAInMessage(ACCOUNTING_REQUEST, AAA_APP_NASREQ))==NULL) {
00698                 LM_ERR("failed to create new AAA request\n");
00699                 return -1;
00700         }
00701 
00702         /* AVP_ACCOUNTIG_RECORD_TYPE */
00703         if( (status = diam_status(req, acc_env.code))<0) {
00704                 LM_ERR("status unknown\n");
00705                 goto error;
00706         }
00707         tmp[0] = status+'0';
00708         tmp[1] = 0;
00709         if( (avp=AAACreateAVP(AVP_Accounting_Record_Type, 0, 0, tmp,
00710         1, AVP_DUPLICATE_DATA)) == 0) {
00711                 LM_ERR("failed to create AVP:no more free memory!\n");
00712                 goto error;
00713         }
00714         if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
00715                 LM_ERR("avp not added \n");
00716                 AAAFreeAVP(&avp);
00717                 goto error;
00718         }
00719         /* SIP_MSGID AVP */
00720         mid = req->id;
00721         if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid), 
00722         sizeof(mid), AVP_DUPLICATE_DATA)) == 0) {
00723                 LM_ERR("failed to create AVP:no more free memory!\n");
00724                 goto error;
00725         }
00726         if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
00727                 LM_ERR("avp not added \n");
00728                 AAAFreeAVP(&avp);
00729                 goto error;
00730         }
00731 
00732         /* SIP Service AVP */
00733         if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING, 
00734         SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) {
00735                 LM_ERR("failed to create AVP:no more free memory!\n");
00736                 goto error;
00737         }
00738         if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
00739                 LM_ERR("avp not added \n");
00740                 AAAFreeAVP(&avp);
00741                 goto error;
00742         }
00743 
00744         /* also the extra attributes */
00745         attr_cnt += extra2strar( dia_extra, req, val_arr, int_arr, type_arr);
00746 
00747         /* add attributes */
00748         for(i=0; i<attr_cnt; i++) {
00749                 if((avp=AAACreateAVP(diam_attrs[i], 0,0, val_arr[i].s, val_arr[i].len,
00750                 AVP_DUPLICATE_DATA)) == 0) {
00751                         LM_ERR("failed to create AVP: no more free memory!\n");
00752                         goto error;
00753                 }
00754                 if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
00755                         LM_ERR("avp not added \n");
00756                         AAAFreeAVP(&avp);
00757                         goto error;
00758                 }
00759         }
00760 
00761         /* and the leg attributes */
00762         if ( leg_info ) {
00763                 cnt = legs2strar(leg_info,req,val_arr,int_arr,type_arr,1);
00764                 do {
00765                         for (i=0; i<cnt; i++) {
00766                                 if((avp=AAACreateAVP(diam_attrs[attr_cnt+i], 0, 0,
00767                                 val_arr[i].s, val_arr[i].len, AVP_DUPLICATE_DATA)) == 0) {
00768                                         LM_ERR("failed to create AVP: no more free memory!\n");
00769                                         goto error;
00770                                 }
00771                                 if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
00772                                         LM_ERR("avp not added \n");
00773                                         AAAFreeAVP(&avp);
00774                                         goto error;
00775                                 }
00776                         }
00777                 } while ( (cnt=legs2strar(leg_info,req,val_arr,int_arr,
00778                                           type_arr,0))!=0 );
00779         }
00780 
00781         if (get_uri(req, &uri) < 0) {
00782                 LM_ERR("failed to get uri, From/To URI not found\n");
00783                 goto error;
00784         }
00785 
00786         if (parse_uri(uri->s, uri->len, &puri) < 0) {
00787                 LM_ERR("failed to parse From/To URI\n");
00788                 goto error;
00789         }
00790 
00791         /* Destination-Realm AVP */
00792         if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s,
00793         puri.host.len, AVP_DUPLICATE_DATA)) == 0) {
00794                 LM_ERR("failed to create AVP:no more free memory!\n");
00795                 goto error;
00796         }
00797 
00798         if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
00799                 LM_ERR("avp not added \n");
00800                 AAAFreeAVP(&avp);
00801                 goto error;
00802         }
00803 
00804         /* prepare the message to be sent over the network */
00805         if(AAABuildMsgBuffer(send) != AAA_ERR_SUCCESS) {
00806                 LM_ERR("message buffer not created\n");
00807                 goto error;
00808         }
00809 
00810         if(sockfd==AAA_NO_CONNECTION) {
00811                 sockfd = init_mytcp(diameter_client_host, diameter_client_port);
00812                 if(sockfd==AAA_NO_CONNECTION) {
00813                         LM_ERR("failed to reconnect to Diameter client\n");
00814                         goto error;
00815                 }
00816         }
00817 
00818         /* send the message to the DIAMETER client */
00819         ret = tcp_send_recv(sockfd, send->buf.s, send->buf.len, rb, req->id);
00820         if(ret == AAA_CONN_CLOSED) {
00821                 LM_NOTICE("connection to Diameter client closed.It will be "
00822                                 "reopened by the next request\n");
00823                 close(sockfd);
00824                 sockfd = AAA_NO_CONNECTION;
00825                 goto error;
00826         }
00827 
00828         if(ret != ACC_SUCCESS) {
00829                 /* a transmission error occurred */
00830                 LM_ERR("message sending to the DIAMETER backend authorization "
00831                                 "server failed\n");
00832                 goto error;
00833         }
00834 
00835         AAAFreeMessage(&send);
00836         return 1;
00837 
00838 error:
00839         AAAFreeMessage(&send);
00840         return -1;
00841 }
00842 
00843 #endif
00844 
00848 int acc_run_engines(struct sip_msg *msg, int type, int *reset)
00849 {
00850         acc_info_t inf;
00851         acc_engine_t *e;
00852 
00853         e = acc_api_get_engines();
00854 
00855         if(e==NULL)
00856                 return 0;
00857 
00858         memset(&inf, 0, sizeof(acc_info_t));
00859         inf.env  = &acc_env;
00860         inf.varr = val_arr;
00861         inf.iarr = int_arr;
00862         inf.tarr = type_arr;
00863         inf.leg_info = leg_info;
00864         while(e) {
00865                 if(e->flags & 1) {
00866                         if((type==0) && (msg->flags&(e->acc_flag))) {
00867                                 LM_DBG("acc event for engine: %s\n", e->name);
00868                                 e->acc_req(msg, &inf);
00869                                 if(reset) *reset |= e->acc_flag;
00870                         }
00871                         if((type==1) && (msg->flags&(e->missed_flag))) {
00872                                 LM_DBG("missed event for engine: %s\n", e->name);
00873                                 e->acc_req(msg, &inf);
00874                                 if(reset) *reset |= e->missed_flag;
00875                         }
00876                 }
00877                 e = e->next;
00878         }
00879         return 0;
00880 }
00881 
00885 void acc_api_set_arrays(acc_info_t *inf)
00886 {
00887         inf->varr = val_arr;
00888         inf->iarr = int_arr;
00889         inf->tarr = type_arr;
00890         inf->leg_info = leg_info;
00891 }
00892