00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00038 #include "../../modules/tm/tm_load.h"
00039 #include "../../str.h"
00040 #include "../dialog/dlg_load.h"
00041
00042 #include "acc_api.h"
00043 #include "acc_cdr.h"
00044 #include "acc_mod.h"
00045 #include "acc_extra.h"
00046 #include "acc.h"
00047
00048 #include <sys/time.h>
00049
00050
00051 #ifdef __OS_solaris
00052 #define timersub(tvp, uvp, vvp) \
00053 do { \
00054 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
00055 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
00056 if ((vvp)->tv_usec < 0) { \
00057 (vvp)->tv_sec--; \
00058 (vvp)->tv_usec += 1000000; \
00059 } \
00060 } while (0)
00061 #endif // __OS_solaris
00062
00063 #define TIME_STR_BUFFER_SIZE 20
00064 #define TIME_BUFFER_LENGTH 256
00065
00066 struct dlg_binds dlgb;
00067 struct acc_extra* cdr_extra = NULL;
00068 int cdr_facility = LOG_DAEMON;
00069
00070 static const str zero_duration = { "0", 1};
00071 static const char time_separator = {'.'};
00072 static char time_buffer[ TIME_BUFFER_LENGTH];
00073 static const str empty_string = { "", 0};
00074
00075
00076 static str cdr_attrs[ MAX_CDR_CORE + MAX_CDR_EXTRA];
00077 static str cdr_value_array[ MAX_CDR_CORE + MAX_CDR_EXTRA];
00078 static int cdr_int_arr[ MAX_CDR_CORE + MAX_CDR_EXTRA];
00079 static char cdr_type_array[ MAX_CDR_CORE + MAX_CDR_EXTRA];
00080
00081 extern struct tm_binds tmb;
00082 extern str cdr_start_str;
00083 extern str cdr_end_str;
00084 extern str cdr_duration_str;
00085
00086
00087 static int cdr_core2strar( struct dlg_cell* dlg,
00088 str* values,
00089 int* unused,
00090 char* types)
00091 {
00092 str* start = NULL;
00093 str* end = NULL;
00094 str* duration = NULL;
00095
00096 if( !dlg || !values || !types)
00097 {
00098 LM_ERR( "invalid input parameter!\n");
00099 return 0;
00100 }
00101
00102 start = dlgb.get_dlg_var( dlg, (str*)&cdr_start_str);
00103 end = dlgb.get_dlg_var( dlg, (str*)&cdr_end_str);
00104 duration = dlgb.get_dlg_var( dlg, (str*)&cdr_duration_str);
00105
00106 values[0] = ( start != NULL ? *start : empty_string);
00107 types[0] = ( start != NULL ? TYPE_STR : TYPE_NULL);
00108
00109 values[1] = ( end != NULL ? *end : empty_string);
00110 types[1] = ( end != NULL ? TYPE_STR : TYPE_NULL);
00111
00112 values[2] = ( duration != NULL ? *duration : empty_string);
00113 types[2] = ( duration != NULL ? TYPE_STR : TYPE_NULL);
00114
00115 return MAX_CDR_CORE;
00116 }
00117
00118
00119 static int write_cdr( struct dlg_cell* dialog,
00120 struct sip_msg* message)
00121 {
00122 static char cdr_message[ MAX_SYSLOG_SIZE];
00123 static char* const cdr_message_end = cdr_message +
00124 MAX_SYSLOG_SIZE -
00125 2;
00126 char* message_position = NULL;
00127 int message_index = 0;
00128 int counter = 0;
00129
00130 if( !dialog || !message)
00131 {
00132 LM_ERR( "dialog and/or message is/are empty!");
00133 return -1;
00134 }
00135
00136
00137 message_index = cdr_core2strar( dialog,
00138 cdr_value_array,
00139 cdr_int_arr,
00140 cdr_type_array);
00141
00142
00143 message_index += extra2strar( cdr_extra,
00144 message,
00145 cdr_value_array + message_index,
00146 cdr_int_arr + message_index,
00147 cdr_type_array + message_index);
00148
00149 for( counter = 0, message_position = cdr_message;
00150 counter < message_index ;
00151 counter++ )
00152 {
00153 const char* const next_message_end = message_position +
00154 2 +
00155 cdr_attrs[ counter].len +
00156 1 +
00157 cdr_value_array[ counter].len;
00158
00159 if( next_message_end >= cdr_message_end ||
00160 next_message_end < message_position)
00161 {
00162 LM_WARN("cdr message too long, truncating..\n");
00163 message_position = cdr_message_end;
00164 break;
00165 }
00166
00167 if( counter > 0)
00168 {
00169 *(message_position++) = A_SEPARATOR_CHR;
00170 *(message_position++) = A_SEPARATOR_CHR_2;
00171 }
00172
00173 memcpy( message_position,
00174 cdr_attrs[ counter].s,
00175 cdr_attrs[ counter].len);
00176
00177 message_position += cdr_attrs[ counter].len;
00178
00179 *( message_position++) = A_EQ_CHR;
00180
00181 memcpy( message_position,
00182 cdr_value_array[ counter].s,
00183 cdr_value_array[ counter].len);
00184
00185 message_position += cdr_value_array[ counter].len;
00186 }
00187
00188
00189 *(message_position++) = '\n';
00190 *(message_position++) = '\0';
00191
00192 LM_GEN2( cdr_facility, log_level, "%s", cdr_message);
00193
00194 return 0;
00195 }
00196
00197
00198 static int string2time( str* time_str, struct timeval* time_value)
00199 {
00200 char* dot_address = NULL;
00201 int dot_position = -1;
00202 char zero_terminated_value[TIME_STR_BUFFER_SIZE];
00203
00204 if( !time_str)
00205 {
00206 LM_ERR( "time_str is empty!");
00207 return -1;
00208 }
00209
00210 if( time_str->len >= TIME_STR_BUFFER_SIZE)
00211 {
00212 LM_ERR( "time_str is too long %d >= %d!",
00213 time_str->len,
00214 TIME_STR_BUFFER_SIZE);
00215 return -1;
00216 }
00217
00218 memcpy( zero_terminated_value, time_str->s, time_str->len);
00219 zero_terminated_value[time_str->len] = '\0';
00220
00221 dot_address = strchr( zero_terminated_value, time_separator);
00222
00223 if( !dot_address)
00224 {
00225 LM_ERR( "failed to find separator('%c') in '%s'!\n",
00226 time_separator,
00227 zero_terminated_value);
00228 return -1;
00229 }
00230
00231 dot_position = dot_address-zero_terminated_value + 1;
00232
00233 if( dot_position >= strlen(zero_terminated_value) ||
00234 strchr(dot_address + 1, time_separator))
00235 {
00236 LM_ERR( "invalid time-string '%s'\n", zero_terminated_value);
00237 return -1;
00238 }
00239
00240 time_value->tv_sec = strtol( zero_terminated_value, (char **)NULL, 10);
00241 time_value->tv_usec = strtol( dot_address + 1, (char **)NULL, 10) * 1000;
00242 return 0;
00243 }
00244
00245
00246 static int time2string( struct timeval* time_value, str* time_str)
00247 {
00248 int buffer_length;
00249
00250 if( !time_value)
00251 {
00252 LM_ERR( "time_value or any of its fields is empty!\n");
00253 return -1;
00254 }
00255
00256 buffer_length = snprintf( time_buffer,
00257 TIME_BUFFER_LENGTH,
00258 "%ld%c%03d",
00259 (long int)time_value->tv_sec,
00260 time_separator,
00261 (int)(time_value->tv_usec/1000));
00262
00263 if( buffer_length < 0)
00264 {
00265 LM_ERR( "failed to write to buffer.\n");
00266 return -1;
00267 }
00268
00269 time_str->s = time_buffer;
00270 time_str->len = buffer_length;
00271 return 0;
00272 }
00273
00274
00275 static int set_duration( struct dlg_cell* dialog)
00276 {
00277 struct timeval start_time;
00278 struct timeval end_time;
00279 struct timeval duration_time;
00280 str duration_str;
00281
00282 if( !dialog)
00283 {
00284 LM_ERR("dialog is empty!\n");
00285 return -1;
00286 }
00287
00288 if ( string2time( dlgb.get_dlg_var( dialog, (str*)&cdr_start_str), &start_time) < 0) {
00289 LM_ERR( "failed to extract start time\n");
00290 return -1;
00291 }
00292 if ( string2time( dlgb.get_dlg_var( dialog, (str*)&cdr_end_str), &end_time) < 0) {
00293 LM_ERR( "failed to extract end time\n");
00294 return -1;
00295 }
00296
00297 timersub(&end_time, &start_time, &duration_time);
00298
00299 if( time2string(&duration_time, &duration_str) < 0) {
00300 LM_ERR( "failed to convert current time to string\n");
00301 return -1;
00302 }
00303
00304 if( dlgb.set_dlg_var( dialog,
00305 (str*)&cdr_duration_str,
00306 (str*)&duration_str) != 0)
00307 {
00308 LM_ERR( "failed to set duration time");
00309 return -1;
00310 }
00311
00312 return 0;
00313 }
00314
00315
00316 static int set_start_time( struct dlg_cell* dialog)
00317 {
00318 struct timeval current_time;
00319 str start_time;
00320
00321 if( !dialog)
00322 {
00323 LM_ERR("dialog is empty!\n");
00324 return -1;
00325 }
00326
00327 if( gettimeofday( ¤t_time, NULL) < 0)
00328 {
00329 LM_ERR( "failed to get current time!\n");
00330 return -1;
00331 }
00332
00333 if( time2string(¤t_time, &start_time) < 0) {
00334 LM_ERR( "failed to convert current time to string\n");
00335 return -1;
00336 }
00337
00338 if( dlgb.set_dlg_var( dialog,
00339 (str*)&cdr_start_str,
00340 (str*)&start_time) != 0)
00341 {
00342 LM_ERR( "failed to set start time\n");
00343 return -1;
00344 }
00345
00346 if( dlgb.set_dlg_var( dialog,
00347 (str*)&cdr_end_str,
00348 (str*)&start_time) != 0)
00349 {
00350 LM_ERR( "failed to set initiation end time\n");
00351 return -1;
00352 }
00353
00354 if( dlgb.set_dlg_var( dialog,
00355 (str*)&cdr_duration_str,
00356 (str*)&zero_duration) != 0)
00357 {
00358 LM_ERR( "failed to set initiation duration time\n");
00359 return -1;
00360 }
00361
00362 return 0;
00363 }
00364
00365
00366 static int set_end_time( struct dlg_cell* dialog)
00367 {
00368 struct timeval current_time;
00369 str end_time;
00370
00371 if( !dialog)
00372 {
00373 LM_ERR("dialog is empty!\n");
00374 return -1;
00375 }
00376
00377 if( gettimeofday( ¤t_time, NULL) < 0)
00378 {
00379 LM_ERR( "failed to set time!\n");
00380 return -1;
00381 }
00382
00383 if( time2string(¤t_time, &end_time) < 0) {
00384 LM_ERR( "failed to convert current time to string\n");
00385 return -1;
00386 }
00387
00388 if( dlgb.set_dlg_var( dialog,
00389 (str*)&cdr_end_str,
00390 (str*)&end_time) != 0)
00391 {
00392 LM_ERR( "failed to set start time");
00393 return -1;
00394 }
00395
00396 return 0;
00397 }
00398
00399
00400 static void cdr_on_start( struct dlg_cell* dialog,
00401 int type,
00402 struct dlg_cb_params* params)
00403 {
00404 if( !dialog || !params)
00405 {
00406 LM_ERR("invalid values\n!");
00407 return;
00408 }
00409
00410 if( cdr_start_on_confirmed == 0)
00411 {
00412 return;
00413 }
00414
00415 if( set_start_time( dialog) != 0)
00416 {
00417 LM_ERR( "failed to set start time!\n");
00418 return;
00419 }
00420 }
00421
00422
00423 static void cdr_on_failed( struct dlg_cell* dialog,
00424 int type,
00425 struct dlg_cb_params* params)
00426 {
00427 struct sip_msg* msg = 0;
00428
00429 if( !dialog || !params)
00430 {
00431 LM_ERR("invalid values\n!");
00432 return;
00433 }
00434
00435 if( params->rpl && params->rpl != FAKED_REPLY)
00436 {
00437 msg = params->rpl;
00438 }
00439 else if( params->req)
00440 {
00441 msg = params->req;
00442 }
00443 else
00444 {
00445 LM_ERR( "request and response are invalid!");
00446 return;
00447 }
00448
00449 if( write_cdr( dialog, msg) != 0)
00450 {
00451 LM_ERR( "failed to write cdr!\n");
00452 return;
00453 }
00454 }
00455
00456
00457 void cdr_on_end_confirmed( struct dlg_cell* dialog,
00458 int type,
00459 struct dlg_cb_params* params)
00460 {
00461 if( !dialog || !params || !params->req)
00462 {
00463 LM_ERR("invalid values\n!");
00464 return;
00465 }
00466
00467 if( write_cdr( dialog, params->req) != 0)
00468 {
00469 LM_ERR( "failed to write cdr!\n");
00470 return;
00471 }
00472 }
00473
00474
00475 static void cdr_on_end( struct dlg_cell* dialog,
00476 int type,
00477 struct dlg_cb_params* params)
00478 {
00479 if( !dialog || !params || !params->req)
00480 {
00481 LM_ERR("invalid values\n!");
00482 return;
00483 }
00484
00485 if( set_end_time( dialog) != 0)
00486 {
00487 LM_ERR( "failed to set end time!\n");
00488 return;
00489 }
00490
00491 if( set_duration( dialog) != 0)
00492 {
00493 LM_ERR( "failed to set duration!\n");
00494 return;
00495 }
00496 }
00497
00498
00499 static void cdr_on_expired( struct dlg_cell* dialog,
00500 int type,
00501 struct dlg_cb_params* params)
00502 {
00503 if( !dialog || !params)
00504 {
00505 LM_ERR("invalid values\n!");
00506 return;
00507 }
00508
00509 LM_DBG("dialog '%p' expired!\n", dialog);
00510 }
00511
00512
00513 static void cdr_on_destroy( struct dlg_cell* dialog,
00514 int type,
00515 struct dlg_cb_params* params)
00516 {
00517 if( !dialog || !params)
00518 {
00519 LM_ERR("invalid values\n!");
00520 return;
00521 }
00522
00523 LM_DBG("dialog '%p' destroyed!\n", dialog);
00524 }
00525
00526
00527 static void cdr_on_create( struct dlg_cell* dialog,
00528 int type,
00529 struct dlg_cb_params* params)
00530 {
00531 if( !dialog || !params || !params->req)
00532 {
00533 LM_ERR( "invalid values\n!");
00534 return;
00535 }
00536
00537 if( cdr_enable == 0)
00538 {
00539 return;
00540 }
00541
00542 if( dlgb.register_dlgcb( dialog, DLGCB_CONFIRMED, cdr_on_start, 0, 0) != 0)
00543 {
00544 LM_ERR("can't register create dialog CONFIRM callback\n");
00545 return;
00546 }
00547
00548 if( dlgb.register_dlgcb( dialog, DLGCB_FAILED, cdr_on_failed, 0, 0) != 0)
00549 {
00550 LM_ERR("can't register create dialog FAILED callback\n");
00551 return;
00552 }
00553
00554 if( dlgb.register_dlgcb( dialog, DLGCB_TERMINATED, cdr_on_end, 0, 0) != 0)
00555 {
00556 LM_ERR("can't register create dialog TERMINATED callback\n");
00557 return;
00558 }
00559
00560 if( dlgb.register_dlgcb( dialog, DLGCB_TERMINATED_CONFIRMED, cdr_on_end_confirmed, 0, 0) != 0)
00561 {
00562 LM_ERR("can't register create dialog TERMINATED CONFIRMED callback\n");
00563 return;
00564 }
00565
00566 if( dlgb.register_dlgcb( dialog, DLGCB_EXPIRED, cdr_on_expired, 0, 0) != 0)
00567 {
00568 LM_ERR("can't register create dialog EXPIRED callback\n");
00569 return;
00570 }
00571
00572 if( dlgb.register_dlgcb( dialog, DLGCB_DESTROY, cdr_on_destroy, 0, 0) != 0)
00573 {
00574 LM_ERR("can't register create dialog DESTROY callback\n");
00575 return;
00576 }
00577
00578 LM_DBG("dialog '%p' created!", dialog);
00579
00580 if( set_start_time( dialog) != 0)
00581 {
00582 LM_ERR( "failed to set start time");
00583 return;
00584 }
00585 }
00586
00587 int set_cdr_extra( char* cdr_extra_value)
00588 {
00589 struct acc_extra* extra = 0;
00590 int counter = 0;
00591
00592 if( cdr_extra_value && ( cdr_extra = parse_acc_extra( cdr_extra_value))==0)
00593 {
00594 LM_ERR("failed to parse crd_extra param\n");
00595 return -1;
00596 }
00597
00598
00599 cdr_attrs[ counter++] = cdr_start_str;
00600 cdr_attrs[ counter++] = cdr_end_str;
00601 cdr_attrs[ counter++] = cdr_duration_str;
00602
00603 for(extra=cdr_extra; extra ; extra=extra->next)
00604 {
00605 cdr_attrs[ counter++] = extra->name;
00606 }
00607
00608 return 0;
00609 }
00610
00611
00612 int set_cdr_facility( char* cdr_facility_str)
00613 {
00614 int facility_id = -1;
00615
00616 if( !cdr_facility_str)
00617 {
00618 LM_ERR( "facility is empty\n");
00619 return -1;
00620 }
00621
00622 facility_id = str2facility( cdr_facility_str);
00623
00624 if( facility_id == -1)
00625 {
00626 LM_ERR("invalid cdr facility configured\n");
00627 return -1;
00628 }
00629
00630 cdr_facility = facility_id;
00631
00632 return 0;
00633 }
00634
00635
00636 int init_cdr_generation( void)
00637 {
00638 if( load_dlg_api( &dlgb) != 0)
00639 {
00640 LM_ERR("can't load dialog API\n");
00641 return -1;
00642 }
00643
00644 if( dlgb.register_dlgcb( 0, DLGCB_CREATED, cdr_on_create, 0, 0) != 0)
00645 {
00646 LM_ERR("can't register create callback\n");
00647 return -1;
00648 }
00649
00650 return 0;
00651 }
00652
00653
00654 void destroy_cdr_generation( void)
00655 {
00656 if( !cdr_extra)
00657 {
00658 return;
00659 }
00660
00661 destroy_extras( cdr_extra);
00662 }