Example #1
0
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_channel_amaflags2string(cdr->amaflags), bufsize);
	/* Unique ID */
	if (loguniqueid)
		append_string(buf, cdr->uniqueid, bufsize);
	/* append the user field */
	if(loguserfield)
		append_string(buf, cdr->userfield,bufsize);
	/* 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;
}
Example #2
0
static void custom_log(struct ast_event *event)
{
	CURL *curl;
	CURLcode res;
	struct ast_tm timeresult;
	struct curl_slist *headers = NULL;
	char start_time[80] = "";

	struct ast_cel_event_record record = {
		.version = AST_CEL_EVENT_RECORD_VERSION,
	};

	if (ast_cel_fill_record(event, &record)) {
		return;
	}

	ast_localtime(&record.event_time, &timeresult, NULL);
	ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);

	curl = curl_easy_init();
	if (curl) {
		headers = curl_slist_append(headers, "Content-Type: application/json");

		curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.0.5:9200/asterisk/cel/");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

		char *post_fields = malloc(sizeof(char) * 6048);
		sprintf(post_fields, "{\"EventName\": \"%s\", \"AccountCode\": \"%s\",	\
			\"CallerIDnum\": \"%s\", \"CallerIDname\": \"%s\", 	\
			\"CallerIDani\": \"%s\", \"CallerIDrdnis\": \"%s\",	\
			\"CAllerIDdnid\": \"%s\", \"Exten\": \"%s\",		\
			\"Context\": \"%s\", \"Channel\": \"%s\", 	 		\
			\"Application\": \"%s\", \"AppData\": \"%s\",		\
			\"EventTime\": \"%s\", \"AMAFlags\": \"%s\", 	 	\
			\"UniqueID\": \"%s\", \"LinkedID\": \"%s\", 	 	\
			\"Userfield\": \"%s\", \"Peer\": \"%s\", 	 		\
			\"Peeraccount\": \"%s\", \"Extra\": \"%s\" }",
			record.event_name, record.account_code, record.caller_id_num,
			record.caller_id_name, record.caller_id_ani, record.caller_id_rdnis,
			record.caller_id_dnid, record.extension, record.context,
			record.channel_name, record.application_name, record.application_data,
			start_time, ast_channel_amaflags2string(record.amaflag),
			record.unique_id, record.linked_id, record.user_field, record.peer,
			record.peer_account, record.extra);

		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields);
		curl_easy_perform(curl);
		curl_slist_free_all(headers);
		curl_easy_cleanup(curl);
		free(post_fields);
	}
Example #3
0
static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *record)
{
	int recordtype = PW_STATUS_STOP;
	struct ast_tm tm;
	char timestr[128];
	char *amaflags;
	int left_len;
	char *left_value;
	int send_len;

	if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) {
		return -1;
	}
	/* Account code */
	if (!ADD_VENDOR_CODE(PW_AST_ACCT_CODE, record->account_code)) {
		return -1;
	}
	/* Source */
	if (!ADD_VENDOR_CODE(PW_AST_CIDNUM, record->caller_id_num)) {
		return -1;
	}
	/* Destination */
	if (!ADD_VENDOR_CODE(PW_AST_EXTEN, record->extension)) {
		return -1;
	}
	/* Destination context */
	if (!ADD_VENDOR_CODE(PW_AST_CONTEXT, record->context)) {
		return -1;
	}
	/* Caller ID */
	if (!ADD_VENDOR_CODE(PW_AST_CIDNAME, record->caller_id_name)) {
		return -1;
	}
	/* Caller ID ani */
	if (!ADD_VENDOR_CODE(PW_AST_CIDANI, record->caller_id_ani)) {
		return -1;
	}
	/* Caller ID rdnis */
	if (!ADD_VENDOR_CODE(PW_AST_CIDRDNIS, record->caller_id_rdnis)) {
		return -1;
	}
	/* Caller ID dnid */
	if (!ADD_VENDOR_CODE(PW_AST_CIDDNID, record->caller_id_dnid)) {
		return -1;
	}
	/* Channel */
	if (!ADD_VENDOR_CODE(PW_AST_CHANNAME, record->channel_name)) {
		return -1;
	}
	/* Last Application */
	if (!ADD_VENDOR_CODE(PW_AST_APPNAME, record->application_name)) {
		return -1;
	}
	/* Last Data */
	if (!ADD_VENDOR_CODE(PW_AST_APPDATA, record->application_data)) {
		return -1;
	}
	/* Extra */
	
	left_len = strlen(record->extra);
        left_value = (char *)record->extra;
        while(left_len > 0){
               if(left_len > 240){
                    send_len = 240;
                }else{
                    send_len = left_len; 
                }
                if(!rc_avpair_add(rh, send, PW_AST_EXTRA, left_value, send_len, VENDOR_CODE )) {
			return -1;
                }
                left_len-=send_len;
                left_value+=send_len;
        }
	
	/* Event Time */
	ast_localtime(&record->event_time, &tm,
		ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL);
	ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
	if (!rc_avpair_add(rh, send, PW_AST_EVENT_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
		return -1;
	}
	/* AMA Flags */
	amaflags = ast_strdupa(ast_channel_amaflags2string(record->amaflag));
	if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, amaflags, strlen(amaflags), VENDOR_CODE)) {
		return -1;
	}
	if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
		/* Unique ID */
		if (!ADD_VENDOR_CODE(PW_AST_UNIQUE_ID, record->unique_id)) {
			return -1;
		}
	}
	/* LinkedID */
	if (!ADD_VENDOR_CODE(PW_AST_LINKED_ID, record->linked_id)) {
		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, send, PW_USER_NAME, (void *)record->channel_name,
			strlen(record->channel_name), 0)) {
		return -1;
	}
	return 0;
}
Example #4
0
static void manager_log(struct ast_event *event)
{
	struct ast_tm timeresult;
	char start_time[80] = "";
	char user_defined_header[160];
	const char *event_name;
	struct ast_cel_event_record record = {
		.version = AST_CEL_EVENT_RECORD_VERSION,
	};

	if (!enablecel) {
		return;
	}

	if (ast_cel_fill_record(event, &record)) {
		return;
	}

	ast_localtime(&record.event_time, &timeresult, NULL);
	ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);

	event_name = record.event_name;
	user_defined_header[0] = '\0';
	if (record.event_type == AST_CEL_USER_DEFINED) {
		if (cel_show_user_def) {
			snprintf(user_defined_header, sizeof(user_defined_header),
				"UserDefType: %s\r\n", record.user_defined_name);
		} else {
			event_name = record.user_defined_name;
		}
	}

	manager_event(EVENT_FLAG_CALL, "CEL",
		"EventName: %s\r\n"
		"AccountCode: %s\r\n"
		"CallerIDnum: %s\r\n"
		"CallerIDname: %s\r\n"
		"CallerIDani: %s\r\n"
		"CallerIDrdnis: %s\r\n"
		"CallerIDdnid: %s\r\n"
		"Exten: %s\r\n"
		"Context: %s\r\n"
		"Channel: %s\r\n"
		"Application: %s\r\n"
		"AppData: %s\r\n"
		"EventTime: %s\r\n"
		"AMAFlags: %s\r\n"
		"UniqueID: %s\r\n"
		"LinkedID: %s\r\n"
		"Userfield: %s\r\n"
		"Peer: %s\r\n"
		"PeerAccount: %s\r\n"
		"%s"
		"Extra: %s\r\n",
		event_name,
		record.account_code,
		record.caller_id_num,
		record.caller_id_name,
		record.caller_id_ani,
		record.caller_id_rdnis,
		record.caller_id_dnid,
		record.extension,
		record.context,
		record.channel_name,
		record.application_name,
		record.application_data,
		start_time,
		ast_channel_amaflags2string(record.amaflag),
		record.unique_id,
		record.linked_id,
		record.user_field,
		record.peer,
		record.peer_account,
		user_defined_header,
		record.extra);
}
Example #5
0
int ast_channel_data_add_structure(struct ast_data *tree,
	struct ast_channel *chan, int add_bridged)
{
	struct ast_data *data_bridged;
	struct ast_data *data_cdr;
	struct ast_data *data_flags;
	struct ast_data *data_zones;
	struct ast_data *enum_node;
	struct ast_data *data_softhangup;
#if 0	/* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */
	struct ast_data *data_callerid;
	char value_str[100];
#endif

	if (!tree) {
		return -1;
	}

	ast_data_add_structure(ast_channel, tree, chan);

	if (add_bridged) {
		RAII_VAR(struct ast_channel *, bc, ast_channel_bridge_peer(chan), ast_channel_cleanup);
		if (bc) {
			data_bridged = ast_data_add_node(tree, "bridged");
			if (!data_bridged) {
				return -1;
			}
			ast_channel_data_add_structure(data_bridged, bc, 0);
		}
	}

	ast_data_add_codec(tree, "oldwriteformat", ast_channel_oldwriteformat(chan));
	ast_data_add_codec(tree, "readformat", ast_channel_readformat(chan));
	ast_data_add_codec(tree, "writeformat", ast_channel_writeformat(chan));
	ast_data_add_codec(tree, "rawreadformat", ast_channel_rawreadformat(chan));
	ast_data_add_codec(tree, "rawwriteformat", ast_channel_rawwriteformat(chan));
	ast_data_add_codecs(tree, "nativeformats", ast_channel_nativeformats(chan));

	/* state */
	enum_node = ast_data_add_node(tree, "state");
	if (!enum_node) {
		return -1;
	}
	ast_data_add_str(enum_node, "text", ast_state2str(ast_channel_state(chan)));
	ast_data_add_int(enum_node, "value", ast_channel_state(chan));

	/* hangupcause */
	enum_node = ast_data_add_node(tree, "hangupcause");
	if (!enum_node) {
		return -1;
	}
	ast_data_add_str(enum_node, "text", ast_cause2str(ast_channel_hangupcause(chan)));
	ast_data_add_int(enum_node, "value", ast_channel_hangupcause(chan));

	/* amaflags */
	enum_node = ast_data_add_node(tree, "amaflags");
	if (!enum_node) {
		return -1;
	}
	ast_data_add_str(enum_node, "text", ast_channel_amaflags2string(ast_channel_amaflags(chan)));
	ast_data_add_int(enum_node, "value", ast_channel_amaflags(chan));

	/* transfercapability */
	enum_node = ast_data_add_node(tree, "transfercapability");
	if (!enum_node) {
		return -1;
	}
	ast_data_add_str(enum_node, "text", ast_transfercapability2str(ast_channel_transfercapability(chan)));
	ast_data_add_int(enum_node, "value", ast_channel_transfercapability(chan));

	/* _softphangup */
	data_softhangup = ast_data_add_node(tree, "softhangup");
	if (!data_softhangup) {
		return -1;
	}
	ast_data_add_bool(data_softhangup, "dev", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_DEV);
	ast_data_add_bool(data_softhangup, "asyncgoto", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO);
	ast_data_add_bool(data_softhangup, "shutdown", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_SHUTDOWN);
	ast_data_add_bool(data_softhangup, "timeout", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_TIMEOUT);
	ast_data_add_bool(data_softhangup, "appunload", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_APPUNLOAD);
	ast_data_add_bool(data_softhangup, "explicit", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_EXPLICIT);
	ast_data_add_bool(data_softhangup, "unbridge", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_UNBRIDGE);

	/* channel flags */
	data_flags = ast_data_add_node(tree, "flags");
	if (!data_flags) {
		return -1;
	}
	channel_data_add_flags(data_flags, chan);

	ast_data_add_uint(tree, "timetohangup", ast_channel_whentohangup(chan)->tv_sec);

#if 0	/* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */
	/* callerid */
	data_callerid = ast_data_add_node(tree, "callerid");
	if (!data_callerid) {
		return -1;
	}
	ast_data_add_structure(ast_callerid, data_callerid, &(chan->cid));
	/* insert the callerid ton */
	enum_node = ast_data_add_node(data_callerid, "cid_ton");
	if (!enum_node) {
		return -1;
	}
	ast_data_add_int(enum_node, "value", chan->cid.cid_ton);
	snprintf(value_str, sizeof(value_str), "TON: %s/Plan: %s",
		party_number_ton2str(chan->cid.cid_ton),
		party_number_plan2str(chan->cid.cid_ton));
	ast_data_add_str(enum_node, "text", value_str);
#endif

	/* tone zone */
	if (ast_channel_zone(chan)) {
		data_zones = ast_data_add_node(tree, "zone");
		if (!data_zones) {
			return -1;
		}
		ast_tone_zone_data_add_structure(data_zones, ast_channel_zone(chan));
	}

	/* insert cdr */
	data_cdr = ast_data_add_node(tree, "cdr");
	if (!data_cdr) {
		return -1;
	}

	return 0;
}
Example #6
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;
}
Example #7
0
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_strdupa(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_strdupa(ast_channel_amaflags2string(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;
}
Example #8
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;
}