diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 110 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 78 |
2 files changed, 132 insertions, 56 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index be9db0776..9cd0608d9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3052,7 +3052,7 @@ static void enable_dsp_detect(struct sip_pvt *p) } } - if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT)) { + if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { features |= DSP_FEATURE_FAX_DETECT; } @@ -4163,6 +4163,11 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout) res = 0; ast_set_flag(&p->flags[0], SIP_OUTGOING); + /* T.38 re-INVITE FAX detection should never be done for outgoing calls, + * so ensure it is disabled. + */ + ast_clear_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38); + if (p->options->transfer) { char buf[SIPBUFSIZE/2]; @@ -5199,22 +5204,24 @@ static int sip_transfer(struct ast_channel *ast, const char *dest) } /*! \brief Helper function which updates T.38 capability information and triggers a reinvite */ -static void interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_t38_parameters *parameters) +static int interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_t38_parameters *parameters) { + int res = 0; + if (!ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) { - return; + return -1; } switch (parameters->request_response) { case AST_T38_NEGOTIATED: case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */ /* Negotiation can not take place without a valid max_ifp value. */ if (!parameters->max_ifp) { - change_t38_state(p, T38_DISABLED); - if (p->t38.state == T38_PEER_REINVITE) { - AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); - transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); - } - break; + change_t38_state(p, T38_DISABLED); + if (p->t38.state == T38_PEER_REINVITE) { + AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); + transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); + } + break; } else if (p->t38.state == T38_PEER_REINVITE) { AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr")); p->t38.our_parms = *parameters; @@ -5256,9 +5263,28 @@ static void interpret_t38_parameters(struct sip_pvt *p, const struct ast_control } else if (p->t38.state == T38_ENABLED) transmit_reinvite_with_sdp(p, FALSE, FALSE); break; + case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */ + struct ast_control_t38_parameters parameters = p->t38.their_parms; + + if (p->t38.state == T38_PEER_REINVITE) { + AST_SCHED_DEL(sched, p->t38id); + parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl); + parameters.request_response = AST_T38_REQUEST_NEGOTIATE; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); + /* we need to return a positive value here, so that applications that + * send this request can determine conclusively whether it was accepted or not... + * older versions of chan_sip would just silently accept it and return zero. + */ + res = AST_T38_REQUEST_PARMS; + } + break; + } default: + res = -1; break; } + + return res; } /*! \brief Play indication to user @@ -5348,9 +5374,10 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data case AST_CONTROL_T38_PARAMETERS: if (datalen != sizeof(struct ast_control_t38_parameters)) { ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int) sizeof(struct ast_control_t38_parameters), (int) datalen); + res = -1; } else { const struct ast_control_t38_parameters *parameters = data; - interpret_t38_parameters(p, parameters); + res = interpret_t38_parameters(p, parameters); } break; case AST_CONTROL_SRCUPDATE: @@ -5838,20 +5865,20 @@ static struct ast_frame *sip_read(struct ast_channel *ast) p->lastrtprx = time(NULL); /* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */ - if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT)) { + if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { ast_channel_lock(ast); if (strcmp(ast->exten, "fax")) { const char *target_context = S_OR(ast->macrocontext, ast->context); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) { - ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension\n", ast->name); + ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to CNG detection\n", ast->name); pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten); if (ast_async_goto(ast, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context); } fr = &ast_null_frame; } else { - ast_log(LOG_NOTICE, "Fax detected but no fax extension\n"); + ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n"); } } else { ast_channel_unlock(ast); @@ -7154,6 +7181,25 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } else if ((t38action == SDP_T38_INITIATE) && p->owner && p->lastinvite) { change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */ + /* If fax detection is enabled then send us off to the fax extension */ + if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38)) { + ast_channel_lock(p->owner); + if (strcmp(p->owner->exten, "fax")) { + const char *target_context = S_OR(p->owner->macrocontext, p->owner->context); + ast_channel_unlock(p->owner); + if (ast_exists_extension(p->owner, target_context, "fax", 1, p->owner->cid.cid_num)) { + ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to peer T.38 re-INVITE\n", p->owner->name); + pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten); + if (ast_async_goto(p->owner, target_context, "fax", 1)) { + ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, target_context); + } + } else { + ast_log(LOG_NOTICE, "T.38 re-INVITE detected but no fax extension\n"); + } + } else { + ast_channel_unlock(p->owner); + } + } } } else { ast_udptl_stop(p->udptl); @@ -18825,15 +18871,24 @@ static int do_magic_pickup(struct ast_channel *channel, const char *extension, c return 0; } +/*! \brief Called to deny a T38 reinvite if the core does not respond to our request */ static int sip_t38_abort(const void *data) { struct sip_pvt *p = (struct sip_pvt *) data; - change_t38_state(p, T38_DISABLED); - transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); - p->t38id = -1; - dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr"); - + sip_pvt_lock(p); + /* an application may have taken ownership of the T.38 negotiation on this + * channel while we were waiting to grab the lock... if it did, the scheduler + * id will have been reset to -1, which is our indication that we do *not* + * want to abort the negotiation process + */ + if (p->t38id != -1) { + change_t38_state(p, T38_DISABLED); + transmit_response_reliable(p, "488 Not acceptable here", &p->initreq); + p->t38id = -1; + dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr"); + } + sip_pvt_unlock(p); return 0; } @@ -22603,7 +22658,24 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_IGNORESDPVERSION); } else if (!strcasecmp(v->name, "faxdetect")) { ast_set_flag(&mask[1], SIP_PAGE2_FAX_DETECT); - ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_FAX_DETECT); + if (ast_true(v->value)) { + ast_set_flag(&flags[1], SIP_PAGE2_FAX_DETECT_BOTH); + } else if (ast_false(v->value)) { + ast_clear_flag(&flags[1], SIP_PAGE2_FAX_DETECT_BOTH); + } else { + char *buf = ast_strdupa(v->value); + char *word, *next = buf; + + while ((word = strsep(&next, ","))) { + if (!strcasecmp(word, "cng")) { + ast_set_flag(&flags[1], SIP_PAGE2_FAX_DETECT_CNG); + } else if (!strcasecmp(word, "t38")) { + ast_set_flag(&flags[1], SIP_PAGE2_FAX_DETECT_T38); + } else { + ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno); + } + } + } } else if (!strcasecmp(v->name, "rfc2833compensate")) { ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 57fac84ca..ce87f0f23 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -302,43 +302,47 @@ a second page of flags (for flags[1] */ /*@{*/ /* realtime flags */ -#define SIP_PAGE2_RTCACHEFRIENDS (1 << 0) /*!< GP: Should we keep RT objects in memory for extended time? */ -#define SIP_PAGE2_RTAUTOCLEAR (1 << 2) /*!< GP: Should we clean memory from peers after expiry? */ -#define SIP_PAGE2_RPID_UPDATE (1 << 3) -#define SIP_PAGE2_Q850_REASON (1 << 4) /*!< DP: Get/send cause code via Reason header */ - -/* Space for addition of other realtime flags in the future */ -#define SIP_PAGE2_SYMMETRICRTP (1 << 8) /*!< GDP: Whether symmetric RTP is enabled or not */ -#define SIP_PAGE2_STATECHANGEQUEUE (1 << 9) /*!< D: Unsent state pending change exists */ - -#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 10) -#define SIP_PAGE2_RPID_IMMEDIATE (1 << 11) -#define SIP_PAGE2_RPORT_PRESENT (1 << 12) /*!< Was rport received in the Via header? */ -#define SIP_PAGE2_PREFERRED_CODEC (1 << 13) /*!< GDP: Only respond with single most preferred joint codec */ -#define SIP_PAGE2_VIDEOSUPPORT (1 << 14) /*!< DP: Video supported if offered? */ -#define SIP_PAGE2_TEXTSUPPORT (1 << 15) /*!< GDP: Global text enable */ -#define SIP_PAGE2_ALLOWSUBSCRIBE (1 << 16) /*!< GP: Allow subscriptions from this peer? */ -#define SIP_PAGE2_ALLOWOVERLAP (1 << 17) /*!< DP: Allow overlap dialing ? */ -#define SIP_PAGE2_SUBSCRIBEMWIONLY (1 << 18) /*!< GP: Only issue MWI notification if subscribed to */ -#define SIP_PAGE2_IGNORESDPVERSION (1 << 19) /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */ - -#define SIP_PAGE2_T38SUPPORT (3 << 20) /*!< GDP: T.38 Fax Support */ -#define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 20) /*!< GDP: T.38 Fax Support (no error correction) */ -#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC (2 << 20) /*!< GDP: T.38 Fax Support (FEC error correction) */ -#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY (3 << 20) /*!< GDP: T.38 Fax Support (redundancy error correction) */ - -#define SIP_PAGE2_CALL_ONHOLD (3 << 23) /*!< D: Call hold states: */ -#define SIP_PAGE2_CALL_ONHOLD_ACTIVE (1 << 23) /*!< D: Active hold */ -#define SIP_PAGE2_CALL_ONHOLD_ONEDIR (2 << 23) /*!< D: One directional hold */ -#define SIP_PAGE2_CALL_ONHOLD_INACTIVE (3 << 23) /*!< D: Inactive hold */ - -#define SIP_PAGE2_RFC2833_COMPENSATE (1 << 25) /*!< DP: Compensate for buggy RFC2833 implementations */ -#define SIP_PAGE2_BUGGY_MWI (1 << 26) /*!< DP: Buggy CISCO MWI fix */ -#define SIP_PAGE2_DIALOG_ESTABLISHED (1 << 27) /*!< 29: Has a dialog been established? */ -#define SIP_PAGE2_FAX_DETECT (1 << 28) /*!< DP: Fax Detection support */ -#define SIP_PAGE2_REGISTERTRYING (1 << 29) /*!< DP: Send 100 Trying on REGISTER attempts */ -#define SIP_PAGE2_UDPTL_DESTINATION (1 << 30) /*!< DP: Use source IP of RTP as destination if NAT is enabled */ -#define SIP_PAGE2_VIDEOSUPPORT_ALWAYS (1 << 31) /*!< DP: Always set up video, even if endpoints don't support it */ +#define SIP_PAGE2_RTCACHEFRIENDS (1 << 0) /*!< GP: Should we keep RT objects in memory for extended time? */ +#define SIP_PAGE2_RTAUTOCLEAR (1 << 1) /*!< GP: Should we clean memory from peers after expiry? */ +#define SIP_PAGE2_RPID_UPDATE (1 << 2) +#define SIP_PAGE2_Q850_REASON (1 << 3) /*!< DP: Get/send cause code via Reason header */ + +#define SIP_PAGE2_SYMMETRICRTP (1 << 4) /*!< GDP: Whether symmetric RTP is enabled or not */ +#define SIP_PAGE2_STATECHANGEQUEUE (1 << 5) /*!< D: Unsent state pending change exists */ + +#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 6) +#define SIP_PAGE2_RPID_IMMEDIATE (1 << 7) +#define SIP_PAGE2_RPORT_PRESENT (1 << 8) /*!< Was rport received in the Via header? */ +#define SIP_PAGE2_PREFERRED_CODEC (1 << 9) /*!< GDP: Only respond with single most preferred joint codec */ +#define SIP_PAGE2_VIDEOSUPPORT (1 << 10) /*!< DP: Video supported if offered? */ +#define SIP_PAGE2_TEXTSUPPORT (1 << 11) /*!< GDP: Global text enable */ +#define SIP_PAGE2_ALLOWSUBSCRIBE (1 << 12) /*!< GP: Allow subscriptions from this peer? */ +#define SIP_PAGE2_ALLOWOVERLAP (1 << 13) /*!< DP: Allow overlap dialing ? */ +#define SIP_PAGE2_SUBSCRIBEMWIONLY (1 << 14) /*!< GP: Only issue MWI notification if subscribed to */ +#define SIP_PAGE2_IGNORESDPVERSION (1 << 15) /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */ + +#define SIP_PAGE2_T38SUPPORT (3 << 16) /*!< GDP: T.38 Fax Support */ +#define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 16) /*!< GDP: T.38 Fax Support (no error correction) */ +#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC (2 << 16) /*!< GDP: T.38 Fax Support (FEC error correction) */ +#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY (3 << 16) /*!< GDP: T.38 Fax Support (redundancy error correction) */ + +#define SIP_PAGE2_CALL_ONHOLD (3 << 18) /*!< D: Call hold states: */ +#define SIP_PAGE2_CALL_ONHOLD_ACTIVE (1 << 18) /*!< D: Active hold */ +#define SIP_PAGE2_CALL_ONHOLD_ONEDIR (2 << 18) /*!< D: One directional hold */ +#define SIP_PAGE2_CALL_ONHOLD_INACTIVE (3 << 18) /*!< D: Inactive hold */ + +#define SIP_PAGE2_RFC2833_COMPENSATE (1 << 20) /*!< DP: Compensate for buggy RFC2833 implementations */ +#define SIP_PAGE2_BUGGY_MWI (1 << 21) /*!< DP: Buggy CISCO MWI fix */ +#define SIP_PAGE2_DIALOG_ESTABLISHED (1 << 22) /*!< 29: Has a dialog been established? */ + +#define SIP_PAGE2_FAX_DETECT (3 << 23) /*!< DP: Fax Detection support */ +#define SIP_PAGE2_FAX_DETECT_CNG (1 << 23) /*!< DP: Fax Detection support - detect CNG in audio */ +#define SIP_PAGE2_FAX_DETECT_T38 (2 << 23) /*!< DP: Fax Detection support - detect T.38 reinvite from peer */ +#define SIP_PAGE2_FAX_DETECT_BOTH (3 << 23) /*!< DP: Fax Detection support - detect both */ + +#define SIP_PAGE2_REGISTERTRYING (1 << 24) /*!< DP: Send 100 Trying on REGISTER attempts */ +#define SIP_PAGE2_UDPTL_DESTINATION (1 << 25) /*!< DP: Use source IP of RTP as destination if NAT is enabled */ +#define SIP_PAGE2_VIDEOSUPPORT_ALWAYS (1 << 26) /*!< DP: Always set up video, even if endpoints don't support it */ #define SIP_PAGE2_FLAGS_TO_COPY \ (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \ |