Merge "chan_ooh323: fix h323 log file path"
[asterisk/asterisk.git] / res / res_pjsip_t38.c
index 7b7cd99..11804e2 100644 (file)
@@ -142,7 +142,8 @@ static void t38_change_state(struct ast_sip_session *session, struct ast_sip_ses
                new_state, old_state,
                session->channel ? ast_channel_name(session->channel) : "<gone>");
 
-       if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &state->timer)) {
+       if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
+               &state->timer, 0)) {
                ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n",
                        session->channel ? ast_channel_name(session->channel) : "<gone>");
                ao2_ref(session, -1);
@@ -248,10 +249,7 @@ static struct t38_state *t38_state_get_or_alloc(struct ast_sip_session *session)
        state = datastore->data;
 
        /* This will get bumped up before scheduling */
-       state->timer.user_data = session;
-       state->timer.cb = t38_automatic_reject_timer_cb;
-
-       datastore->data = state;
+       pj_timer_entry_init(&state->timer, 0, session, t38_automatic_reject_timer_cb);
 
        return state;
 }
@@ -297,18 +295,30 @@ static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_da
        struct t38_state *state;
        struct ast_sip_session_media *session_media = NULL;
 
-       if (status.code == 100) {
+       if (status.code / 100 <= 1) {
+               /* Ignore any non-final responses (1xx) */
+               return 0;
+       }
+
+       if (session->t38state != T38_LOCAL_REINVITE) {
+               /* Do nothing.  We have already processed a final response. */
+               ast_debug(3, "Received %d response to T.38 re-invite on '%s' but already had a final response (T.38 state:%d)\n",
+                       status.code,
+                       session->channel ? ast_channel_name(session->channel) : "unknown channel",
+                       session->t38state);
                return 0;
        }
 
        state = t38_state_get_or_alloc(session);
        if (!session->channel || !state) {
-               ast_log(LOG_WARNING, "Received response to T.38 re-invite on '%s' but state unavailable\n",
+               ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but state unavailable\n",
+                       status.code,
                        session->channel ? ast_channel_name(session->channel) : "unknown channel");
                return 0;
        }
 
-       if (status.code == 200) {
+       if (status.code / 100 == 2) {
+               /* Accept any 2xx response as successfully negotiated */
                int index;
 
                session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
@@ -506,21 +516,42 @@ static struct ast_frame *t38_framehook(struct ast_channel *chan, struct ast_fram
                return f;
        }
 
-       if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
+       if (f->frametype == AST_FRAME_CONTROL
+               && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
                if (channel->session->endpoint->media.t38.enabled) {
-                       struct t38_parameters_task_data *data = t38_parameters_task_data_alloc(channel->session, f);
-
-                       if (!data) {
-                               return f;
-                       }
+                       struct t38_parameters_task_data *data;
 
-                       if (ast_sip_push_task(channel->session->serializer, t38_interpret_parameters, data)) {
+                       data = t38_parameters_task_data_alloc(channel->session, f);
+                       if (data
+                               && ast_sip_push_task(channel->session->serializer,
+                                       t38_interpret_parameters, data)) {
                                ao2_ref(data, -1);
                        }
                } else {
-                       struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REFUSED, };
-                       ast_debug(2, "T.38 support not enabled, rejecting T.38 control packet\n");
-                       ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
+                       static const struct ast_control_t38_parameters rsp_refused = {
+                               .request_response = AST_T38_REFUSED,
+                       };
+                       static const struct ast_control_t38_parameters rsp_terminated = {
+                               .request_response = AST_T38_TERMINATED,
+                       };
+                       const struct ast_control_t38_parameters *parameters = f->data.ptr;
+
+                       switch (parameters->request_response) {
+                       case AST_T38_REQUEST_NEGOTIATE:
+                               ast_debug(2, "T.38 support not enabled on %s, refusing T.38 negotiation\n",
+                                       ast_channel_name(chan));
+                               ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS,
+                                       &rsp_refused, sizeof(rsp_refused));
+                               break;
+                       case AST_T38_REQUEST_TERMINATE:
+                               ast_debug(2, "T.38 support not enabled on %s, 'terminating' T.38 session\n",
+                                       ast_channel_name(chan));
+                               ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS,
+                                       &rsp_terminated, sizeof(rsp_terminated));
+                               break;
+                       default:
+                               break;
+                       }
                }
        }
 
@@ -748,17 +779,17 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
 
        if (!session->endpoint->media.t38.enabled) {
                ast_debug(3, "Declining; T.38 not enabled on session\n");
-               return -1;
+               return 0;
        }
 
        if (!(state = t38_state_get_or_alloc(session))) {
-               return -1;
+               return 0;
        }
 
        if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
                ast_debug(3, "Declining; T.38 state is rejected or declined\n");
                t38_change_state(session, session_media, state, T38_DISABLED);
-               return -1;
+               return 0;
        }
 
        ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
@@ -767,7 +798,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
        if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
                /* The provided host was actually invalid so we error out this negotiation */
                ast_debug(3, "Declining; provided host is invalid\n");
-               return -1;
+               return 0;
        }
 
        /* Check the address family to make sure it matches configured */
@@ -775,7 +806,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
                (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) {
                /* The address does not match configured */
                ast_debug(3, "Declining, provided host does not match configured address family\n");
-               return -1;
+               return 0;
        }
 
        return 1;
@@ -1023,18 +1054,13 @@ static int unload_module(void)
  */
 static int load_module(void)
 {
-       CHECK_PJSIP_SESSION_MODULE_LOADED();
-
        if (ast_check_ipv6()) {
                ast_sockaddr_parse(&address, "::", 0);
        } else {
                ast_sockaddr_parse(&address, "0.0.0.0", 0);
        }
 
-       if (ast_sip_session_register_supplement(&t38_supplement)) {
-               ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n");
-               goto end;
-       }
+       ast_sip_session_register_supplement(&t38_supplement);
 
        if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) {
                ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n");
@@ -1053,5 +1079,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Supp
        .load = load_module,
        .unload = unload_module,
        .load_pri = AST_MODPRI_CHANNEL_DRIVER,
-       .requires = "res_pjsip,res_pjsip_session",
+       .requires = "res_pjsip,res_pjsip_session,udptl",
 );