Adding reload support to res_fax.so

(closes issue ASTERISK-16712)
reported by Frank DiGennaro

Review: https://reviewboard.asterisk.org/r/1713



git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@354545 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Michelson
2012-02-09 16:56:34 +00:00
parent ead2b47907
commit aeadbab220
2 changed files with 125 additions and 57 deletions

View File

@@ -30,6 +30,10 @@ RTP changes
mode has successfully exited. These changes are based on how pjmedia handles mode has successfully exited. These changes are based on how pjmedia handles
media sources and source changes. media sources and source changes.
FAX changes
------------
* res_fax now has module reload support.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
--- Functionality changes since Asterisk 1.8.7.1 ----------------------------- --- Functionality changes since Asterisk 1.8.7.1 -----------------------------
------------------------------------------------------------------------------ ------------------------------------------------------------------------------

View File

@@ -249,13 +249,28 @@ static AST_RWLIST_HEAD_STATIC(faxmodules, fax_module);
#define RES_FAX_STATUSEVENTS 0 #define RES_FAX_STATUSEVENTS 0
#define RES_FAX_MODEM (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29) #define RES_FAX_MODEM (AST_FAX_MODEM_V17 | AST_FAX_MODEM_V27 | AST_FAX_MODEM_V29)
static struct { struct fax_options {
enum ast_fax_modems modems; enum ast_fax_modems modems;
uint32_t statusevents:1; uint32_t statusevents:1;
uint32_t ecm:1; uint32_t ecm:1;
unsigned int minrate; unsigned int minrate;
unsigned int maxrate; unsigned int maxrate;
} general_options; };
static struct fax_options general_options;
static const struct fax_options default_options = {
.minrate = RES_FAX_MINRATE,
.maxrate = RES_FAX_MAXRATE,
.statusevents = RES_FAX_STATUSEVENTS,
.modems = RES_FAX_MODEM,
.ecm = AST_FAX_OPTFLAG_TRUE,
};
AST_RWLOCK_DEFINE_STATIC(options_lock);
static void get_general_options(struct fax_options* options);
static void set_general_options(const struct fax_options* options);
static const char *config = "res_fax.conf"; static const char *config = "res_fax.conf";
@@ -368,6 +383,7 @@ static void destroy_session_details(void *details)
static struct ast_fax_session_details *session_details_new(void) static struct ast_fax_session_details *session_details_new(void)
{ {
struct ast_fax_session_details *d; struct ast_fax_session_details *d;
struct fax_options options;
if (!(d = ao2_alloc(sizeof(*d), destroy_session_details))) { if (!(d = ao2_alloc(sizeof(*d), destroy_session_details))) {
return NULL; return NULL;
@@ -378,6 +394,8 @@ static struct ast_fax_session_details *session_details_new(void)
return NULL; return NULL;
} }
get_general_options(&options);
AST_LIST_HEAD_INIT_NOLOCK(&d->documents); AST_LIST_HEAD_INIT_NOLOCK(&d->documents);
/* These options need to be set to the configured default and may be overridden by /* These options need to be set to the configured default and may be overridden by
@@ -385,11 +403,11 @@ static struct ast_fax_session_details *session_details_new(void)
d->option.request_t38 = AST_FAX_OPTFLAG_FALSE; d->option.request_t38 = AST_FAX_OPTFLAG_FALSE;
d->option.send_cng = AST_FAX_OPTFLAG_FALSE; d->option.send_cng = AST_FAX_OPTFLAG_FALSE;
d->option.send_ced = AST_FAX_OPTFLAG_FALSE; d->option.send_ced = AST_FAX_OPTFLAG_FALSE;
d->option.ecm = general_options.ecm; d->option.ecm = options.ecm;
d->option.statusevents = general_options.statusevents; d->option.statusevents = options.statusevents;
d->modems = general_options.modems; d->modems = options.modems;
d->minrate = general_options.minrate; d->minrate = options.minrate;
d->maxrate = general_options.maxrate; d->maxrate = options.maxrate;
return d; return d;
} }
@@ -425,12 +443,18 @@ static struct ast_fax_session_details *find_or_create_details(struct ast_channel
unsigned int ast_fax_maxrate(void) unsigned int ast_fax_maxrate(void)
{ {
return general_options.maxrate; struct fax_options options;
get_general_options(&options);
return options.maxrate;
} }
unsigned int ast_fax_minrate(void) unsigned int ast_fax_minrate(void)
{ {
return general_options.minrate; struct fax_options options;
get_general_options(&options);
return options.minrate;
} }
static int update_modem_bits(enum ast_fax_modems *bits, const char *value) static int update_modem_bits(enum ast_fax_modems *bits, const char *value)
@@ -2428,6 +2452,7 @@ static char *cli_fax_show_settings(struct ast_cli_entry *e, int cmd, struct ast_
{ {
struct fax_module *fax; struct fax_module *fax;
char modems[128] = ""; char modems[128] = "";
struct fax_options options;
switch (cmd) { switch (cmd) {
case CLI_INIT: case CLI_INIT:
@@ -2440,12 +2465,14 @@ static char *cli_fax_show_settings(struct ast_cli_entry *e, int cmd, struct ast_
return NULL; return NULL;
} }
get_general_options(&options);
ast_cli(a->fd, "FAX For Asterisk Settings:\n"); ast_cli(a->fd, "FAX For Asterisk Settings:\n");
ast_cli(a->fd, "\tECM: %s\n", general_options.ecm ? "Enabled" : "Disabled"); ast_cli(a->fd, "\tECM: %s\n", options.ecm ? "Enabled" : "Disabled");
ast_cli(a->fd, "\tStatus Events: %s\n", general_options.statusevents ? "On" : "Off"); ast_cli(a->fd, "\tStatus Events: %s\n", options.statusevents ? "On" : "Off");
ast_cli(a->fd, "\tMinimum Bit Rate: %d\n", general_options.minrate); ast_cli(a->fd, "\tMinimum Bit Rate: %d\n", options.minrate);
ast_cli(a->fd, "\tMaximum Bit Rate: %d\n", general_options.maxrate); ast_cli(a->fd, "\tMaximum Bit Rate: %d\n", options.maxrate);
ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems)); ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems); ast_cli(a->fd, "\tModem Modulations Allowed: %s\n", modems);
ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n"); ast_cli(a->fd, "\n\nFAX Technology Modules:\n\n");
AST_RWLIST_RDLOCK(&faxmodules); AST_RWLIST_RDLOCK(&faxmodules);
@@ -2588,35 +2615,60 @@ static struct ast_cli_entry fax_cli[] = {
AST_CLI_DEFINE(cli_fax_show_stats, "Summarize FAX session history"), AST_CLI_DEFINE(cli_fax_show_stats, "Summarize FAX session history"),
}; };
static void set_general_options(const struct fax_options *options)
{
ast_rwlock_wrlock(&options_lock);
general_options = *options;
ast_rwlock_unlock(&options_lock);
}
static void get_general_options(struct fax_options *options)
{
ast_rwlock_rdlock(&options_lock);
*options = general_options;
ast_rwlock_unlock(&options_lock);
}
/*! \brief configure res_fax */ /*! \brief configure res_fax */
static int set_config(const char *config_file) static int set_config(int reload)
{ {
struct ast_config *cfg; struct ast_config *cfg;
struct ast_variable *v; struct ast_variable *v;
struct ast_flags config_flags = { 0 }; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
char modems[128] = ""; char modems[128] = "";
struct fax_options options;
int res = 0;
/* set defaults */ options = default_options;
general_options.minrate = RES_FAX_MINRATE;
general_options.maxrate = RES_FAX_MAXRATE; /* When we're not reloading, we have to be certain to set the general options
general_options.statusevents = RES_FAX_STATUSEVENTS; * to the defaults in case config loading goes wrong at some point. On a reload,
general_options.modems = RES_FAX_MODEM; * the general options need to stay the same as what they were prior to the
general_options.ecm = AST_FAX_OPTFLAG_TRUE; * reload rather than being reset to the defaults.
*/
if (!reload) {
set_general_options(&options);
}
/* read configuration */ /* read configuration */
if (!(cfg = ast_config_load2(config_file, "res_fax", config_flags))) { if (!(cfg = ast_config_load2(config, "res_fax", config_flags))) {
ast_log(LOG_NOTICE, "Configuration file '%s' not found, using default options.\n", config_file); ast_log(LOG_NOTICE, "Configuration file '%s' not found, %s options.\n",
config, reload ? "not changing" : "using default");
return 0; return 0;
} }
if (cfg == CONFIG_STATUS_FILEINVALID) { if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_NOTICE, "Configuration file '%s' is invalid, using default options.\n", config_file); ast_log(LOG_NOTICE, "Configuration file '%s' is invalid, %s options.\n",
config, reload ? "not changing" : "using default");
return 0; return 0;
} }
if (cfg == CONFIG_STATUS_FILEUNCHANGED) { if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); return 0;
cfg = ast_config_load2(config_file, "res_fax", config_flags); }
if (reload) {
options = default_options;
} }
/* create configuration */ /* create configuration */
@@ -2626,49 +2678,54 @@ static int set_config(const char *config_file)
if (!strcasecmp(v->name, "minrate")) { if (!strcasecmp(v->name, "minrate")) {
ast_debug(3, "reading minrate '%s' from configuration file\n", v->value); ast_debug(3, "reading minrate '%s' from configuration file\n", v->value);
if ((rate = fax_rate_str_to_int(v->value)) == 0) { if ((rate = fax_rate_str_to_int(v->value)) == 0) {
ast_config_destroy(cfg); res = -1;
return -1; goto end;
} }
general_options.minrate = rate; options.minrate = rate;
} else if (!strcasecmp(v->name, "maxrate")) { } else if (!strcasecmp(v->name, "maxrate")) {
ast_debug(3, "reading maxrate '%s' from configuration file\n", v->value); ast_debug(3, "reading maxrate '%s' from configuration file\n", v->value);
if ((rate = fax_rate_str_to_int(v->value)) == 0) { if ((rate = fax_rate_str_to_int(v->value)) == 0) {
ast_config_destroy(cfg); res = -1;
return -1; goto end;
} }
general_options.maxrate = rate; options.maxrate = rate;
} else if (!strcasecmp(v->name, "statusevents")) { } else if (!strcasecmp(v->name, "statusevents")) {
ast_debug(3, "reading statusevents '%s' from configuration file\n", v->value); ast_debug(3, "reading statusevents '%s' from configuration file\n", v->value);
general_options.statusevents = ast_true(v->value); options.statusevents = ast_true(v->value);
} else if (!strcasecmp(v->name, "ecm")) { } else if (!strcasecmp(v->name, "ecm")) {
ast_debug(3, "reading ecm '%s' from configuration file\n", v->value); ast_debug(3, "reading ecm '%s' from configuration file\n", v->value);
general_options.ecm = ast_true(v->value); options.ecm = ast_true(v->value);
} else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) { } else if ((!strcasecmp(v->name, "modem")) || (!strcasecmp(v->name, "modems"))) {
general_options.modems = 0; options.modems = 0;
update_modem_bits(&general_options.modems, v->value); update_modem_bits(&options.modems, v->value);
} }
} }
if (options.maxrate < options.minrate) {
ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", options.maxrate, options.minrate);
res = -1;
goto end;
}
if (check_modem_rate(options.modems, options.minrate)) {
ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, options.minrate);
res = -1;
goto end;
}
if (check_modem_rate(options.modems, options.maxrate)) {
ast_fax_modem_to_str(options.modems, modems, sizeof(modems));
ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, options.maxrate);
res = -1;
goto end;
}
set_general_options(&options);
end:
ast_config_destroy(cfg); ast_config_destroy(cfg);
return res;
if (general_options.maxrate < general_options.minrate) {
ast_log(LOG_ERROR, "maxrate %d is less than minrate %d\n", general_options.maxrate, general_options.minrate);
return -1;
}
if (check_modem_rate(general_options.modems, general_options.minrate)) {
ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'minrate' setting %d\n", modems, general_options.minrate);
return -1;
}
if (check_modem_rate(general_options.modems, general_options.maxrate)) {
ast_fax_modem_to_str(general_options.modems, modems, sizeof(modems));
ast_log(LOG_ERROR, "'modems' setting '%s' is incompatible with 'maxrate' setting %d\n", modems, general_options.maxrate);
return -1;
}
return 0;
} }
/*! \brief FAXOPT read function returns the contents of a FAX option */ /*! \brief FAXOPT read function returns the contents of a FAX option */
@@ -2829,7 +2886,7 @@ static int load_module(void)
return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_DECLINE;
} }
if (set_config(config) < 0) { if (set_config(0) < 0) {
ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config); ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config);
ao2_ref(faxregistry.container, -1); ao2_ref(faxregistry.container, -1);
return AST_MODULE_LOAD_DECLINE; return AST_MODULE_LOAD_DECLINE;
@@ -2854,9 +2911,16 @@ static int load_module(void)
return res; return res;
} }
static int reload_module(void)
{
set_config(1);
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Generic FAX Applications", AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Generic FAX Applications",
.load = load_module, .load = load_module,
.unload = unload_module, .unload = unload_module,
.reload = reload_module,
.load_pri = AST_MODPRI_APP_DEPEND, .load_pri = AST_MODPRI_APP_DEPEND,
); );