dect
/
asterisk
Archived
13
0
Fork 0

Merged revisions 297157,297486,297495 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r297157 | mnicholson | 2010-12-01 13:47:33 -0600 (Wed, 01 Dec 2010) | 2 lines
  
  Changed some NOTICE and WARNING messages to DEBUG messages.
........
  r297486 | mnicholson | 2010-12-02 15:30:47 -0600 (Thu, 02 Dec 2010) | 6 lines
  
  Add support for reserving a fax session before answering the channel.
  
  Note: this change breaks ABI compatibility.
  
  FAX-217
........
  r297495 | mnicholson | 2010-12-03 09:21:52 -0600 (Fri, 03 Dec 2010) | 4 lines
  
  Print a DEBUG message instead of a WARNING message when the selected fax tech does not support reserving sessions.
  
  Answer the channel before quering it for t.38 support.  This is necessary for the query to work properly over local channels.
........


git-svn-id: http://svn.digium.com/svn/asterisk/trunk@297496 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
mnicholson 2010-12-03 15:32:22 +00:00
parent 184c5bf3a8
commit 74a4a31f86
2 changed files with 189 additions and 62 deletions

View File

@ -58,8 +58,10 @@ enum ast_fax_modems {
/*! \brief current state of a fax session */
enum ast_fax_state {
/*! reserved state */
AST_FAX_STATE_RESERVED = 0,
/*! uninitialized state */
AST_FAX_STATE_UNINITIALIZED = 0,
AST_FAX_STATE_UNINITIALIZED,
/*! initialized state */
AST_FAX_STATE_INITIALIZED,
/*! fax resources open state */
@ -168,7 +170,8 @@ struct ast_fax_session_details {
struct ast_fax_tech;
struct ast_fax_debug_info;
struct ast_fax_tech_token;
/*! \brief The data required to handle a fax session */
struct ast_fax_session {
/*! session id */
@ -183,6 +186,8 @@ struct ast_fax_session {
unsigned long frames_sent;
/*! the fax technology callbacks */
const struct ast_fax_tech *tech;
/*! the token used to reserve this session */
struct ast_fax_tech_token *token;
/*! private implementation pointer */
void *tech_pvt;
/*! fax state */
@ -197,9 +202,11 @@ struct ast_fax_session {
struct ast_fax_debug_info *debug_info;
/*! used to take variable-sized frames in and output frames of an expected size to the fax stack */
struct ast_smoother *smoother;
};
struct ast_fax_tech_token;
/*! some flags to track the stat counters for this session */
unsigned int reserved:1;
unsigned int active:1;
};
/*! \brief used to register a FAX technology module with res_fax */
struct ast_fax_tech {
@ -242,7 +249,15 @@ struct ast_fax_tech {
/*! displays settings from the fax technology module */
char * (* const cli_show_settings)(int);
};
/*! \brief used by res_fax to reserve a FAX session */
struct ast_fax_tech_token {
/*! the fax technology callbacks */
const struct ast_fax_tech *tech;
/*! private implementation pointer */
void *tech_pvt;
};
/*! \brief register a fax technology */
int ast_fax_tech_register(struct ast_fax_tech *tech);

View File

@ -220,6 +220,8 @@ static int fax_logger_level = -1;
static struct {
/*! The number of active FAX sessions */
int active_sessions;
/*! The number of reserved FAX sessions */
int reserved_sessions;
/*! active sessions are astobj2 objects */
struct ao2_container *container;
/*! Total number of Tx FAX attempts */
@ -631,12 +633,26 @@ static unsigned int fax_rate_str_to_int(const char *ratestr)
}
}
static void fax_session_release(struct ast_fax_session *s)
{
if (s->token) {
s->tech->release_token(s->token);
s->token = NULL;
}
if (s->reserved) {
ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
s->reserved = 0;
}
}
/*! \brief destroy a FAX session structure */
static void destroy_session(void *session)
{
struct ast_fax_session *s = session;
if (s->tech) {
fax_session_release(s);
if (s->tech_pvt) {
s->tech->destroy_session(s);
}
@ -656,14 +672,16 @@ static void destroy_session(void *session)
ast_smoother_free(s->smoother);
}
ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
if (s->active) {
ast_atomic_fetchadd_int(&faxregistry.active_sessions, -1);
s->active = 0;
}
ast_free(s->channame);
ast_free(s->chan_uniqueid);
}
/*! \brief create a FAX session */
static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *details, struct ast_channel *chan)
static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_details *details)
{
struct ast_fax_session *s;
struct fax_module *faxmod;
@ -672,7 +690,68 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d
return NULL;
}
s->state = AST_FAX_STATE_RESERVED;
/* locate a FAX technology module that can handle said requirements
* Note: the requirements have not yet been finalized as T.38
* negotiation has not yet occured. */
AST_RWLIST_RDLOCK(&faxmodules);
AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
if ((faxmod->tech->caps & details->caps) != details->caps) {
continue;
}
ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description);
ast_module_ref(faxmod->tech->module);
s->tech = faxmod->tech;
break;
}
AST_RWLIST_UNLOCK(&faxmodules);
if (!faxmod) {
ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (0x%X)\n", details->caps);
ao2_ref(s, -1);
return NULL;
}
if (!s->tech->reserve_session) {
ast_debug(1, "Selected FAX technology module (%s) does not support reserving sessions.\n", s->tech->description);
return s;
}
if (!(s->token = s->tech->reserve_session(s))) {
ao2_ref(s, -1);
return NULL;
}
s->reserved = 1;
ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, 1);
return s;
}
/*! \brief create a FAX session */
static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *details, struct ast_channel *chan, struct ast_fax_session *reserved)
{
struct ast_fax_session *s = NULL;
struct fax_module *faxmod;
if (reserved) {
s = reserved;
ao2_ref(reserved, +1);
if (s->reserved) {
ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
s->reserved = 0;
}
}
if (!s && !(s = ao2_alloc(sizeof(*s), destroy_session))) {
return NULL;
}
s->active = 1;
ast_atomic_fetchadd_int(&faxregistry.active_sessions, 1);
s->state = AST_FAX_STATE_UNINITIALIZED;
if (details->option.debug && (details->caps & AST_FAX_TECH_AUDIO)) {
if (!(s->debug_info = ast_calloc(1, sizeof(*(s->debug_info))))) {
@ -701,39 +780,39 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d
s->chan = chan;
s->details = details;
ao2_ref(s->details, 1);
s->state = AST_FAX_STATE_UNINITIALIZED;
details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
/* locate a FAX technology module that can handle said requirements */
AST_RWLIST_RDLOCK(&faxmodules);
AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
if ((faxmod->tech->caps & details->caps) != details->caps) {
continue;
if (!s->tech) {
/* locate a FAX technology module that can handle said requirements */
AST_RWLIST_RDLOCK(&faxmodules);
AST_RWLIST_TRAVERSE(&faxmodules, faxmod, list) {
if ((faxmod->tech->caps & details->caps) != details->caps) {
continue;
}
ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
ast_module_ref(faxmod->tech->module);
s->tech = faxmod->tech;
break;
}
ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
ast_module_ref(faxmod->tech->module);
s->tech = faxmod->tech;
break;
}
AST_RWLIST_UNLOCK(&faxmodules);
AST_RWLIST_UNLOCK(&faxmodules);
if (!faxmod) {
ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (0x%X)\n", details->caps);
ao2_ref(s, -1);
return NULL;
if (!faxmod) {
ast_log(LOG_ERROR, "Could not locate a FAX technology module with capabilities (0x%X)\n", details->caps);
ao2_ref(s, -1);
return NULL;
}
}
if (!(s->tech_pvt = s->tech->new_session(s, NULL))) {
if (!(s->tech_pvt = s->tech->new_session(s, s->token))) {
ast_log(LOG_ERROR, "FAX session failed to initialize.\n");
ao2_ref(s, -1);
ast_module_unref(faxmod->tech->module);
return NULL;
}
/* link the session to the session container */
if (!(ao2_link(faxregistry.container, s))) {
ast_log(LOG_ERROR, "failed to add FAX session '%d' to container.\n", s->id);
ao2_ref(s, -1);
ast_module_unref(faxmod->tech->module);
return NULL;
}
ast_debug(4, "channel '%s' using FAX session '%d'\n", s->channame, s->id);
@ -930,7 +1009,7 @@ static int disable_t38(struct ast_channel *chan)
ast_debug(1, "Shutting down T.38 on %s\n", chan->name);
if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
ast_log(LOG_WARNING, "error while disabling T.38 on channel '%s'\n", chan->name);
ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
return -1;
}
@ -940,12 +1019,12 @@ static int disable_t38(struct ast_channel *chan)
while (ms > 0) {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "error while disabling T.38 on channel '%s'\n", chan->name);
ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
return -1;
}
if (ms == 0) { /* all done, nothing happened */
ast_log(LOG_WARNING, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
break;
}
@ -987,7 +1066,7 @@ static struct ast_control_t38_parameters our_t38_parameters = {
};
/*! \brief this is the generic FAX session handling function */
static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details)
static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details, struct ast_fax_session *reserved)
{
int ms;
int timeout = RES_FAX_TIMEOUT;
@ -1005,7 +1084,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
chancount = 1;
/* create the FAX session */
if (!(fax = fax_session_new(details, chan))) {
if (!(fax = fax_session_new(details, chan, reserved))) {
ast_log(LOG_ERROR, "Can't create a FAX session, FAX attempt failed.\n");
report_fax_status(chan, details, "No Available Resource");
return -1;
@ -1093,7 +1172,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
* FAX session complete before we exit the application. if needed,
* send the FAX stack silence so the modems can finish their session without
* any problems */
ast_log(LOG_NOTICE, "Channel '%s' did not return a frame; probably hung up.\n", chan->name);
ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", chan->name);
GENERIC_FAX_EXEC_SET_VARS(fax, chan, "HANGUP", "remote channel hungup");
c = NULL;
chancount = 0;
@ -1295,7 +1374,7 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
ast_playtones_stop(chan);
break;
case AST_T38_NEGOTIATED:
ast_log(LOG_NOTICE, "Negotiated T.38 for receive on %s\n", chan->name);
ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
@ -1316,7 +1395,7 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
}
/* request T.38 */
ast_log(LOG_NOTICE, "Negotiating T.38 for receive on %s\n", chan->name);
ast_debug(1, "Negotiating T.38 for receive on %s\n", chan->name);
/* wait up to five seconds for negotiation to complete */
ms = 5000;
@ -1358,7 +1437,7 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
break;
case AST_T38_NEGOTIATED:
ast_log(LOG_NOTICE, "Negotiated T.38 for receive on %s\n", chan->name);
ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
@ -1402,6 +1481,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
char *parse, modems[128] = "";
int channel_alive;
struct ast_fax_session_details *details;
struct ast_fax_session *s;
struct ast_fax_document *doc;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filename);
@ -1498,15 +1578,6 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
return -1;
}
/* make sure the channel is up */
if (chan->_state != AST_STATE_UP) {
if (ast_answer(chan)) {
ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
ao2_ref(details, -1);
return -1;
}
}
ast_atomic_fetchadd_int(&faxregistry.fax_rx_attempts, 1);
pbx_builtin_setvar_helper(chan, "FAXERROR", "Channel Problems");
@ -1543,10 +1614,31 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
}
if (!(s = fax_session_reserve(details))) {
ast_string_field_set(details, resultstr, "error reserving fax session");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
ao2_ref(details, -1);
return -1;
}
/* make sure the channel is up */
if (chan->_state != AST_STATE_UP) {
if (ast_answer(chan)) {
ast_string_field_set(details, resultstr, "error answering channel");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
ao2_ref(s, -1);
ao2_ref(details, -1);
return -1;
}
}
if (set_fax_t38_caps(chan, details)) {
ast_string_field_set(details, error, "T38_NEG_ERROR");
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
ao2_ref(s, -1);
ao2_ref(details, -1);
return -1;
}
@ -1556,6 +1648,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "T38_NEG_ERROR");
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
ao2_ref(s, -1);
ao2_ref(details, -1);
ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
return -1;
@ -1564,13 +1657,13 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
details->option.send_ced = 1;
}
if ((channel_alive = generic_fax_exec(chan, details)) < 0) {
if ((channel_alive = generic_fax_exec(chan, details, s)) < 0) {
ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
}
if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
if (disable_t38(chan)) {
ast_log(LOG_WARNING, "error disabling T.38 mode on %s\n", chan->name);
ast_debug(1, "error disabling T.38 mode on %s\n", chan->name);
}
}
@ -1602,6 +1695,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
args.filename);
ast_channel_unlock(chan);
ao2_ref(s, -1);
ao2_ref(details, -1);
/* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
@ -1666,7 +1760,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
ast_playtones_stop(chan);
break;
case AST_T38_NEGOTIATED:
ast_log(LOG_NOTICE, "Negotiated T.38 for send on %s\n", chan->name);
ast_debug(1, "Negotiated T.38 for send on %s\n", chan->name);
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
@ -1687,7 +1781,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
/* T.38 negotiation did not happen, initiate a switch if requested */
if (details->option.request_t38 == AST_FAX_OPTFLAG_TRUE) {
ast_log(LOG_NOTICE, "Negotiating T.38 for send on %s\n", chan->name);
ast_debug(1, "Negotiating T.38 for send on %s\n", chan->name);
/* wait up to five seconds for negotiation to complete */
ms = 5000;
@ -1729,7 +1823,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
break;
case AST_T38_NEGOTIATED:
ast_log(LOG_NOTICE, "Negotiated T.38 for receive on %s\n", chan->name);
ast_debug(1, "Negotiated T.38 for receive on %s\n", chan->name);
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
@ -1798,7 +1892,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
ast_playtones_stop(chan);
break;
case AST_T38_NEGOTIATED:
ast_log(LOG_NOTICE, "Negotiated T.38 for send on %s\n", chan->name);
ast_debug(1, "Negotiated T.38 for send on %s\n", chan->name);
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
@ -1839,6 +1933,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
char *parse, *filenames, *c, modems[128] = "";
int channel_alive, file_count;
struct ast_fax_session_details *details;
struct ast_fax_session *s;
struct ast_fax_document *doc;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filenames);
@ -1936,15 +2031,6 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
return -1;
}
/* make sure the channel is up */
if (chan->_state != AST_STATE_UP) {
if (ast_answer(chan)) {
ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
ao2_ref(details, -1);
return -1;
}
}
ast_atomic_fetchadd_int(&faxregistry.fax_tx_attempts, 1);
file_count = 0;
@ -2003,10 +2089,31 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
details->option.request_t38 = AST_FAX_OPTFLAG_TRUE;
}
if (!(s = fax_session_reserve(details))) {
ast_string_field_set(details, resultstr, "error reserving fax session");
set_channel_variables(chan, details);
ast_log(LOG_ERROR, "Unable to reserve FAX session.\n");
ao2_ref(details, -1);
return -1;
}
/* make sure the channel is up */
if (chan->_state != AST_STATE_UP) {
if (ast_answer(chan)) {
ast_string_field_set(details, resultstr, "error answering channel");
set_channel_variables(chan, details);
ast_log(LOG_WARNING, "Channel '%s' failed answer attempt.\n", chan->name);
ao2_ref(s, -1);
ao2_ref(details, -1);
return -1;
}
}
if (set_fax_t38_caps(chan, details)) {
ast_string_field_set(details, error, "T38_NEG_ERROR");
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
ao2_ref(s, -1);
ao2_ref(details, -1);
return -1;
}
@ -2016,6 +2123,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_string_field_set(details, error, "T38_NEG_ERROR");
ast_string_field_set(details, resultstr, "error negotiating T.38");
set_channel_variables(chan, details);
ao2_ref(s, -1);
ao2_ref(details, -1);
ast_log(LOG_ERROR, "error initializing channel '%s' in T.38 mode\n", chan->name);
return -1;
@ -2024,18 +2132,19 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
details->option.send_cng = 1;
}
if ((channel_alive = generic_fax_exec(chan, details)) < 0) {
if ((channel_alive = generic_fax_exec(chan, details, s)) < 0) {
ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
}
if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) {
if (disable_t38(chan)) {
ast_log(LOG_WARNING, "error disabling T.38 mode on %s\n", chan->name);
ast_debug(1, "error disabling T.38 mode on %s\n", chan->name);
}
}
if (!(filenames = generate_filenames_string(details, "FileName: ", "\r\n"))) {
ast_log(LOG_ERROR, "Error generating SendFAX manager event\n");
ao2_ref(s, -1);
ao2_ref(details, -1);
return (!channel_alive) ? -1 : 0;
}
@ -2069,6 +2178,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_free(filenames);
ao2_ref(s, -1);
ao2_ref(details, -1);
/* If the channel hungup return -1; otherwise, return 0 to continue in the dialplan */
@ -2307,6 +2417,7 @@ static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli
ast_cli(a->fd, "\nFAX Statistics:\n---------------\n\n");
ast_cli(a->fd, "%-20.20s : %d\n", "Current Sessions", faxregistry.active_sessions);
ast_cli(a->fd, "%-20.20s : %d\n", "Reserved Sessions", faxregistry.reserved_sessions);
ast_cli(a->fd, "%-20.20s : %d\n", "Transmit Attempts", faxregistry.fax_tx_attempts);
ast_cli(a->fd, "%-20.20s : %d\n", "Receive Attempts", faxregistry.fax_rx_attempts);
ast_cli(a->fd, "%-20.20s : %d\n", "Completed FAXes", faxregistry.fax_complete);
@ -2616,6 +2727,7 @@ static int load_module(void)
/* initialize the registry */
faxregistry.active_sessions = 0;
faxregistry.reserved_sessions = 0;
if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
return AST_MODULE_LOAD_DECLINE;
}