res_pjsip_session: Add ability to accept multiple sdp answers
[asterisk/asterisk.git] / third-party / pjproject / patches / 0100-sip_inv-Add-option-to-accept-updated-SDP-on-same-To-.patch
1 From 13e20772cd3c8735a6b78e30391a33f3eba4c023 Mon Sep 17 00:00:00 2001
2 From: George Joseph <gjoseph@digium.com>
3 Date: Fri, 22 Jun 2018 09:33:34 -0600
4 Subject: [PATCH] sip_inv:  Add option to accept updated SDP on same To tag
5
6 Currently, setting pjsip_cfg()->endpt.follow_early_media_fork allows
7 sip_inv to process media updates when the To tag is different.  There
8 are some cases where media updates need to be processed when the tags
9 are the same.  Since removing the requirement for different tags would
10 change default behavior, a new option "accept_multiple_sdp_answers"
11 has been added along with a new pjsip_inv_session flag
12 "updated_sdp_answer" to indicate under which condition we're
13 updating.
14
15 The logic was also updated to more closely follow RFC6337 in that
16 if 100rel is efffect, do not accept updated SDPs.
17
18 See
19 https://tools.ietf.org/html/rfc6337#section-3.1.1
20 for more information.
21 ---
22  pjsip/include/pjsip-ua/sip_inv.h |  2 ++
23  pjsip/include/pjsip/sip_config.h | 25 ++++++++++++++++
24  pjsip/src/pjsip-ua/sip_inv.c     | 62 +++++++++++++++++++++++++---------------
25  pjsip/src/pjsip/sip_config.c     |  3 +-
26  4 files changed, 68 insertions(+), 24 deletions(-)
27
28 diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
29 index 1bb7b8adc..77ef070c3 100644
30 --- a/pjsip/include/pjsip-ua/sip_inv.h
31 +++ b/pjsip/include/pjsip-ua/sip_inv.h
32 @@ -442,6 +442,8 @@ struct pjsip_inv_session
33      pj_bool_t           following_fork;            /**< Internal, following
34                                                          forked media?      */
35      pj_atomic_t                *ref_cnt;                   /**< Reference counter. */
36 +    pj_bool_t            updated_sdp_answer;        /**< SDP answer just been
37 +                                                        updated?           */
38  };
39  
40  
41 diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
42 index b3a9468e2..b7cf6feed 100644
43 --- a/pjsip/include/pjsip/sip_config.h
44 +++ b/pjsip/include/pjsip/sip_config.h
45 @@ -157,6 +157,17 @@ typedef struct pjsip_cfg_t
46          */
47         pj_bool_t disable_secure_dlg_check;
48  
49 +        /**
50 +         * Accept multiple SDP answers on non-reliable 18X responses and the 2XX
51 +         * response when they are all received from the same source (same To tag).
52 +         *
53 +         * See also:
54 +         * https://tools.ietf.org/html/rfc6337#section-3.1.1
55 +         *
56 +         * Default is PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS.
57 +         */
58 +        pj_bool_t accept_multiple_sdp_answers;
59 +
60      } endpt;
61  
62      /** Transaction layer settings. */
63 @@ -402,6 +413,20 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
64  #endif
65  
66  
67 +/**
68 + * Accept multiple SDP answers on non-reliable 18X responses and the 2XX
69 + * response when they are all received from the same source (same To tag).
70 + *
71 + * This option can also be controlled at run-time by the
72 + * \a accept_multiple_sdp_answers setting in pjsip_cfg_t.
73 + *
74 + * Default is PJ_FALSE.
75 + */
76 +#ifndef PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS
77 +#   define PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS        PJ_TRUE
78 +#endif
79 +
80 +
81  /**
82   * Specify whether "alias" param should be added to the Via header
83   * in any outgoing request with connection oriented transport.
84 diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
85 index c9686a088..c22726bad 100644
86 --- a/pjsip/src/pjsip-ua/sip_inv.c
87 +++ b/pjsip/src/pjsip-ua/sip_inv.c
88 @@ -162,6 +162,7 @@ struct tsx_inv_data
89      pj_bool_t           retrying;  /* Resend (e.g. due to 401/407)         */
90      pj_str_t            done_tag;  /* To tag in RX response with answer    */
91      pj_bool_t           done_early;/* Negotiation was done for early med?  */
92 +    pj_bool_t           done_early_rel;/* Early med was realiable?         */
93      pj_bool_t           has_sdp;   /* Message with SDP?                    */
94  };
95  
96 @@ -2000,18 +2001,20 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
97  
98      /* Initialize info that we are following forked media */
99      inv->following_fork = PJ_FALSE;
100 +    inv->updated_sdp_answer = PJ_FALSE;
101  
102      /* MUST NOT do multiple SDP offer/answer in a single transaction,
103 -     * EXCEPT if:
104 -     * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
105 -     * - the previous negotiation was done on an early media (18x) and
106 -     *    this response is a final/2xx response, and
107 -     *  - the 2xx response has different To tag than the 18x response
108 -     *    (i.e. the request has forked).
109 +     * EXCEPT previous nego was in 18x (early media) and any of the following
110 +     * condition is met:
111 +     *  - Non-forking scenario:
112 +     *   - 'accept_multiple_sdp_answers' is set, and
113 +     *    - previous early response was not reliable (rfc6337 section 3.1.1).
114 +     *  - Forking scenario:
115 +     *    - This response has different To tag than the previous response, and
116 +     *    - This response is 18x/2xx (early or final). If this is 18x,
117 +     *      only do multiple SDP nego if 'follow_early_media_fork' is set.
118       *
119 -     * The exception above is to add a rudimentary support for early media
120 -     * forking (sample case: custom ringback). See this ticket for more
121 -     * info: http://trac.pjsip.org/repos/ticket/657
122 +     * See also ticket #657, #1644, #1764 for more info.
123       */
124      if (tsx_inv_data->sdp_done) {
125         pj_str_t res_tag;
126 @@ -2020,21 +2023,29 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
127         res_tag = rdata->msg_info.to->tag;
128         st_code = rdata->msg_info.msg->line.status.code;
129  
130 -       /* Allow final/early response after SDP has been negotiated in early
131 -        * media, IF this response is a final/early response with different
132 -        * tag.
133 -         * See ticket #1644 and #1764 for forked early media case.
134 -        */
135 -       if (tsx->role == PJSIP_ROLE_UAC &&
136 -           (st_code/100 == 2 ||
137 -            (st_code/10 == 18 /* st_code == 18x */
138 -              && pjsip_cfg()->endpt.follow_early_media_fork)) &&
139 -           tsx_inv_data->done_early &&
140 -           pj_stricmp(&tsx_inv_data->done_tag, &res_tag))
141 +       if (tsx->role == PJSIP_ROLE_UAC && tsx_inv_data->done_early &&
142 +              (
143 +                  /* Non-forking scenario */
144 +                  (
145 +                      !tsx_inv_data->done_early_rel &&
146 +                      (st_code/100 == 2 || st_code/10 == 18) &&
147 +                       pjsip_cfg()->endpt.accept_multiple_sdp_answers &&
148 +                      !pj_stricmp(&tsx_inv_data->done_tag, &res_tag)
149 +                  )
150 +                  ||
151 +                  /* Forking scenario */
152 +                  (
153 +                      (st_code/100 == 2 ||
154 +                          (st_code/10 == 18 &&
155 +                              pjsip_cfg()->endpt.follow_early_media_fork)) &&
156 +                      pj_stricmp(&tsx_inv_data->done_tag, &res_tag)
157 +                  )
158 +              )
159 +          )
160         {
161             const pjmedia_sdp_session *reoffer_sdp = NULL;
162  
163 -           PJ_LOG(4,(inv->obj_name, "Received forked %s response "
164 +           PJ_LOG(4,(inv->obj_name, "Received %s response "
165                       "after SDP negotiation has been done in early "
166                       "media. Renegotiating SDP..",
167                       (st_code/10==18? "early" : "final" )));
168 @@ -2054,7 +2065,9 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
169                 return status;
170             }
171  
172 -           inv->following_fork = PJ_TRUE;
173 +           inv->following_fork = !!pj_stricmp(&tsx_inv_data->done_tag,
174 +                                              &res_tag);
175 +           inv->updated_sdp_answer = PJ_TRUE;
176  
177         } else {
178  
179 @@ -2135,6 +2148,7 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
180                 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) 
181      {
182         int status_code;
183 +       pjsip_msg *msg = rdata->msg_info.msg;
184  
185         /* This is an answer. 
186          * Process and negotiate remote answer.
187 @@ -2161,8 +2175,10 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
188          */
189  
190         tsx_inv_data->sdp_done = 1;
191 -       status_code = rdata->msg_info.msg->line.status.code;
192 +       status_code = msg->line.status.code;
193         tsx_inv_data->done_early = (status_code/100==1);
194 +       tsx_inv_data->done_early_rel = tsx_inv_data->done_early &&
195 +                                      pjsip_100rel_is_reliable(rdata);
196         pj_strdup(tsx->pool, &tsx_inv_data->done_tag, 
197                   &rdata->msg_info.to->tag);
198  
199 diff --git a/pjsip/src/pjsip/sip_config.c b/pjsip/src/pjsip/sip_config.c
200 index 3576f351e..316824a00 100644
201 --- a/pjsip/src/pjsip/sip_config.c
202 +++ b/pjsip/src/pjsip/sip_config.c
203 @@ -34,7 +34,8 @@ pjsip_cfg_t pjsip_sip_cfg_var =
204         PJSIP_FOLLOW_EARLY_MEDIA_FORK,
205         PJSIP_REQ_HAS_VIA_ALIAS,
206         PJSIP_RESOLVE_HOSTNAME_TO_GET_INTERFACE,
207 -       0
208 +       0,
209 +       PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS
210      },
211  
212      /* Transaction settings */
213 -- 
214 2.14.4
215