static int build_csv_record(char *buf, size_t bufsize, struct ast_cdr *cdr) { buf[0] = '\0'; /* Account code */ append_string(buf, cdr->accountcode, bufsize); /* Source */ append_string(buf, cdr->src, bufsize); /* Destination */ append_string(buf, cdr->dst, bufsize); /* Destination context */ append_string(buf, cdr->dcontext, bufsize); /* Caller*ID */ append_string(buf, cdr->clid, bufsize); /* Channel */ append_string(buf, cdr->channel, bufsize); /* Destination Channel */ append_string(buf, cdr->dstchannel, bufsize); /* Last Application */ append_string(buf, cdr->lastapp, bufsize); /* Last Data */ append_string(buf, cdr->lastdata, bufsize); /* Start Time */ append_date(buf, cdr->start, bufsize); /* Answer Time */ append_date(buf, cdr->answer, bufsize); /* End Time */ append_date(buf, cdr->end, bufsize); /* Duration */ append_int(buf, cdr->duration, bufsize); /* Billable seconds */ append_int(buf, cdr->billsec, bufsize); /* Disposition */ append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); /* AMA Flags */ append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); #ifdef CSV_LOGUNIQUEID /* Unique ID */ append_string(buf, cdr->uniqueid, bufsize); #endif #ifdef CSV_LOGUSERFIELD /* append the user field */ append_string(buf, cdr->userfield,bufsize); #endif /* If we hit the end of our buffer, log an error */ if (strlen(buf) < bufsize - 5) { /* Trim off trailing comma */ buf[strlen(buf) - 1] = '\0'; strncat(buf, "\n", bufsize - strlen(buf) - 1); return 0; } return -1; }
static int manager_log(struct ast_cdr *cdr) { time_t t; struct tm timeresult; char strStartTime[80] = ""; char strAnswerTime[80] = ""; char strEndTime[80] = ""; if (!enablecdr) return 0; t = cdr->start.tv_sec; localtime_r(&t, &timeresult); strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult); if (cdr->answer.tv_sec) { t = cdr->answer.tv_sec; localtime_r(&t, &timeresult); strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult); } t = cdr->end.tv_sec; localtime_r(&t, &timeresult); strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult); manager_event(EVENT_FLAG_CALL, "Cdr", "AccountCode: %s\r\n" "Source: %s\r\n" "Destination: %s\r\n" "DestinationContext: %s\r\n" "CallerID: %s\r\n" "Channel: %s\r\n" "DestinationChannel: %s\r\n" "LastApplication: %s\r\n" "LastData: %s\r\n" "StartTime: %s\r\n" "AnswerTime: %s\r\n" "EndTime: %s\r\n" "Duration: %d\r\n" "BillableSeconds: %d\r\n" "Disposition: %s\r\n" "AMAFlags: %s\r\n" "UniqueID: %s\r\n" "UserField: %s\r\n", cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield); return 0; }
static int mongodb_log(struct ast_cdr *cdr) { const char * ns; mongo conn[1]; ast_debug(1, "mongodb: Starting mongodb_log.\n"); mongo_init( &conn ); if (mongo_connect( &conn , ast_str_buffer(hostname), dbport ) != MONGO_OK){ mongo_destroy( &conn ); ast_log(LOG_ERROR, "Method: mongodb_log, MongoDB failed to connect.\n"); connected = 0; records = 0; return -1; } if (ast_str_strlen(dbuser) != 0 && (mongo_cmd_authenticate(&conn, ast_str_buffer(dbname), ast_str_buffer(dbuser), ast_str_buffer(password)) != MONGO_OK)) { mongo_destroy( &conn ); ast_log(LOG_ERROR, "Method: mongodb_log, MongoDB failed to authenticate to do %s with username %s!\n", ast_str_buffer(dbname), ast_str_buffer(dbuser)); connected = 0; records = 0; return -1; } ast_debug(1, "mongodb: Locking mongodb_lock.\n"); ast_mutex_lock(&mongodb_lock); ast_debug(1, "mongodb: Got connection, Preparing record.\n"); bson b[1]; ast_debug(1, "mongodb: Init bson.\n"); bson_init( &b ); bson_append_new_oid( &b, "_id" ); ast_debug(1, "mongodb: accountcode.\n"); bson_append_string( &b , "accountcode", cdr->accountcode); ast_debug(1, "mongodb: src.\n"); bson_append_string( &b , "src", cdr->src); ast_debug(1, "mongodb: dst.\n"); bson_append_string( &b, "dst" , cdr->dst ); ast_debug(1, "mongodb: dcontext.\n"); bson_append_string( &b, "dcontext" , cdr->dcontext ); ast_debug(1, "mongodb: clid.\n"); bson_append_string( &b, "clid" , cdr->clid ); ast_debug(1, "mongodb: channel.\n"); bson_append_string( &b, "channel" , cdr->channel ); ast_debug(1, "mongodb: dstchannel.\n"); bson_append_string( &b, "dstchannel" , cdr->dstchannel ); ast_debug(1, "mongodb: lastapp.\n"); bson_append_string( &b, "lastapp" , cdr->lastapp ); ast_debug(1, "mongodb: lastdata.\n"); bson_append_string( &b, "lastdata" , cdr->lastdata ); ast_debug(1, "mongodb: start.\n"); bson_append_date( &b, "start", (bson_date_t)cdr->start.tv_sec*1000); ast_debug(1, "mongodb: answer.\n"); bson_append_date( &b, "answer", (bson_date_t)cdr->answer.tv_sec*1000); ast_debug(1, "mongodb: end.\n"); bson_append_date( &b, "end" , (bson_date_t)cdr->end.tv_sec*1000); ast_debug(1, "mongodb: duration.\n"); bson_append_int( &b, "duration" , cdr->duration ); ast_debug(1, "mongodb: billsec.\n"); bson_append_int( &b, "billsec" , cdr->billsec ); ast_debug(1, "mongodb: disposition.\n"); bson_append_string( &b, "disposition" , ast_cdr_disp2str(cdr->disposition) ); ast_debug(1, "mongodb: amaflags.\n"); bson_append_string( &b, "amaflags" , ast_cdr_flags2str(cdr->amaflags) ); ast_debug(1, "mongodb: uniqueid.\n"); bson_append_string( &b, "uniqueid" , cdr->uniqueid ); ast_debug(1, "mongodb: userfield.\n"); bson_append_string( &b, "userfield" , cdr->userfield ); bson_finish(&b); ast_debug(1, "mongodb: Inserting a CDR record.\n"); mongo_insert( &conn , ast_str_buffer(dbnamespace) , &b ); bson_destroy(&b); mongo_destroy( &conn ); connected = 1; records++; totalrecords++; ast_debug(1, "Unlocking mongodb_lock.\n"); ast_mutex_unlock(&mongodb_lock); return 0; }
static int csv_log(struct ast_cdr *cdr) { FILE *mf = NULL; /* Make sure we have a big enough buf */ char buf[1024]; char csvmaster[PATH_MAX]; snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); #if 0 printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode); #endif if (build_csv_record(buf, sizeof(buf), cdr)) { ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); return 0; } /* because of the absolutely unconditional need for the highest reliability possible in writing billing records, we open write and close the log file each time */ ast_mutex_lock(&mf_lock); if ((mf = fopen(csvmaster, "a"))) { fputs(buf, mf); fflush(mf); /* be particularly anal here */ fclose(mf); mf = NULL; ast_mutex_unlock(&mf_lock); } else { ast_mutex_unlock(&mf_lock); ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno)); } if (!ast_strlen_zero(cdr->accountcode)) { if (writefile(buf, cdr->accountcode)) ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno)); } return 0; }
static int tds_log(struct ast_cdr *cdr) { char sqlcmd[2048], start[80], answer[80], end[80]; char *accountcode, *src, *dst, *dcontext, *clid, *channel, *dstchannel, *lastapp, *lastdata, *uniqueid; int res = 0; int retried = 0; #ifdef FREETDS_PRE_0_62 TDS_INT result_type; #endif ast_mutex_lock(&tds_lock); memset(sqlcmd, 0, 2048); accountcode = anti_injection(cdr->accountcode, 20); src = anti_injection(cdr->src, 80); dst = anti_injection(cdr->dst, 80); dcontext = anti_injection(cdr->dcontext, 80); clid = anti_injection(cdr->clid, 80); channel = anti_injection(cdr->channel, 80); dstchannel = anti_injection(cdr->dstchannel, 80); lastapp = anti_injection(cdr->lastapp, 80); lastdata = anti_injection(cdr->lastdata, 80); uniqueid = anti_injection(cdr->uniqueid, 32); get_date(start, cdr->start); get_date(answer, cdr->answer); get_date(end, cdr->end); sprintf( sqlcmd, "INSERT INTO cdr " "(" "accountcode, " "src, " "dst, " "dcontext, " "clid, " "channel, " "dstchannel, " "lastapp, " "lastdata, " "start, " "answer, " "[end], " "duration, " "billsec, " "disposition, " "amaflags, " "uniqueid" ") " "VALUES " "(" "'%s', " /* accountcode */ "'%s', " /* src */ "'%s', " /* dst */ "'%s', " /* dcontext */ "'%s', " /* clid */ "'%s', " /* channel */ "'%s', " /* dstchannel */ "'%s', " /* lastapp */ "'%s', " /* lastdata */ "%s, " /* start */ "%s, " /* answer */ "%s, " /* end */ "%ld, " /* duration */ "%ld, " /* billsec */ "'%s', " /* disposition */ "'%s', " /* amaflags */ "'%s'" /* uniqueid */ ")", accountcode, src, dst, dcontext, clid, channel, dstchannel, lastapp, lastdata, start, answer, end, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), uniqueid ); do { if (!connected) { if (mssql_connect()) ast_log(LOG_ERROR, "Failed to reconnect to SQL database.\n"); else ast_log(LOG_WARNING, "Reconnected to SQL database.\n"); retried = 1; /* note that we have now tried */ } #ifdef FREETDS_PRE_0_62 if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds, &result_type) != TDS_SUCCEED || result_type != TDS_CMD_SUCCEED)) #else if (!connected || (tds_submit_query(tds, sqlcmd) != TDS_SUCCEED) || (tds_process_simple_query(tds) != TDS_SUCCEED)) #endif { ast_log(LOG_ERROR, "Failed to insert Call Data Record into SQL database.\n"); mssql_disconnect(); /* this is ok even if we are already disconnected */ } } while (!connected && !retried); free(accountcode); free(src); free(dst); free(dcontext); free(clid); free(channel); free(dstchannel); free(lastapp); free(lastdata); free(uniqueid); ast_mutex_unlock(&tds_lock); return res; }
static int manager_log(struct ast_cdr *cdr) { struct ast_tm timeresult; char strStartTime[80] = ""; char strAnswerTime[80] = ""; char strEndTime[80] = ""; char buf[CUSTOM_FIELDS_BUF_SIZE]; if (!enablecdr) return 0; ast_localtime(&cdr->start, &timeresult, NULL); ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult); if (cdr->answer.tv_sec) { ast_localtime(&cdr->answer, &timeresult, NULL); ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult); } ast_localtime(&cdr->end, &timeresult, NULL); ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult); buf[0] = '\0'; ast_rwlock_rdlock(&customfields_lock); if (customfields && ast_str_strlen(customfields)) { struct ast_channel *dummy = ast_dummy_channel_alloc(); if (!dummy) { ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n"); return 0; } dummy->cdr = ast_cdr_dup(cdr); pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1); ast_channel_unref(dummy); } ast_rwlock_unlock(&customfields_lock); manager_event(EVENT_FLAG_CDR, "Cdr", "AccountCode: %s\r\n" "Source: %s\r\n" "Destination: %s\r\n" "DestinationContext: %s\r\n" "CallerID: %s\r\n" "Channel: %s\r\n" "DestinationChannel: %s\r\n" "LastApplication: %s\r\n" "LastData: %s\r\n" "StartTime: %s\r\n" "AnswerTime: %s\r\n" "EndTime: %s\r\n" "Duration: %ld\r\n" "BillableSeconds: %ld\r\n" "Disposition: %s\r\n" "AMAFlags: %s\r\n" "UniqueID: %s\r\n" "UserField: %s\r\n" "%s", cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf); return 0; }
static int odbc_log(struct ast_cdr *cdr) { int ODBC_res; char sqlcmd[2048] = "", timestr[128]; int res = 0; struct tm tm; if (usegmtime) gmtime_r(&cdr->start.tv_sec,&tm); else ast_localtime(&cdr->start.tv_sec, &tm, NULL); ast_mutex_lock(&odbc_lock); strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); memset(sqlcmd,0,2048); if (loguniqueid) { snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp," "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) " "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table); } else { snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata," "duration,billsec,disposition,amaflags,accountcode) " "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table); } if (!connected) { res = odbc_init(); if (res < 0) { odbc_disconnect(); ast_mutex_unlock(&odbc_lock); return 0; } } ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, ODBC_con, &ODBC_stmt); if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res); SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); odbc_disconnect(); ast_mutex_unlock(&odbc_lock); return 0; } /* We really should only have to do this once. But for some strange reason if I don't it blows holes in memory like like a shotgun. So we just do this so its safe. */ ODBC_res = SQLPrepare(ODBC_stmt, (unsigned char *)sqlcmd, SQL_NTS); if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Error in PREPARE %d\n", ODBC_res); SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); odbc_disconnect(); ast_mutex_unlock(&odbc_lock); return 0; } SQLBindParameter(ODBC_stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(timestr), 0, ×tr, 0, NULL); SQLBindParameter(ODBC_stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL); SQLBindParameter(ODBC_stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL); SQLBindParameter(ODBC_stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL); SQLBindParameter(ODBC_stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL); SQLBindParameter(ODBC_stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL); SQLBindParameter(ODBC_stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL); SQLBindParameter(ODBC_stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL); SQLBindParameter(ODBC_stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL); SQLBindParameter(ODBC_stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL); SQLBindParameter(ODBC_stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL); if (dispositionstring) SQLBindParameter(ODBC_stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL); else SQLBindParameter(ODBC_stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL); SQLBindParameter(ODBC_stmt, 13, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL); SQLBindParameter(ODBC_stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL); if (loguniqueid) { SQLBindParameter(ODBC_stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL); SQLBindParameter(ODBC_stmt, 16, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL); } if (connected) { res = odbc_do_query(); if (res < 0) { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n"); if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Reconnecting to dsn %s\n", dsn); SQLDisconnect(ODBC_con); res = odbc_init(); if (res < 0) { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: %s has gone away!\n", dsn); odbc_disconnect(); } else { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Trying Query again!\n"); res = odbc_do_query(); if (res < 0) { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n"); } } } } else { if (option_verbose > 10) ast_verbose( VERBOSE_PREFIX_4 "cdr_odbc: Query FAILED Call not logged!\n"); } SQLFreeHandle(SQL_HANDLE_STMT, ODBC_stmt); ast_mutex_unlock(&odbc_lock); return 0; }
static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data) { struct ast_cdr *cdr = data; SQLRETURN ODBC_res; char sqlcmd[2048] = "", timestr[128]; struct ast_tm tm; SQLHSTMT stmt; ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL); ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) { snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp," "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) " "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr); } else { snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata," "duration,billsec,disposition,amaflags,accountcode) " "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr); } ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; } SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL); SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL); SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL); SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL); SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL); SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL); SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL); SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL); if (ast_test_flag(&config, CONFIG_HRTIME)) { double hrbillsec = 0.0; double hrduration; if (!ast_tvzero(cdr->answer)) { hrbillsec = (double) ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0; } hrduration = (double) ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0; SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrduration, 0, NULL); SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrbillsec, 0, NULL); } else { SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL); SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL); } if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING)) SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL); else SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL); SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL); SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL); if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) { SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL); SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL); } ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS); if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; } return stmt; }
static int build_radius_record(VALUE_PAIR **tosend, struct ast_cdr *cdr) { int recordtype = PW_STATUS_STOP; struct ast_tm tm; char timestr[128]; char *tmp; if (!rc_avpair_add(rh, tosend, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) return -1; /* Account code */ if (!rc_avpair_add(rh, tosend, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE)) return -1; /* Source */ if (!rc_avpair_add(rh, tosend, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE)) return -1; /* Destination */ if (!rc_avpair_add(rh, tosend, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE)) return -1; /* Destination context */ if (!rc_avpair_add(rh, tosend, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE)) return -1; /* Caller ID */ if (!rc_avpair_add(rh, tosend, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE)) return -1; /* Channel */ if (!rc_avpair_add(rh, tosend, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE)) return -1; /* Destination Channel */ if (!rc_avpair_add(rh, tosend, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE)) return -1; /* Last Application */ if (!rc_avpair_add(rh, tosend, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE)) return -1; /* Last Data */ if (!rc_avpair_add(rh, tosend, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE)) return -1; /* Start Time */ ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, ast_localtime(&cdr->start, &tm, ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL)); if (!rc_avpair_add(rh, tosend, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE)) return -1; /* Answer Time */ ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, ast_localtime(&cdr->answer, &tm, ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL)); if (!rc_avpair_add(rh, tosend, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE)) return -1; /* End Time */ ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, ast_localtime(&cdr->end, &tm, ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL)); if (!rc_avpair_add(rh, tosend, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE)) return -1; /* Duration */ if (!rc_avpair_add(rh, tosend, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE)) return -1; /* Billable seconds */ if (!rc_avpair_add(rh, tosend, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE)) return -1; /* Disposition */ tmp = ast_cdr_disp2str(cdr->disposition); if (!rc_avpair_add(rh, tosend, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE)) return -1; /* AMA Flags */ tmp = ast_cdr_flags2str(cdr->amaflags); if (!rc_avpair_add(rh, tosend, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE)) return -1; if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) { /* Unique ID */ if (!rc_avpair_add(rh, tosend, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE)) return -1; } if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) { /* append the user field */ if (!rc_avpair_add(rh, tosend, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE)) return -1; } /* Setting Acct-Session-Id & User-Name attributes for proper generation of Acct-Unique-Session-Id on server side */ /* Channel */ if (!rc_avpair_add(rh, tosend, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0)) return -1; /* Unique ID */ if (!rc_avpair_add(rh, tosend, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0)) return -1; return 0; }
static int beanstalk_put(struct ast_cdr *cdr) { struct ast_tm timeresult; char strAnswerTime[80] = ""; char strStartTime[80]; char strEndTime[80]; char *cdr_buffer; int bs_id; int bs_socket; struct ast_json *t_cdr_json; if (!enablecdr) { return 0; } ast_rwlock_rdlock(&config_lock); bs_socket = bs_connect(bs_host, bs_port); if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) { ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port); ast_rwlock_unlock(&config_lock); return 0; } ast_localtime(&cdr->start, &timeresult, NULL); ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult); if (cdr->answer.tv_sec) { ast_localtime(&cdr->answer, &timeresult, NULL); ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult); } ast_localtime(&cdr->end, &timeresult, NULL); ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult); ast_rwlock_unlock(&config_lock); t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:s}", "AccountCode", S_OR(cdr->accountcode, ""), "Source", S_OR(cdr->src, ""), "Destination", S_OR(cdr->dst, ""), "DestinationContext", S_OR(cdr->dcontext, ""), "CallerID", S_OR(cdr->clid, ""), "Channel", S_OR(cdr->channel, ""), "DestinationChannel", S_OR(cdr->dstchannel, ""), "LastApplication", S_OR(cdr->lastapp, ""), "LastData", S_OR(cdr->lastdata, ""), "StartTime", S_OR(strStartTime, ""), "AnswerTime", S_OR(strAnswerTime, ""), "EndTime", S_OR(strEndTime, ""), "Duration", cdr->duration, "Billsec", cdr->billsec, "Disposition", S_OR(ast_cdr_disp2str(cdr->disposition), ""), "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""), "UniqueID", S_OR(cdr->uniqueid, ""), "UserField", S_OR(cdr->userfield, "")); cdr_buffer = ast_json_dump_string(t_cdr_json); ast_json_unref(t_cdr_json); bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cdr_buffer, strlen(cdr_buffer)); if (bs_id > 0) { ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cdr_buffer); } else { ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cdr_buffer); } bs_disconnect(bs_socket); ast_json_free(cdr_buffer); return 0; }
static int mongodb_log(struct ast_cdr *cdr) { int ret = -1; bson_t *doc = NULL; mongoc_collection_t *collection = NULL; if(dbpool == NULL) { ast_log(LOG_ERROR, "unexpected error, no connection pool\n"); return ret; } mongoc_client_t *dbclient = mongoc_client_pool_pop(dbpool); if(dbclient == NULL) { ast_log(LOG_ERROR, "unexpected error, no client allocated\n"); return ret; } do { bson_error_t error; doc = bson_new(); if(doc == NULL) { ast_log(LOG_ERROR, "cannot make a document\n"); break; } mongoc_collection_t *collection = mongoc_client_get_collection(dbclient, dbname, dbcollection); if(collection == NULL) { ast_log(LOG_ERROR, "cannot get such a collection, %s, %s\n", dbname, dbcollection); break; } BSON_APPEND_UTF8(doc, "clid", cdr->clid); BSON_APPEND_UTF8(doc, "src", cdr->src); BSON_APPEND_UTF8(doc, "dst", cdr->dst); BSON_APPEND_UTF8(doc, "dcontext", cdr->dcontext); BSON_APPEND_UTF8(doc, "channel", cdr->channel); BSON_APPEND_UTF8(doc, "dstchannel", cdr->dstchannel); BSON_APPEND_UTF8(doc, "lastapp", cdr->lastapp); BSON_APPEND_UTF8(doc, "lastdata", cdr->lastdata); BSON_APPEND_UTF8(doc, "disposition", ast_cdr_disp2str(cdr->disposition)); BSON_APPEND_UTF8(doc, "amaflags", ast_channel_amaflags2string(cdr->amaflags)); BSON_APPEND_UTF8(doc, "accountcode", cdr->accountcode); BSON_APPEND_UTF8(doc, "uniqueid", cdr->uniqueid); BSON_APPEND_UTF8(doc, "userfield", cdr->userfield); BSON_APPEND_UTF8(doc, "peeraccount", cdr->peeraccount); BSON_APPEND_UTF8(doc, "linkedid", cdr->linkedid); BSON_APPEND_INT32(doc, "duration", cdr->duration); BSON_APPEND_INT32(doc, "billsec", cdr->billsec); BSON_APPEND_INT32(doc, "sequence", cdr->sequence); BSON_APPEND_TIMEVAL(doc, "start", &cdr->start); BSON_APPEND_TIMEVAL(doc, "answer", &cdr->answer); BSON_APPEND_TIMEVAL(doc, "end", &cdr->end); if (serverid) BSON_APPEND_OID(doc, SERVERID, serverid); if(!mongoc_collection_insert(collection, MONGOC_INSERT_NONE, doc, NULL, &error)) ast_log(LOG_ERROR, "insertion failed, %s\n", error.message); ret = 0; // success } while(0); if (collection) mongoc_collection_destroy(collection); if (doc) bson_destroy(doc); mongoc_client_pool_push(dbpool, dbclient); return ret; }
static int sqlite_log(struct ast_cdr *cdr) { int res = 0; char *zErr = 0; struct tm tm; time_t t; char startstr[80]; char answerstr[80]; char endstr[80]; char *dispositionstr = NULL; int count; ast_mutex_lock(&sqlite_lock); t = cdr->start.tv_sec; ast_localtime(&t, &tm, NULL); strftime(startstr, sizeof(startstr), DATE_FORMAT, &tm); t = cdr->answer.tv_sec; ast_localtime(&t, &tm, NULL); strftime(answerstr, sizeof(answerstr), DATE_FORMAT, &tm); t = cdr->end.tv_sec; ast_localtime(&t, &tm, NULL); strftime(endstr, sizeof(endstr), DATE_FORMAT, &tm); dispositionstr = ast_cdr_disp2str(cdr->disposition); for(count=0; count<5; count++) { res = sqlite_exec_printf(db, "INSERT INTO cdr (" "clid," "src," "dst," "dcontext," "channel," "dstchannel," "lastapp," "lastdata," "start," "answer," "end," "duration," "billsec," "disposition," "amaflags," "accountcode," "uniqueid," "userfield" ") VALUES (" "'%q', " // clid "'%q', " // src "'%q', " // dst "'%q', " // dcontext "'%q', " // channel "'%q', " // dstchannel "'%q', " // lastapp "'%q', " // lastdata "'%q', " // start "'%q', " // answer "'%q', " // end "%d, " // duration "%d, " // billsec "'%q', " // disposition "%d, " // amaflags "'%q', " // accountcode "'%q', " // uniqueiq "'%q' " // userfield ")", NULL, NULL, &zErr, cdr->clid, cdr->src, cdr->dst, cdr->dcontext, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, startstr, answerstr, endstr, cdr->duration, cdr->billsec, dispositionstr, cdr->amaflags, cdr->accountcode, cdr->uniqueid, cdr->userfield ); if (res != SQLITE_BUSY && res != SQLITE_LOCKED) break; usleep(200); } if (zErr) { ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr); free(zErr); } ast_mutex_unlock(&sqlite_lock); return res; }
static int pgsql_log(struct ast_cdr *cdr) { struct tm tm; time_t t = cdr->start.tv_sec; char sqlcmd[2048] = "", timestr[128]; char *pgerror; PGresult *result; ast_mutex_lock(&pgsql_lock); ast_localtime(&t, &tm, NULL); strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) { conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); if (PQstatus(conn) != CONNECTION_BAD) { connected = 1; } else { pgerror = PQerrorMessage(conn); ast_log(LOG_ERROR, "cdr_pgsql: Unable to connect to database server %s. Calls will not be logged!\n", pghostname); ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); PQfinish(conn); conn = NULL; } } if (connected) { char *clid=NULL, *dcontext=NULL, *channel=NULL, *dstchannel=NULL, *lastapp=NULL, *lastdata=NULL; char *src=NULL, *dst=NULL, *uniqueid=NULL, *userfield=NULL; int pgerr; /* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */ if ((clid = alloca(strlen(cdr->clid) * 2 + 1)) != NULL) PQescapeStringConn(conn, clid, cdr->clid, strlen(cdr->clid), &pgerr); if ((dcontext = alloca(strlen(cdr->dcontext) * 2 + 1)) != NULL) PQescapeStringConn(conn, dcontext, cdr->dcontext, strlen(cdr->dcontext), &pgerr); if ((channel = alloca(strlen(cdr->channel) * 2 + 1)) != NULL) PQescapeStringConn(conn, channel, cdr->channel, strlen(cdr->channel), &pgerr); if ((dstchannel = alloca(strlen(cdr->dstchannel) * 2 + 1)) != NULL) PQescapeStringConn(conn, dstchannel, cdr->dstchannel, strlen(cdr->dstchannel), &pgerr); if ((lastapp = alloca(strlen(cdr->lastapp) * 2 + 1)) != NULL) PQescapeStringConn(conn, lastapp, cdr->lastapp, strlen(cdr->lastapp), &pgerr); if ((lastdata = alloca(strlen(cdr->lastdata) * 2 + 1)) != NULL) PQescapeStringConn(conn, lastdata, cdr->lastdata, strlen(cdr->lastdata), &pgerr); if ((uniqueid = alloca(strlen(cdr->uniqueid) * 2 + 1)) != NULL) PQescapeStringConn(conn, uniqueid, cdr->uniqueid, strlen(cdr->uniqueid), &pgerr); if ((userfield = alloca(strlen(cdr->userfield) * 2 + 1)) != NULL) PQescapeStringConn(conn, userfield, cdr->userfield, strlen(cdr->userfield), &pgerr); if ((src = alloca(strlen(cdr->src) * 2 + 1)) != NULL) PQescapeStringConn(conn, src, cdr->src, strlen(cdr->src), &pgerr); if ((dst = alloca(strlen(cdr->dst) * 2 + 1)) != NULL) PQescapeStringConn(conn, dst, cdr->dst, strlen(cdr->dst), &pgerr); /* Check for all alloca failures above at once */ if ((!clid) || (!dcontext) || (!channel) || (!dstchannel) || (!lastapp) || (!lastdata) || (!uniqueid) || (!userfield) || (!src) || (!dst)) { ast_log(LOG_ERROR, "cdr_pgsql: Out of memory error (insert fails)\n"); ast_mutex_unlock(&pgsql_lock); return -1; } if (option_debug > 1) ast_log(LOG_DEBUG, "cdr_pgsql: inserting a CDR record.\n"); snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (calldate,clid,src,dst,dcontext,channel,dstchannel," "lastapp,lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) VALUES" " ('%s','%s','%s','%s','%s', '%s','%s','%s','%s',%ld,%ld,'%s',%ld,'%s','%s','%s')", table, timestr, clid, src, dst, dcontext, channel, dstchannel, lastapp, lastdata, cdr->duration,cdr->billsec,ast_cdr_disp2str(cdr->disposition),cdr->amaflags, cdr->accountcode, uniqueid, userfield); if (option_debug > 2) ast_log(LOG_DEBUG, "cdr_pgsql: SQL command executed: %s\n",sqlcmd); /* Test to be sure we're still connected... */ /* If we're connected, and connection is working, good. */ /* Otherwise, attempt reconnect. If it fails... sorry... */ if (PQstatus(conn) == CONNECTION_OK) { connected = 1; } else { ast_log(LOG_ERROR, "cdr_pgsql: Connection was lost... attempting to reconnect.\n"); PQreset(conn); if (PQstatus(conn) == CONNECTION_OK) { ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); connected = 1; } else { pgerror = PQerrorMessage(conn); ast_log(LOG_ERROR, "cdr_pgsql: Unable to reconnect to database server %s. Calls will not be logged!\n", pghostname); ast_log(LOG_ERROR, "cdr_pgsql: Reason: %s\n", pgerror); PQfinish(conn); conn = NULL; connected = 0; ast_mutex_unlock(&pgsql_lock); return -1; } } result = PQexec(conn, sqlcmd); if (PQresultStatus(result) != PGRES_COMMAND_OK) { pgerror = PQresultErrorMessage(result); ast_log(LOG_ERROR,"cdr_pgsql: Failed to insert call detail record into database!\n"); ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); ast_log(LOG_ERROR,"cdr_pgsql: Connection may have been lost... attempting to reconnect.\n"); PQreset(conn); if (PQstatus(conn) == CONNECTION_OK) { ast_log(LOG_ERROR, "cdr_pgsql: Connection reestablished.\n"); connected = 1; PQclear(result); result = PQexec(conn, sqlcmd); if (PQresultStatus(result) != PGRES_COMMAND_OK) { pgerror = PQresultErrorMessage(result); ast_log(LOG_ERROR,"cdr_pgsql: HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); ast_log(LOG_ERROR,"cdr_pgsql: Reason: %s\n", pgerror); } } ast_mutex_unlock(&pgsql_lock); PQclear(result); return -1; } PQclear(result); } ast_mutex_unlock(&pgsql_lock); return 0; }