diff options
Diffstat (limited to 'res/res_fax.c')
-rw-r--r-- | res/res_fax.c | 82 |
1 files changed, 68 insertions, 14 deletions
diff --git a/res/res_fax.c b/res/res_fax.c index 50be862a4..fe0b6f904 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -192,6 +192,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <enum name="gateway"> <para>R/W T38 Gateway Enabled (yes/no)</para> </enum> + <enum name="timeout"> + <para>R/W Gateway fax activity timeout in seconds (yes/no/seconds)</para> + </enum> <enum name="pages"> <para>R/O Number of pages transferred.</para> </enum> @@ -452,6 +455,7 @@ static struct ast_fax_session_details *session_details_new(void) d->minrate = general_options.minrate; d->maxrate = general_options.maxrate; d->gateway_id = -1; + d->gateway_timeout = FAX_GATEWAY_TIMEOUT; return d; } @@ -2419,7 +2423,7 @@ static struct fax_gateway *fax_gateway_new(struct ast_fax_session_details *detai ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_V21); details->caps = AST_FAX_TECH_GATEWAY; - if (!(gateway->s = fax_session_reserve(details, &gateway->token))) { + if (details->gateway_timeout && !(gateway->s = fax_session_reserve(details, &gateway->token))) { details->caps |= ~AST_FAX_TECH_GATEWAY; ast_log(LOG_ERROR, "Can't reserve a FAX session, gateway attempt failed.\n"); ao2_ref(gateway, -1); @@ -2503,6 +2507,7 @@ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, st gateway->t38_state = T38_STATE_NEGOTIATING; gateway->timeout_start = ast_tvnow(); + details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ast_debug(1, "requesting T.38 for gateway session for %s\n", chan->name); return fp; @@ -2595,6 +2600,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params); gateway->t38_state = T38_STATE_UNKNOWN; gateway->timeout_start = ast_tvnow(); + details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ao2_ref(details, -1); return f; } else if (state == T38_STATE_UNAVAILABLE || state == T38_STATE_REJECTED) { @@ -2632,6 +2638,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params); gateway->t38_state = T38_STATE_UNKNOWN; gateway->timeout_start = ast_tvnow(); + details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ast_debug(1, "%s is attempting to negotiate T.38 after we already sent a negotiation request based on v21 preamble detection\n", active->name); ao2_ref(details, -1); @@ -2810,10 +2817,23 @@ static void fax_gateway_framehook_destroy(void *data) { static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) { struct fax_gateway *gateway = data; struct ast_channel *peer, *active; + struct ast_fax_session_details *details; + + if (gateway->s) { + details = gateway->s->details; + ao2_ref(details, 1); + } else { + if (!(details = find_details(chan))) { + ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name); + ast_framehook_detach(chan, gateway->framehook); + details->gateway_id = -1; + return f; + } + } /* restore audio formats when we are detached */ if (event == AST_FRAMEHOOK_EVENT_DETACHED) { - set_channel_variables(chan, gateway->s->details); + set_channel_variables(chan, details); if (gateway->bridged) { ast_set_read_format(chan, &gateway->chan_read_format); @@ -2826,20 +2846,24 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct } } + ao2_ref(details, -1); return NULL; } if (!f || (event == AST_FRAMEHOOK_EVENT_ATTACHED)) { + ao2_ref(details, -1); return NULL; }; /* this frame was generated by the fax gateway, pass it on */ if (ast_test_flag(f, AST_FAX_FRFLAG_GATEWAY)) { + ao2_ref(details, -1); return f; } if (!(peer = ast_bridged_channel(chan))) { /* not bridged, don't do anything */ + ao2_ref(details, -1); return f; } @@ -2848,16 +2872,19 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) { ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", chan->name, peer->name); ast_framehook_detach(chan, gateway->framehook); - gateway->s->details->gateway_id = -1; + details->gateway_id = -1; - ast_string_field_set(gateway->s->details, result, "FAILED"); - ast_string_field_set(gateway->s->details, resultstr, "neither channel supports T.38"); - ast_string_field_set(gateway->s->details, error, "T38_NEG_ERROR"); - set_channel_variables(chan, gateway->s->details); + ast_string_field_set(details, result, "FAILED"); + ast_string_field_set(details, resultstr, "neither channel supports T.38"); + ast_string_field_set(details, error, "T38_NEG_ERROR"); + set_channel_variables(chan, details); + ao2_ref(details, -1); return f; } - gateway->timeout_start = ast_tvnow(); + if (details->gateway_timeout) { + gateway->timeout_start = ast_tvnow(); + } /* we are bridged, change r/w formats to SLIN for v21 preamble * detection and T.30 */ @@ -2878,15 +2905,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct } if (gateway->bridged && !ast_tvzero(gateway->timeout_start)) { - if (ast_tvdiff_ms(ast_tvnow(), gateway->timeout_start) > FAX_GATEWAY_TIMEOUT) { + if (ast_tvdiff_ms(ast_tvnow(), gateway->timeout_start) > details->gateway_timeout) { ast_debug(1, "no fax activity between %s and %s after %d ms, disabling gateway\n", chan->name, peer->name, FAX_GATEWAY_TIMEOUT); ast_framehook_detach(chan, gateway->framehook); - gateway->s->details->gateway_id = -1; + details->gateway_id = -1; - ast_string_field_set(gateway->s->details, result, "FAILED"); - ast_string_field_build(gateway->s->details, resultstr, "no fax activity after %d ms", FAX_GATEWAY_TIMEOUT); - ast_string_field_set(gateway->s->details, error, "TIMEOUT"); - set_channel_variables(chan, gateway->s->details); + ast_string_field_set(details, result, "FAILED"); + ast_string_field_build(details, resultstr, "no fax activity after %d ms", FAX_GATEWAY_TIMEOUT); + ast_string_field_set(details, error, "TIMEOUT"); + set_channel_variables(chan, details); + ao2_ref(details, -1); return f; } } @@ -2900,6 +2928,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct case AST_FORMAT_ULAW: break; default: + ao2_ref(details, -1); return f; } break; @@ -2907,13 +2936,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct if (f->subclass.integer == AST_MODEM_T38) { break; } + ao2_ref(details, -1); return f; case AST_FRAME_CONTROL: if (f->subclass.integer == AST_CONTROL_T38_PARAMETERS) { break; } + ao2_ref(details, -1); return f; default: + ao2_ref(details, -1); return f; } @@ -2927,17 +2959,20 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct break; default: ast_log(LOG_WARNING, "unhandled framehook event %i\n", event); + ao2_ref(details, -1); return f; } /* handle control frames */ if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) { + ao2_ref(details, -1); return fax_gateway_detect_t38(gateway, chan, peer, active, f); } if (!gateway->detected_v21 && gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) { /* not in gateway mode and have not detected v21 yet, listen * for v21 */ + ao2_ref(details, -1); return fax_gateway_detect_v21(gateway, chan, peer, active, f); } @@ -2948,6 +2983,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id != AST_FORMAT_SLINEAR)) { if (active->readtrans && (f = ast_translate(active->readtrans, f, 1)) == NULL) { f = &ast_null_frame; + ao2_ref(details, -1); return f; } } @@ -2958,6 +2994,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct * now we'll just ignore the return value. */ gateway->s->tech->write(gateway->s, f); f = &ast_null_frame; + ao2_ref(details, -1); return f; } @@ -2974,12 +3011,15 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_format_set(&silence_frame.subclass.format, AST_FORMAT_SLINEAR, 0); memset(silence_buf, 0, sizeof(silence_buf)); + ao2_ref(details, -1); return ast_frisolate(&silence_frame); } else { + ao2_ref(details, -1); return &ast_null_frame; } } + ao2_ref(details, -1); return f; } @@ -3432,6 +3472,8 @@ static int acf_faxopt_read(struct ast_channel *chan, const char *cmd, char *data } else if (!strcasecmp(data, "t38gateway") || !strcasecmp(data, "gateway") || !strcasecmp(data, "t38_gateway") || !strcasecmp(data, "faxgateway")) { ast_copy_string(buf, details->gateway_id != -1 ? "yes" : "no", len); + } else if (!strcasecmp(data, "timeout")) { + snprintf(buf, len, "%d", details->gateway_timeout / 1000); } else if (!strcasecmp(data, "error")) { ast_copy_string(buf, details->error, len); } else if (!strcasecmp(data, "filename")) { @@ -3527,6 +3569,18 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat } else { ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data); } + } else if (!strcasecmp(data, "timeout")) { + const char *val = ast_skip_blanks(value); + int timeout; + if (ast_true(val)) { + details->gateway_timeout = FAX_GATEWAY_TIMEOUT; + } else if (ast_false(val)) { + details->gateway_timeout = 0; + } else if (sscanf(val, "%d", &timeout) == 1 && timeout > 0) { + details->gateway_timeout = timeout * 1000; + } else { + ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data); + } } else if (!strcasecmp(data, "headerinfo")) { ast_string_field_set(details, headerinfo, value); } else if (!strcasecmp(data, "localstationid")) { |