]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_fax: gateway sends T.38 request to both endpoints if V.21 detected
authorAlexei Gradinari <alex2grad@gmail.com>
Wed, 29 May 2019 22:54:16 +0000 (18:54 -0400)
committerAlexei Gradinari <alex2grad@gmail.com>
Thu, 20 Jun 2019 22:57:49 +0000 (16:57 -0600)
According T.38 Gateway 'Use case 3'
https://wiki.asterisk.org/wiki/display/AST/T.38+Gateway
T.38 Gateway should send T.38 negotiation request to called endpoint
if FAX preamble (using V.21 detector) generated by called endpoint.
But it does not, because fax_gateway_detect_v21 constructs T.38
negotiation request, but forwards it only to other channel,
not to the channel on which FAX preamble is detected.

Some SIP endpoints could be improperly configured to rely on the other side
to initiate T.38 re-INVITEs.

With this patch the T.38 Gateway tries to negotiate with both sides
by sending T.38 negotiation request to both endpoints supported T.38.

Change-Id: I73bb24799bfe1a48adae9c034a2edbae54cc2a39

res/res_fax.c

index e4f315a1af706581928e469fd110ce71c51f2e5d..7d9cb4e8ca0a82a8089b2398b940bbe8321e1dfa 100644 (file)
@@ -2921,6 +2921,9 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session
                return 0;
        }
 
+       /* if we start gateway we don't need v21 detection sessions any more */
+       destroy_v21_sessions(gateway);
+
        /* create the FAX session */
        if (!(s = fax_session_new(details, chan, gateway->s, gateway->token))) {
                gateway->token = NULL;
@@ -2962,7 +2965,7 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session
 }
 
 /*! \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)
+static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, struct ast_channel *chan)
 {
        struct ast_frame *fp;
        struct ast_control_t38_parameters t38_parameters = {
@@ -2981,7 +2984,7 @@ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, st
        if (!details) {
                ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", ast_channel_name(chan));
                ast_framehook_detach(chan, gateway->framehook);
-               return f;
+               return NULL;
        }
 
        t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
@@ -2989,7 +2992,7 @@ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, st
 
        if (!(fp = ast_frisolate(&control_frame))) {
                ast_log(LOG_ERROR, "error generating T.38 request control frame on chan %s for T.38 gateway session\n", ast_channel_name(chan));
-               return f;
+               return NULL;
        }
 
        gateway->t38_state = T38_STATE_NEGOTIATING;
@@ -3018,17 +3021,40 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str
 
        if (gateway->detected_v21) {
                enum ast_t38_state state_other;
+               enum ast_t38_state state_active;
+               struct ast_frame *fp;
 
                destroy_v21_sessions(gateway);
 
                ast_channel_unlock(chan);
+               state_active = ast_channel_get_t38_state(active);
                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);
+
+               ast_debug(1, "detected v21 preamble from %s\n", ast_channel_name(active));
+
+               if (state_active == T38_STATE_UNKNOWN || state_other == T38_STATE_UNKNOWN) {
+                       if (!(fp = fax_gateway_request_t38(gateway, chan))) {
+                               return f;
+                       }
+                       /* May be called endpoint is improperly configured to rely on the calling endpoint
+                        * to initiate T.38 re-INVITEs, send T.38 negotiation request to called endpoint */
+                       if (state_active == T38_STATE_UNKNOWN) {
+                               ast_debug(1, "sending T.38 negotiation request to %s\n", ast_channel_name(active));
+                               if (active == chan) {
+                                       ast_channel_unlock(chan);
+                               }
+                               ast_write(active, fp);
+                               if (active == chan) {
+                                       ast_channel_lock(chan);
+                               }
+                       }
+                       if (state_other == T38_STATE_UNKNOWN) {
+                               ast_debug(1, "sending T.38 negotiation request to %s\n", ast_channel_name(other));
+                               return fp;
+                       }
                } else {
-                       ast_debug(1, "detected v21 preamble on %s, but %s does not support T.38 for T.38 gateway session\n", ast_channel_name(active), ast_channel_name(other));
+                       ast_debug(1, "neither %s nor %s support T.38 for T.38 gateway session\n", ast_channel_name(active), ast_channel_name(other));
                }
        }
 
@@ -3190,7 +3216,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str
                ast_channel_lock(chan);
                if (state_other == T38_STATE_UNKNOWN) {
                        gateway->t38_state = T38_STATE_UNAVAILABLE;
-               } else {
+               } else if (state_other != T38_STATE_NEGOTIATING) {
                        ast_framehook_detach(chan, details->gateway_id);
                        details->gateway_id = -1;