diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_fax.c | 109 | ||||
-rw-r--r-- | res/res_pjsip_refer.c | 7 | ||||
-rw-r--r-- | res/res_pjsip_t38.c | 14 |
3 files changed, 104 insertions, 26 deletions
diff --git a/res/res_fax.c b/res/res_fax.c index 86260d10e..e37091b31 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -641,6 +641,7 @@ static void fixup_callback(void *data, struct ast_channel *old_chan, struct ast_ struct ast_fax_session_details *new_details = find_or_create_details(new_chan); ast_framehook_detach(old_chan, old_details->gateway_id); + new_details->is_t38_negotiated = old_details->is_t38_negotiated; fax_gateway_attach(new_chan, new_details); ao2_cleanup(new_details); } @@ -1439,6 +1440,7 @@ static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_de static void set_channel_variables(struct ast_channel *chan, struct ast_fax_session_details *details) { char buf[10]; + pbx_builtin_setvar_helper(chan, "FAXSTATUS", S_OR(details->result, NULL)); pbx_builtin_setvar_helper(chan, "FAXERROR", S_OR(details->error, NULL)); pbx_builtin_setvar_helper(chan, "FAXSTATUSSTRING", S_OR(details->resultstr, NULL)); @@ -1447,7 +1449,7 @@ static void set_channel_variables(struct ast_channel *chan, struct ast_fax_sessi pbx_builtin_setvar_helper(chan, "FAXBITRATE", S_OR(details->transfer_rate, NULL)); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", S_OR(details->resolution, NULL)); - if (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED) { + if (details->is_t38_negotiated) { pbx_builtin_setvar_helper(chan, "FAXMODE", "T38"); } else { pbx_builtin_setvar_helper(chan, "FAXMODE", "audio"); @@ -1656,6 +1658,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det ast_string_field_set(details, result, ""); ast_string_field_set(details, resultstr, ""); ast_string_field_set(details, error, ""); + details->is_t38_negotiated = t38negotiated; set_channel_variables(chan, details); if (fax->tech->start_session(fax) < 0) { @@ -1706,12 +1709,18 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det * do T.38 as well */ t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters); - t38_parameters.request_response = (details->caps & AST_FAX_TECH_T38) ? AST_T38_NEGOTIATED : AST_T38_REFUSED; + if (details->caps & AST_FAX_TECH_T38) { + details->is_t38_negotiated = 1; + t38_parameters.request_response = AST_T38_NEGOTIATED; + } else { + t38_parameters.request_response = AST_T38_REFUSED; + } ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)); break; case AST_T38_NEGOTIATED: t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters); t38negotiated = 1; + details->is_t38_negotiated = 1; break; default: break; @@ -2880,11 +2889,17 @@ static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_ return gateway; } -/*! \brief Create a fax session and start T.30<->T.38 gateway mode +/*! + * \brief Create a fax session and start T.30<->T.38 gateway mode + * * \param gateway a fax gateway object * \param details fax session details * \param chan active channel - * \return 0 on error 1 on success*/ + * + * \pre chan is locked on entry + * + * \return 0 on error 1 on success + */ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session_details *details, struct ast_channel *chan) { struct ast_fax_session *s; @@ -2896,6 +2911,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error starting gateway session"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); report_fax_status(chan, details, "No Available Resource"); ast_log(LOG_ERROR, "Can't create a FAX session, gateway attempt failed.\n"); @@ -2916,6 +2932,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error starting gateway session"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return -1; } @@ -2928,6 +2945,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session return 0; } +/*! \pre chan is locked on entry */ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_frame *f) { struct ast_frame *fp; @@ -2960,12 +2978,14 @@ 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->is_t38_negotiated = 0; details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ast_debug(1, "requesting T.38 for gateway session for %s\n", ast_channel_name(chan)); return fp; } +/*! \pre chan is locked on entry */ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f) { struct ast_channel *other = (active == chan) ? peer : chan; @@ -2981,8 +3001,14 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str } if (gateway->detected_v21) { + enum ast_t38_state state_other; + destroy_v21_sessions(gateway); - if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) { + + ast_channel_unlock(chan); + state_other = ast_channel_get_t38_state(other); + ast_channel_lock(chan); + if (state_other == T38_STATE_UNKNOWN) { ast_debug(1, "detected v21 preamble from %s\n", ast_channel_name(active)); return fax_gateway_request_t38(gateway, chan, f); } else { @@ -2993,21 +3019,29 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str return f; } -static int fax_gateway_indicate_t38(struct ast_channel *chan, struct ast_channel *active, struct ast_control_t38_parameters *control_params) +/*! \pre chan is locked on entry */ +static void fax_gateway_indicate_t38(struct ast_channel *chan, struct ast_channel *active, struct ast_control_t38_parameters *control_params) { if (active == chan) { - return ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); + ast_channel_unlock(chan); + ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); + ast_channel_lock(chan); } else { - return ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); + ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params)); } } -/*! \brief T38 Gateway Negotiate t38 parameters +/*! + * \brief T38 Gateway Negotiate t38 parameters + * * \param gateway gateway object * \param chan channel running the gateway * \param peer channel im bridged too * \param active channel the frame originated on * \param f the control frame to process + * + * \pre chan is locked on entry + * * \return processed control frame or null frame */ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f) @@ -3015,6 +3049,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str struct ast_control_t38_parameters *control_params = f->data.ptr; struct ast_channel *other = (active == chan) ? peer : chan; struct ast_fax_session_details *details; + enum ast_t38_state state_other; if (f->datalen != sizeof(struct ast_control_t38_parameters)) { /* invalaid AST_CONTROL_T38_PARAMETERS frame, we can't @@ -3037,9 +3072,11 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str } if (control_params->request_response == AST_T38_REQUEST_NEGOTIATE) { - enum ast_t38_state state = ast_channel_get_t38_state(other); + ast_channel_unlock(chan); + state_other = ast_channel_get_t38_state(other); + ast_channel_lock(chan); - if (state == T38_STATE_UNKNOWN) { + if (state_other == T38_STATE_UNKNOWN) { /* we detected a request to negotiate T.38 and the * other channel appears to support T.38, we'll pass * the request through and only step in if the other @@ -3048,10 +3085,11 @@ 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->is_t38_negotiated = 0; details->gateway_timeout = FAX_GATEWAY_TIMEOUT; ao2_ref(details, -1); return f; - } else if (state == T38_STATE_UNAVAILABLE || state == T38_STATE_REJECTED) { + } else if (state_other == T38_STATE_UNAVAILABLE || state_other == T38_STATE_REJECTED) { /* the other channel does not support T.38, we need to * step in here */ ast_debug(1, "%s is attempting to negotiate T.38 but %s does not support it\n", ast_channel_name(active), ast_channel_name(other)); @@ -3063,12 +3101,14 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str if (fax_gateway_start(gateway, details, chan)) { ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(active), ast_channel_name(other)); gateway->t38_state = T38_STATE_REJECTED; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_REFUSED; ast_framehook_detach(chan, details->gateway_id); details->gateway_id = -1; } else { gateway->t38_state = T38_STATE_NEGOTIATED; + details->is_t38_negotiated = chan == active; control_params->request_response = AST_T38_NEGOTIATED; report_fax_status(chan, details, "T.38 Negotiated"); } @@ -3086,6 +3126,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->is_t38_negotiated = 0; 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", ast_channel_name(active)); @@ -3108,6 +3149,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "no gateway necessary"); ast_string_field_set(details, error, "NATIVE_T38"); + details->is_t38_negotiated = 1; set_channel_variables(chan, details); ast_debug(1, "%s is attempting to negotiate T.38 after we already negotiated T.38 with %s, disabling the gateway\n", ast_channel_name(active), ast_channel_name(other)); @@ -3122,11 +3164,15 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str && control_params->request_response == AST_T38_REFUSED) { ast_debug(1, "unable to negotiate T.38 on %s for fax gateway\n", ast_channel_name(active)); + details->is_t38_negotiated = 0; /* our request to negotiate T.38 was refused, if the other * channel supports T.38, they might still reinvite and save * the day. Otherwise disable the gateway. */ - if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) { + ast_channel_unlock(chan); + state_other = ast_channel_get_t38_state(other); + ast_channel_lock(chan); + if (state_other == T38_STATE_UNKNOWN) { gateway->t38_state = T38_STATE_UNAVAILABLE; } else { ast_framehook_detach(chan, details->gateway_id); @@ -3150,11 +3196,13 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str if (fax_gateway_start(gateway, details, chan)) { ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(active), ast_channel_name(other)); gateway->t38_state = T38_STATE_NEGOTIATING; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_REQUEST_TERMINATE; fax_gateway_indicate_t38(chan, active, control_params); } else { gateway->t38_state = T38_STATE_NEGOTIATED; + details->is_t38_negotiated = chan == active; report_fax_status(chan, details, "T.38 Negotiated"); } @@ -3170,14 +3218,16 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str t38_parameters_fax_to_ast(control_params, &details->our_t38_parameters); if (fax_gateway_start(gateway, details, chan)) { - ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(active), ast_channel_name(other)); + ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", ast_channel_name(other), ast_channel_name(active)); gateway->t38_state = T38_STATE_REJECTED; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_REFUSED; ast_framehook_detach(chan, details->gateway_id); details->gateway_id = -1; } else { gateway->t38_state = T38_STATE_NEGOTIATED; + details->is_t38_negotiated = chan == other; control_params->request_response = AST_T38_NEGOTIATED; } @@ -3193,6 +3243,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str details->gateway_id = -1; gateway->t38_state = T38_STATE_REJECTED; + details->is_t38_negotiated = 0; control_params->request_response = AST_T38_TERMINATED; fax_gateway_indicate_t38(chan, active, control_params); @@ -3208,6 +3259,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "no gateway necessary"); ast_string_field_set(details, error, "NATIVE_T38"); + details->is_t38_negotiated = 1; set_channel_variables(chan, details); ao2_ref(details, -1); @@ -3250,7 +3302,8 @@ static void fax_gateway_framehook_destroy(void *data) ao2_ref(gateway, -1); } -/*! \brief T.30<->T.38 gateway framehook. +/*! + * \brief T.30<->T.38 gateway framehook. * * Intercept packets on bridged channels and determine if a T.38 gateway is * required. If a gateway is required, start a gateway and handle T.38 @@ -3261,6 +3314,8 @@ static void fax_gateway_framehook_destroy(void *data) * \param event framehook event * \param data framehook data (struct fax_gateway *) * + * \pre chan is locked on entry + * * \return processed frame or NULL when f is NULL or a null frame */ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) @@ -3323,8 +3378,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct } if (!gateway->bridged) { + enum ast_t38_state state_chan; + enum ast_t38_state state_peer; + + ast_channel_unlock(chan); + state_chan = ast_channel_get_t38_state(chan); + state_peer = ast_channel_get_t38_state(peer); + ast_channel_lock(chan); + /* don't start a gateway if neither channel can handle T.38 */ - if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) { + if (state_chan == T38_STATE_UNAVAILABLE && state_peer == T38_STATE_UNAVAILABLE) { ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", ast_channel_name(chan), ast_channel_name(peer)); ast_framehook_detach(chan, gateway->framehook); details->gateway_id = -1; @@ -3332,6 +3395,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct 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"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return f; } @@ -3376,6 +3440,7 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_string_field_set(details, result, "FAILED"); ast_string_field_build(details, resultstr, "no fax activity after %d ms", details->gateway_timeout); ast_string_field_set(details, error, "TIMEOUT"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return f; } @@ -3491,9 +3556,9 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d .disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */ }; - if (global_fax_debug) { - details->option.debug = AST_FAX_OPTFLAG_TRUE; - } + if (global_fax_debug) { + details->option.debug = AST_FAX_OPTFLAG_TRUE; + } ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "gateway operation started successfully"); @@ -3506,6 +3571,7 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error initializing gateway session"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); report_fax_status(chan, details, "No Available Resource"); return -1; @@ -3521,6 +3587,7 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d ast_string_field_set(details, result, "FAILED"); ast_string_field_set(details, resultstr, "error attaching gateway to channel"); ast_string_field_set(details, error, "INIT_ERROR"); + details->is_t38_negotiated = 0; set_channel_variables(chan, details); return -1; } @@ -4509,7 +4576,9 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat ast_log(LOG_WARNING, "Attempt to attach a T.38 gateway on channel (%s) with gateway already running.\n", ast_channel_name(chan)); } } else if (ast_false(val)) { + ast_channel_lock(chan); ast_framehook_detach(chan, details->gateway_id); + ast_channel_unlock(chan); details->gateway_id = -1; } else { ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data); @@ -4561,7 +4630,9 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat ast_log(LOG_WARNING, "Attempt to attach a FAX detect on channel (%s) with FAX detect already running.\n", ast_channel_name(chan)); } } else if (ast_false(val)) { + ast_channel_lock(chan); ast_framehook_detach(chan, details->faxdetect_id); + ast_channel_unlock(chan); details->faxdetect_id = -1; } else { ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index e5bb90e5c..8fe4e8477 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -607,7 +607,10 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann ao2_ref(refer->progress, +1); /* If we can't attach a frame hook for whatever reason send a notification of success immediately */ - if ((refer->progress->framehook = ast_framehook_attach(chan, &hook)) < 0) { + ast_channel_lock(chan); + refer->progress->framehook = ast_framehook_attach(chan, &hook); + ast_channel_unlock(chan); + if (refer->progress->framehook < 0) { struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200, PJSIP_EVSUB_STATE_TERMINATED); @@ -638,7 +641,9 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann refer_progress_notify(notification); } + ast_channel_lock(chan); ast_framehook_detach(chan, refer->progress->framehook); + ast_channel_unlock(chan); ao2_cleanup(refer->progress); } diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 992902af2..01bfefdd9 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -501,25 +501,27 @@ static void t38_attach_framehook(struct ast_sip_session *session) return; } - /* Skip attaching the framehook if the T.38 datastore already exists for the channel */ ast_channel_lock(session->channel); - if ((datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, NULL))) { + + /* Skip attaching the framehook if the T.38 datastore already exists for the channel */ + datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, + NULL); + if (datastore) { ast_channel_unlock(session->channel); return; } - ast_channel_unlock(session->channel); framehook_id = ast_framehook_attach(session->channel, &hook); if (framehook_id < 0) { - ast_log(LOG_WARNING, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n", + ast_log(LOG_WARNING, "Could not attach T.38 Frame hook, T.38 will be unavailable on '%s'\n", ast_channel_name(session->channel)); + ast_channel_unlock(session->channel); return; } - ast_channel_lock(session->channel); datastore = ast_datastore_alloc(&t38_framehook_datastore, NULL); if (!datastore) { - ast_log(LOG_ERROR, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n", + ast_log(LOG_ERROR, "Could not alloc T.38 Frame hook datastore, T.38 will be unavailable on '%s'\n", ast_channel_name(session->channel)); ast_framehook_detach(session->channel, framehook_id); ast_channel_unlock(session->channel); |