acc.c

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

Generated on Thu May 17 12:00:24 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6