Skip to content
Snippets Groups Projects
cdr.c 32.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • {
    	if (argc > 2)
    		return RESULT_SHOWUSAGE;
    
    	submit_unscheduled_batch();
    	ast_cli(fd, "Submitted CDRs to backend engines for processing.  This may take a while.\n");
    
    	return 0;
    }
    
    static struct ast_cli_entry cli_submit = {
    	.cmda = { "cdr", "submit", NULL },
    	.handler = handle_cli_submit,
    	.summary = "Posts all pending batched CDR data",
    	.usage =
    	"Usage: cdr submit\n"
    	"       Posts all pending batched CDR data to the configured CDR backend engine modules.\n"
    };
    
    static struct ast_cli_entry cli_status = {
    	.cmda = { "cdr", "status", NULL },
    	.handler = handle_cli_status,
    	.summary = "Display the CDR status",
    	.usage =
    	"Usage: cdr status\n"
    	"	Displays the Call Detail Record engine system status.\n"
    };
    
    static int do_reload(void)
    {
    	struct ast_config *config;
    	const char *enabled_value;
    	const char *batched_value;
    	const char *scheduleronly_value;
    	const char *batchsafeshutdown_value;
    	const char *size_value;
    	const char *time_value;
    
    	int cfg_size;
    	int cfg_time;
    	int was_enabled;
    	int was_batchmode;
    	int res=0;
    
    	ast_mutex_lock(&cdr_batch_lock);
    
    	batchsize = BATCH_SIZE_DEFAULT;
    	batchtime = BATCH_TIME_DEFAULT;
    	batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT;
    	batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT;
    	was_enabled = enabled;
    	was_batchmode = batchmode;
    	enabled = 1;
    	batchmode = 0;
    
    	/* don't run the next scheduled CDR posting while reloading */
    	if (cdr_sched > -1)
    		ast_sched_del(sched, cdr_sched);
    
    	if ((config = ast_config_load("cdr.conf"))) {
    		if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
    			enabled = ast_true(enabled_value);
    		}
    		if ((batched_value = ast_variable_retrieve(config, "general", "batch"))) {
    			batchmode = ast_true(batched_value);
    		}
    		if ((scheduleronly_value = ast_variable_retrieve(config, "general", "scheduleronly"))) {
    			batchscheduleronly = ast_true(scheduleronly_value);
    		}
    		if ((batchsafeshutdown_value = ast_variable_retrieve(config, "general", "safeshutdown"))) {
    			batchsafeshutdown = ast_true(batchsafeshutdown_value);
    		}
    		if ((size_value = ast_variable_retrieve(config, "general", "size"))) {
    			if (sscanf(size_value, "%d", &cfg_size) < 1)
    				ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", size_value);
    			else if (size_value < 0)
    				ast_log(LOG_WARNING, "Invalid maximum batch size '%d' specified, using default\n", cfg_size);
    			else
    				batchsize = cfg_size;
    		}
    		if ((time_value = ast_variable_retrieve(config, "general", "time"))) {
    			if (sscanf(time_value, "%d", &cfg_time) < 1)
    				ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", time_value);
    			else if (time_value < 0)
    				ast_log(LOG_WARNING, "Invalid maximum batch time '%d' specified, using default\n", cfg_time);
    			else
    				batchtime = cfg_time;
    		}
    
    		if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
    
    			ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
    
    	}
    
    	if (enabled && !batchmode) {
    		ast_log(LOG_NOTICE, "CDR simple logging enabled.\n");
    	} else if (enabled && batchmode) {
    		cdr_sched = ast_sched_add(sched, batchtime * 1000, submit_scheduled_batch, NULL);
    		ast_log(LOG_NOTICE, "CDR batch mode logging enabled, first of either size %d or time %d seconds.\n", batchsize, batchtime);
    	} else {
    		ast_log(LOG_NOTICE, "CDR logging disabled, data will be lost.\n");
    	}
    
    	/* if this reload enabled the CDR batch mode, create the background thread
    	   if it does not exist */
    	if (enabled && batchmode && (!was_enabled || !was_batchmode) && (cdr_thread == AST_PTHREADT_NULL)) {
    
    		if (ast_pthread_create(&cdr_thread, NULL, do_cdr, NULL) < 0) {
    
    			ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
    			ast_sched_del(sched, cdr_sched);
    		} else {
    			ast_cli_register(&cli_submit);
    			ast_register_atexit(ast_cdr_engine_term);
    			res = 0;
    		}
    	/* if this reload disabled the CDR and/or batch mode and there is a background thread,
    	   kill it */
    	} else if (((!enabled && was_enabled) || (!batchmode && was_batchmode)) && (cdr_thread != AST_PTHREADT_NULL)) {
    		/* wake up the thread so it will exit */
    		pthread_cancel(cdr_thread);
    		pthread_kill(cdr_thread, SIGURG);
    		pthread_join(cdr_thread, NULL);
    		cdr_thread = AST_PTHREADT_NULL;
    
    		ast_cli_unregister(&cli_submit);
    		ast_unregister_atexit(ast_cdr_engine_term);
    		res = 0;
    		/* if leaving batch mode, then post the CDRs in the batch,
    		   and don't reschedule, since we are stopping CDR logging */
    		if (!batchmode && was_batchmode) {
    			ast_cdr_engine_term();
    		}
    	} else {
    		res = 0;
    	}
    
    	ast_mutex_unlock(&cdr_batch_lock);
    	ast_config_destroy(config);
    
    	return res;
    }
    
    int ast_cdr_engine_init(void)
    {
    	int res;
    
    	sched = sched_context_create();
    	if (!sched) {
    		ast_log(LOG_ERROR, "Unable to create schedule context.\n");
    		return -1;
    	}
    
    	ast_cli_register(&cli_status);
    
    	res = do_reload();
    	if (res) {
    		ast_mutex_lock(&cdr_batch_lock);
    		res = init_batch();
    		ast_mutex_unlock(&cdr_batch_lock);
    	}
    
    	return res;
    }
    
    
    /* \note This actually gets called a couple of times at shutdown.  Once, before we start
    
       hanging up channels, and then again, after the channel hangup timeout expires */
    void ast_cdr_engine_term(void)
    {
    	ast_cdr_submit_batch(batchsafeshutdown);
    }
    
    
    int ast_cdr_engine_reload(void)
    
    	return do_reload();