<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/17657">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">bundled_pjproject: Add more support for multipart bodies<br><br>Adding upstream patch for pull request...<br>https://github.com/pjsip/pjproject/pull/2920<br>---------------------------------------------------------------<br><br>sip_inv: Additional multipart support (#2919)<br><br>sip_inv.c:inv_check_sdp_in_incoming_msg() deals with multipart<br>message bodies in rdata correctly. In the case where early media is<br>involved though, the existing sdp has to be retrieved from the last<br>tdata sent in this transaction. This, however, always assumes that<br>the sdp sent is in a non-multipart body. While there's a function<br>to retrieve the sdp from multipart and non-multpart rdata bodies,<br>no similar function for tdata exists. So...<br><br>* The existing pjsip_rdata_get_sdp_info2 was refactored to<br> find the sdp in any body, multipart or non-multipart, and<br> from either an rdata or tdata. The new function is<br> pjsip_get_sdp_info. This new function detects whether the<br> pjsip_msg->body->data is the text representation of the sdp<br> from an rdata or an existing pjmedia_sdp_session object<br> from a tdata, or whether pjsip_msg->body is a multipart<br> body containing either of the two sdp formats.<br><br>* The exsting pjsip_rdata_get_sdp_info and pjsip_rdata_get_sdp_info2<br> functions are now wrappers that get the body and Content-Type<br> header from the rdata and call pjsip_get_sdp_info.<br><br>* Two new wrappers named pjsip_tdata_get_sdp_info and<br> pjsip_tdata_get_sdp_info2 have been created that get the body<br> from the tdata and call pjsip_get_sdp_info.<br><br>* For testing purposes, a new field "create_multipart" was added<br> to the pjsip_inv_session structure to allow forcing all bodies<br> created to be multipart.<br><br>* The internal create_sdp_body function now takes an option to<br> indicate that a multipart body should be created.<br><br>* inv_offer_answer_test.c was updated to use the create_multipart<br> field and additional tests were added.<br><br>ASTERISK-29804<br><br>Change-Id: I483c7c3d413280c9e247a96ad581278347f9c71b<br>---<br>A third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919.patch<br>1 file changed, 692 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/57/17657/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919.patch b/third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919.patch</span><br><span>new file mode 100644</span><br><span>index 0000000..615aba6</span><br><span>--- /dev/null</span><br><span>+++ b/third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919.patch</span><br><span>@@ -0,0 +1,692 @@</span><br><span style="color: hsl(120, 100%, 40%);">+From eb3cf4921caf095f82411be93223fe999ff70486 Mon Sep 17 00:00:00 2001</span><br><span style="color: hsl(120, 100%, 40%);">+From: George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+Date: Mon, 13 Dec 2021 08:24:35 -0700</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: [PATCH] sip_inv: Additional multipart support (#2919)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+sip_inv.c:inv_check_sdp_in_incoming_msg() deals with multipart</span><br><span style="color: hsl(120, 100%, 40%);">+message bodies in rdata correctly. In the case where early media is</span><br><span style="color: hsl(120, 100%, 40%);">+involved though, the existing sdp has to be retrieved from the last</span><br><span style="color: hsl(120, 100%, 40%);">+tdata sent in this transaction. This, however, always assumes that</span><br><span style="color: hsl(120, 100%, 40%);">+the sdp sent is in a non-multipart body. While there's a function</span><br><span style="color: hsl(120, 100%, 40%);">+to retrieve the sdp from multipart and non-multpart rdata bodies,</span><br><span style="color: hsl(120, 100%, 40%);">+no similar function for tdata exists. So...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+* The existing pjsip_rdata_get_sdp_info2 was refactored to</span><br><span style="color: hsl(120, 100%, 40%);">+ find the sdp in any body, multipart or non-multipart, and</span><br><span style="color: hsl(120, 100%, 40%);">+ from either an rdata or tdata. The new function is</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_get_sdp_info. This new function detects whether the</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg->body->data is the text representation of the sdp</span><br><span style="color: hsl(120, 100%, 40%);">+ from an rdata or an existing pjmedia_sdp_session object</span><br><span style="color: hsl(120, 100%, 40%);">+ from a tdata, or whether pjsip_msg->body is a multipart</span><br><span style="color: hsl(120, 100%, 40%);">+ body containing either of the two sdp formats.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+* The exsting pjsip_rdata_get_sdp_info and pjsip_rdata_get_sdp_info2</span><br><span style="color: hsl(120, 100%, 40%);">+ functions are now wrappers that get the body and Content-Type</span><br><span style="color: hsl(120, 100%, 40%);">+ header from the rdata and call pjsip_get_sdp_info.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+* Two new wrappers named pjsip_tdata_get_sdp_info and</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tdata_get_sdp_info2 have been created that get the body</span><br><span style="color: hsl(120, 100%, 40%);">+ from the tdata and call pjsip_get_sdp_info.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+* For testing purposes, a new field "create_multipart" was added</span><br><span style="color: hsl(120, 100%, 40%);">+ to the pjsip_inv_session structure to allow forcing all bodies</span><br><span style="color: hsl(120, 100%, 40%);">+ created to be multipart.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+* The internal create_sdp_body function now takes an option to</span><br><span style="color: hsl(120, 100%, 40%);">+ indicate that a multipart body should be created.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+* inv_offer_answer_test.c was updated to use the create_multipart</span><br><span style="color: hsl(120, 100%, 40%);">+ field and additional tests were added.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Fixes #2919</span><br><span style="color: hsl(120, 100%, 40%);">+---</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip/include/pjsip-ua/sip_inv.h | 112 ++++++++++-</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip/src/pjsip-ua/sip_inv.c | 268 ++++++++++++++++++++-----</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip/src/test/inv_offer_answer_test.c | 48 ++++-</span><br><span style="color: hsl(120, 100%, 40%);">+ 3 files changed, 365 insertions(+), 63 deletions(-)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h</span><br><span style="color: hsl(120, 100%, 40%);">+index 14f2d23fa..d64a13eb8 100644</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/include/pjsip-ua/sip_inv.h</span><br><span>++++ b/pjsip/include/pjsip-ua/sip_inv.h</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -447,15 +447,19 @@ struct pjsip_inv_session</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_atomic_t *ref_cnt; /**< Reference counter. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_bool_t updated_sdp_answer; /**< SDP answer just been</span><br><span style="color: hsl(120, 100%, 40%);">+ updated? */</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_bool_t create_multipart; /**< Create multipart</span><br><span style="color: hsl(120, 100%, 40%);">++ bodies. Should be</span><br><span style="color: hsl(120, 100%, 40%);">++ used for testing</span><br><span style="color: hsl(120, 100%, 40%);">++ only. */</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">+- * This structure represents SDP information in a pjsip_rx_data. Application</span><br><span style="color: hsl(120, 100%, 40%);">+- * retrieve this information by calling #pjsip_rdata_get_sdp_info(). This</span><br><span style="color: hsl(120, 100%, 40%);">++ * This structure represents SDP information in a pjsip_(rx|tx)_data. Application</span><br><span style="color: hsl(120, 100%, 40%);">++ * retrieve this information by calling #pjsip_get_sdp_info(). This</span><br><span style="color: hsl(120, 100%, 40%);">+ * mechanism supports multipart message body.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+-typedef struct pjsip_rdata_sdp_info</span><br><span style="color: hsl(120, 100%, 40%);">++typedef struct pjsip_sdp_info</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Pointer and length of the text body in the incoming message. If</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -475,7 +479,15 @@ typedef struct pjsip_rdata_sdp_info</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjmedia_sdp_session *sdp;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+-} pjsip_rdata_sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++} pjsip_sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * For backwards compatibility and completemess,</span><br><span style="color: hsl(120, 100%, 40%);">++ * pjsip_rdata_sdp_info and pjsip_tdata_sdp_info</span><br><span style="color: hsl(120, 100%, 40%);">++ * are typedef'd to pjsip_sdp_info.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++typedef pjsip_sdp_info pjsip_rdata_sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++typedef pjsip_sdp_info pjsip_tdata_sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -1045,6 +1057,44 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_body(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjmedia_sdp_session *sdp,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg_body **p_body);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * This is a utility function to create a multipart body with the</span><br><span style="color: hsl(120, 100%, 40%);">++ * SIP body as the first part.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param pool Pool to allocate memory.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param sdp SDP session to be put in the SIP message body.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param p_body Pointer to receive SIP message body containing</span><br><span style="color: hsl(120, 100%, 40%);">++ * the SDP session.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @return PJ_SUCCESS on success.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pj_status_t) pjsip_create_multipart_sdp_body( pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjmedia_sdp_session *sdp,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_msg_body **p_body);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * Retrieve SDP information from a message body. Application should</span><br><span style="color: hsl(120, 100%, 40%);">++ * prefer to use this function rather than parsing the SDP manually since</span><br><span style="color: hsl(120, 100%, 40%);">++ * this function supports multipart message body.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * This function will only parse the SDP once, the first time it is called</span><br><span style="color: hsl(120, 100%, 40%);">++ * on the same message. Subsequent call on the same message will just pick</span><br><span style="color: hsl(120, 100%, 40%);">++ * up the already parsed SDP from the message.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param pool Pool to allocate memory.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param body The message body.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param msg_media_type From the rdata or tdata Content-Type header, if available.</span><br><span style="color: hsl(120, 100%, 40%);">++ * If NULL, the content_type from the body will be used.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param search_media_type The media type to search for.</span><br><span style="color: hsl(120, 100%, 40%);">++ * If NULL, "application/sdp" will be used.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @return The SDP info.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pjsip_sdp_info*) pjsip_get_sdp_info(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_msg_body *body,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type *msg_media_type,</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_media_type *search_media_type);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Retrieve SDP information from an incoming message. Application should</span><br><span style="color: hsl(120, 100%, 40%);">+ * prefer to use this function rather than parsing the SDP manually since</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -1061,6 +1111,60 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_body(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * Retrieve SDP information from an incoming message. Application should</span><br><span style="color: hsl(120, 100%, 40%);">++ * prefer to use this function rather than parsing the SDP manually since</span><br><span style="color: hsl(120, 100%, 40%);">++ * this function supports multipart message body.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * This function will only parse the SDP once, the first time it is called</span><br><span style="color: hsl(120, 100%, 40%);">++ * on the same message. Subsequent call on the same message will just pick</span><br><span style="color: hsl(120, 100%, 40%);">++ * up the already parsed SDP from the message.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param rdata The incoming message.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param search_media_type The SDP media type to search for.</span><br><span style="color: hsl(120, 100%, 40%);">++ * If NULL, "application/sdp" will be used.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @return The SDP info.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info2(</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_rx_data *rdata,</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_media_type *search_media_type);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * Retrieve SDP information from an outgoing message. Application should</span><br><span style="color: hsl(120, 100%, 40%);">++ * prefer to use this function rather than parsing the SDP manually since</span><br><span style="color: hsl(120, 100%, 40%);">++ * this function supports multipart message body.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * This function will only parse the SDP once, the first time it is called</span><br><span style="color: hsl(120, 100%, 40%);">++ * on the same message. Subsequent call on the same message will just pick</span><br><span style="color: hsl(120, 100%, 40%);">++ * up the already parsed SDP from the message.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param tdata The outgoing message.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @return The SDP info.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DECL(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info(pjsip_tx_data *tdata);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * Retrieve SDP information from an outgoing message. Application should</span><br><span style="color: hsl(120, 100%, 40%);">++ * prefer to use this function rather than parsing the SDP manually since</span><br><span style="color: hsl(120, 100%, 40%);">++ * this function supports multipart message body.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * This function will only parse the SDP once, the first time it is called</span><br><span style="color: hsl(120, 100%, 40%);">++ * on the same message. Subsequent call on the same message will just pick</span><br><span style="color: hsl(120, 100%, 40%);">++ * up the already parsed SDP from the message.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param tdata The outgoing message.</span><br><span style="color: hsl(120, 100%, 40%);">++ * @param search_media_type The SDP media type to search for.</span><br><span style="color: hsl(120, 100%, 40%);">++ * If NULL, "application/sdp" will be used.</span><br><span style="color: hsl(120, 100%, 40%);">++ *</span><br><span style="color: hsl(120, 100%, 40%);">++ * @return The SDP info.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DECL(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info2(</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_tx_data *tdata,</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_media_type *search_media_type);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_END_DECL</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">+diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c</span><br><span style="color: hsl(120, 100%, 40%);">+index ca225015b..2e9556065 100644</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/pjsip-ua/sip_inv.c</span><br><span>++++ b/pjsip/src/pjsip-ua/sip_inv.c</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -105,7 +105,8 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_rx_data *rdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );</span><br><span style="color: hsl(120, 100%, 40%);">+ static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">+- const pjmedia_sdp_session *c_sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjmedia_sdp_session *c_sdp,</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_bool_t multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ static pj_status_t process_answer( pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ int st_code,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata,</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -118,6 +119,8 @@ static pj_status_t handle_timer_response(pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ static pj_bool_t inv_check_secure_dlg(pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_event *e);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) = </span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ &inv_on_state_null,</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -946,66 +949,170 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,</span><br><span style="color: hsl(120, 100%, 40%);">+ return PJ_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+-PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pjsip_sdp_info*) pjsip_get_sdp_info(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_msg_body *body,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type *msg_media_type,</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_media_type *search_media_type)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_rdata_sdp_info *sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_msg_body *body = rdata->msg_info.msg->body;</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_media_type app_sdp;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_sdp_info *sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type search_type;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type multipart_mixed;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type multipart_alternative;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type *msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_status_t status;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info = (pjsip_rdata_sdp_info*)</span><br><span style="color: hsl(120, 100%, 40%);">+- rdata->endpt_info.mod_data[mod_inv.mod.id];</span><br><span style="color: hsl(120, 100%, 40%);">+- if (sdp_info)</span><br><span style="color: hsl(120, 100%, 40%);">+- return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info = PJ_POOL_ZALLOC_T(pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_sdp_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info = PJ_POOL_ZALLOC_T(rdata->tp_info.pool,</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_rdata_sdp_info);</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_ASSERT_RETURN(mod_inv.mod.id >= 0, sdp_info);</span><br><span style="color: hsl(120, 100%, 40%);">+- rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_media_type_init2(&app_sdp, "application", "sdp");</span><br><span style="color: hsl(120, 100%, 40%);">++ if (!body) {</span><br><span style="color: hsl(120, 100%, 40%);">++ return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- if (body && ctype_hdr &&</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_stricmp(&ctype_hdr->media.type, &app_sdp.type)==0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_stricmp(&ctype_hdr->media.subtype, &app_sdp.subtype)==0)</span><br><span style="color: hsl(120, 100%, 40%);">++ if (msg_media_type) {</span><br><span style="color: hsl(120, 100%, 40%);">++ msg_type = msg_media_type;</span><br><span style="color: hsl(120, 100%, 40%);">++ } else {</span><br><span style="color: hsl(120, 100%, 40%);">++ if (body->content_type.type.slen == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">++ return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ msg_type = &body->content_type;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ if (!search_media_type) {</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_init2(&search_type, "application", "sdp");</span><br><span style="color: hsl(120, 100%, 40%);">++ } else {</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_memcpy(&search_type, search_media_type, sizeof(search_type));</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_init2(&multipart_mixed, "multipart", "mixed");</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_init2(&multipart_alternative, "multipart", "alternative");</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ if (pjsip_media_type_cmp(msg_type, &search_type, PJ_FALSE) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->body.ptr = (char*)body->data;</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->body.slen = body->len;</span><br><span style="color: hsl(120, 100%, 40%);">+- } else if (body && ctype_hdr &&</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_stricmp2(&ctype_hdr->media.type, "multipart")==0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+- (pj_stricmp2(&ctype_hdr->media.subtype, "mixed")==0 ||</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_stricmp2(&ctype_hdr->media.subtype, "alternative")==0))</span><br><span style="color: hsl(120, 100%, 40%);">++ /*</span><br><span style="color: hsl(120, 100%, 40%);">++ * If the print_body function is print_sdp, we know that</span><br><span style="color: hsl(120, 100%, 40%);">++ * body->data is a pjmedia_sdp_session object and came from</span><br><span style="color: hsl(120, 100%, 40%);">++ * a tx_data. If not, it's the text representation of the</span><br><span style="color: hsl(120, 100%, 40%);">++ * sdp from an rx_data.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++ if (body->print_body == print_sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->sdp = body->data;</span><br><span style="color: hsl(120, 100%, 40%);">++ } else {</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->body.ptr = (char*)body->data;</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->body.slen = body->len;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ } else if (pjsip_media_type_cmp(&multipart_mixed, msg_type, PJ_FALSE) == 0 ||</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_cmp(&multipart_alternative, msg_type, PJ_FALSE) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_multipart_part *part;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_multipart_part *part;</span><br><span style="color: hsl(120, 100%, 40%);">++ part = pjsip_multipart_find_part(body, &search_type, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++ if (part) {</span><br><span style="color: hsl(120, 100%, 40%);">++ if (part->body->print_body == print_sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->sdp = part->body->data;</span><br><span style="color: hsl(120, 100%, 40%);">++ } else {</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->body.ptr = (char*)part->body->data;</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->body.slen = part->body->len;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- part = pjsip_multipart_find_part(body, &app_sdp, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+- if (part) {</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->body.ptr = (char*)part->body->data;</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->body.slen = part->body->len;</span><br><span style="color: hsl(120, 100%, 40%);">+- }</span><br><span style="color: hsl(120, 100%, 40%);">++ /*</span><br><span style="color: hsl(120, 100%, 40%);">++ * If the body was already a pjmedia_sdp_session, we can just</span><br><span style="color: hsl(120, 100%, 40%);">++ * return it. If not and there wasn't a text representation</span><br><span style="color: hsl(120, 100%, 40%);">++ * of the sdp either, we can also just return.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++ if (sdp_info->sdp || !sdp_info->body.ptr) {</span><br><span style="color: hsl(120, 100%, 40%);">++ return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- if (sdp_info->body.ptr) {</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_status_t status;</span><br><span style="color: hsl(120, 100%, 40%);">+- status = pjmedia_sdp_parse(rdata->tp_info.pool,</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->body.ptr,</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->body.slen,</span><br><span style="color: hsl(120, 100%, 40%);">+- &sdp_info->sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+- if (status == PJ_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+- status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE);</span><br><span style="color: hsl(120, 100%, 40%);">++ /*</span><br><span style="color: hsl(120, 100%, 40%);">++ * If the body was the text representation of teh SDP, we need</span><br><span style="color: hsl(120, 100%, 40%);">++ * to parse it to create a pjmedia_sdp_session object.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++ status = pjmedia_sdp_parse(pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->body.ptr,</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->body.slen,</span><br><span style="color: hsl(120, 100%, 40%);">++ &sdp_info->sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ if (status == PJ_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">++ status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- if (status != PJ_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->sdp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+- PJ_PERROR(1,(THIS_FILE, status,</span><br><span style="color: hsl(120, 100%, 40%);">+- "Error parsing/validating SDP body"));</span><br><span style="color: hsl(120, 100%, 40%);">+- }</span><br><span style="color: hsl(120, 100%, 40%);">++ if (status != PJ_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->sdp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_PERROR(1, (THIS_FILE, status,</span><br><span style="color: hsl(120, 100%, 40%);">++ "Error parsing/validating SDP body"));</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- sdp_info->sdp_err = status;</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info->sdp_err = status;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info2(</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_rx_data *rdata,</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_media_type *search_media_type)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type *msg_media_type = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_rdata_sdp_info *sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ if (rdata->endpt_info.mod_data[mod_inv.mod.id]) {</span><br><span style="color: hsl(120, 100%, 40%);">++ return (pjsip_rdata_sdp_info *)rdata->endpt_info.mod_data[mod_inv.mod.id];</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ /*</span><br><span style="color: hsl(120, 100%, 40%);">++ * rdata should have a Content-Type header at this point but we'll</span><br><span style="color: hsl(120, 100%, 40%);">++ * make sure.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++ if (rdata->msg_info.ctype) {</span><br><span style="color: hsl(120, 100%, 40%);">++ msg_media_type = &rdata->msg_info.ctype->media;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info = pjsip_get_sdp_info(rdata->tp_info.pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ rdata->msg_info.msg->body,</span><br><span style="color: hsl(120, 100%, 40%);">++ msg_media_type,</span><br><span style="color: hsl(120, 100%, 40%);">++ search_media_type);</span><br><span style="color: hsl(120, 100%, 40%);">++ rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ return pjsip_rdata_get_sdp_info2(rdata, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info2(</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_tx_data *tdata,</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_media_type *search_media_type)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_ctype_hdr *ctype_hdr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type *msg_media_type = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_tdata_sdp_info *sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ if (tdata->mod_data[mod_inv.mod.id]) {</span><br><span style="color: hsl(120, 100%, 40%);">++ return (pjsip_tdata_sdp_info *)tdata->mod_data[mod_inv.mod.id];</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ /*</span><br><span style="color: hsl(120, 100%, 40%);">++ * tdata won't usually have a Content-Type header at this point</span><br><span style="color: hsl(120, 100%, 40%);">++ * but we'll check just the same,</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++ ctype_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTENT_TYPE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++ if (ctype_hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">++ msg_media_type = &ctype_hdr->media;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_info = pjsip_get_sdp_info(tdata->pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->msg->body,</span><br><span style="color: hsl(120, 100%, 40%);">++ msg_media_type,</span><br><span style="color: hsl(120, 100%, 40%);">++ search_media_type);</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->mod_data[mod_inv.mod.id] = sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ return sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info(pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ return pjsip_tdata_get_sdp_info2(tdata, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Verify incoming INVITE request.</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -1730,15 +1837,64 @@ PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">+ return PJ_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++static pjsip_multipart_part* create_sdp_part(pj_pool_t *pool, pjmedia_sdp_session *sdp)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_multipart_part *sdp_part;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type media_type;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_init2(&media_type, "application", "sdp");</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_part = pjsip_multipart_create_part(pool);</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_ASSERT_RETURN(sdp_part != NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_ASSERT_RETURN(sdp_part->body != NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_cp(pool, &sdp_part->body->content_type, &media_type);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_part->body->data = sdp;</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_part->body->clone_data = clone_sdp;</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_part->body->print_body = print_sdp;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ return sdp_part;</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++PJ_DEF(pj_status_t) pjsip_create_multipart_sdp_body(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjmedia_sdp_session *sdp,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_msg_body **p_body)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type media_type;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_msg_body *multipart;</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_multipart_part *sdp_part;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_media_type_init2(&media_type, "multipart", "mixed");</span><br><span style="color: hsl(120, 100%, 40%);">++ multipart = pjsip_multipart_create(pool, &media_type, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_ASSERT_RETURN(multipart != NULL, PJ_ENOMEM);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ sdp_part = create_sdp_part(pool, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_ASSERT_RETURN(sdp_part != NULL, PJ_ENOMEM);</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_multipart_add_part(pool, multipart, sdp_part);</span><br><span style="color: hsl(120, 100%, 40%);">++ *p_body = multipart;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ return PJ_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,</span><br><span style="color: hsl(120, 100%, 40%);">+- const pjmedia_sdp_session *c_sdp)</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjmedia_sdp_session *c_sdp,</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_bool_t multipart)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg_body *body;</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_status_t status;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- status = pjsip_create_sdp_body(pool, </span><br><span style="color: hsl(120, 100%, 40%);">+- pjmedia_sdp_session_clone(pool, c_sdp),</span><br><span style="color: hsl(120, 100%, 40%);">+- &body);</span><br><span style="color: hsl(120, 100%, 40%);">++ if (multipart) {</span><br><span style="color: hsl(120, 100%, 40%);">++ status = pjsip_create_multipart_sdp_body(pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjmedia_sdp_session_clone(pool, c_sdp),</span><br><span style="color: hsl(120, 100%, 40%);">++ &body);</span><br><span style="color: hsl(120, 100%, 40%);">++ } else {</span><br><span style="color: hsl(120, 100%, 40%);">++ status = pjsip_create_sdp_body(pool,</span><br><span style="color: hsl(120, 100%, 40%);">++ pjmedia_sdp_session_clone(pool, c_sdp),</span><br><span style="color: hsl(120, 100%, 40%);">++ &body);</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ if (status != PJ_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -1877,7 +2033,7 @@ PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ goto on_return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+- tdata->msg->body = create_sdp_body(tdata->pool, offer);</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->msg->body = create_sdp_body(tdata->pool, offer, inv->create_multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add Allow header. */</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -2059,6 +2215,7 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ )</span><br><span style="color: hsl(120, 100%, 40%);">+ )</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_sdp_info *tdata_sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ const pjmedia_sdp_session *reoffer_sdp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_LOG(4,(inv->obj_name, "Received %s response "</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -2067,14 +2224,15 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ (st_code/10==18? "early" : "final" )));</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Retrieve original SDP offer from INVITE request */</span><br><span style="color: hsl(120, 100%, 40%);">+- reoffer_sdp = (const pjmedia_sdp_session*) </span><br><span style="color: hsl(120, 100%, 40%);">+- tsx->last_tx->msg->body->data;</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata_sdp_info = pjsip_tdata_get_sdp_info(tsx->last_tx);</span><br><span style="color: hsl(120, 100%, 40%);">++ reoffer_sdp = tdata_sdp_info->sdp;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Feed the original offer to negotiator */</span><br><span style="color: hsl(120, 100%, 40%);">+ status = pjmedia_sdp_neg_modify_local_offer2(inv->pool_prov, </span><br><span style="color: hsl(120, 100%, 40%);">+ inv->neg,</span><br><span style="color: hsl(120, 100%, 40%);">+ inv->sdp_neg_flags,</span><br><span style="color: hsl(120, 100%, 40%);">+ reoffer_sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status != PJ_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_LOG(1,(inv->obj_name, "Error updating local offer for "</span><br><span style="color: hsl(120, 100%, 40%);">+ "forked 2xx/18x response (err=%d)", status));</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -2289,7 +2447,7 @@ static pj_status_t process_answer( pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ * session.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+- tdata->msg->body = create_sdp_body(tdata->pool, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->msg->body = create_sdp_body(tdata->pool, sdp, inv->create_multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (inv->options & PJSIP_INV_REQUIRE_100REL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ tdata->msg->body = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -3178,7 +3336,7 @@ PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* See if we have pending SDP answer to send */</span><br><span style="color: hsl(120, 100%, 40%);">+ sdp = inv_has_pending_answer(inv, inv->invite_tsx);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+- inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp, inv->create_multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Keep this for subsequent response retransmission */</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -3547,7 +3705,7 @@ static void inv_respond_incoming_update(pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ const pjmedia_sdp_session *sdp;</span><br><span style="color: hsl(120, 100%, 40%);">+ status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status == PJ_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+- tdata->msg->body = create_sdp_body(tdata->pool, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->msg->body = create_sdp_body(tdata->pool, sdp, inv->create_multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -3713,7 +3871,7 @@ static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* See if we need to attach SDP answer on the PRACK request */</span><br><span style="color: hsl(120, 100%, 40%);">+ sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+- tdata->msg->body = create_sdp_body(tdata->pool, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->msg->body = create_sdp_body(tdata->pool, sdp, inv->create_multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send PRACK (must be using 100rel module!) */</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -5057,7 +5215,7 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ if (sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+- tdata->msg->body = create_sdp_body(tdata->pool, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">++ tdata->msg->body = create_sdp_body(tdata->pool, sdp, inv->create_multipart);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+diff --git a/pjsip/src/test/inv_offer_answer_test.c b/pjsip/src/test/inv_offer_answer_test.c</span><br><span style="color: hsl(120, 100%, 40%);">+index ad5fcd409..6b19f241e 100644</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/test/inv_offer_answer_test.c</span><br><span>++++ b/pjsip/src/test/inv_offer_answer_test.c</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -137,6 +137,7 @@ typedef struct inv_test_param_t</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_bool_t need_established;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned count;</span><br><span style="color: hsl(120, 100%, 40%);">+ oa_t oa[4];</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_bool_t multipart_body;</span><br><span style="color: hsl(120, 100%, 40%);">+ } inv_test_param_t;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ typedef struct inv_test_t</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -321,6 +322,7 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata)</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_assert(!"Invalid offerer type");</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas);</span><br><span style="color: hsl(120, 100%, 40%);">++ inv_test.uas->create_multipart = inv_test.param.multipart_body;</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_assert(status == PJ_SUCCESS);</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_dlg_dec_lock(dlg);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+@@ -426,6 +428,7 @@ static int perform_test(inv_test_param_t *param)</span><br><span style="color: hsl(120, 100%, 40%);">+ sdp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac);</span><br><span style="color: hsl(120, 100%, 40%);">++ inv_test.uac->create_multipart = param->multipart_body;</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without")));</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -555,7 +558,8 @@ static inv_test_param_t test_params[] =</span><br><span style="color: hsl(120, 100%, 40%);">+ 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">+ 1,</span><br><span style="color: hsl(120, 100%, 40%);">+- { OFFERER_UAS }</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAS },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -563,7 +567,25 @@ static inv_test_param_t test_params[] =</span><br><span style="color: hsl(120, 100%, 40%);">+ PJSIP_INV_REQUIRE_100REL,</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">+ 1,</span><br><span style="color: hsl(120, 100%, 40%);">+- { OFFERER_UAS }</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAS },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_FALSE</span><br><span style="color: hsl(120, 100%, 40%);">++ },</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ "INVITE with no offer Multipart",</span><br><span style="color: hsl(120, 100%, 40%);">++ 0,</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">++ 1,</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAS },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE</span><br><span style="color: hsl(120, 100%, 40%);">++ },</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ "INVITE with no offer, with 100rel Multipart",</span><br><span style="color: hsl(120, 100%, 40%);">++ PJSIP_INV_REQUIRE_100REL,</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">++ 1,</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAS },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ #endif</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+@@ -584,14 +606,24 @@ static inv_test_param_t test_params[] =</span><br><span style="color: hsl(120, 100%, 40%);">+ 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">+ 2,</span><br><span style="color: hsl(120, 100%, 40%);">+- { OFFERER_UAC, OFFERER_UAC }</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAC, OFFERER_UAC },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_FALSE</span><br><span style="color: hsl(120, 100%, 40%);">++ },</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ "INVITE and UPDATE by UAC Multipart",</span><br><span style="color: hsl(120, 100%, 40%);">++ 0,</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">++ 2,</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAC, OFFERER_UAC },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ "INVITE and UPDATE by UAC, with 100rel",</span><br><span style="color: hsl(120, 100%, 40%);">+ PJSIP_INV_REQUIRE_100REL,</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">+ 2,</span><br><span style="color: hsl(120, 100%, 40%);">+- { OFFERER_UAC, OFFERER_UAC }</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAC, OFFERER_UAC },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ #endif</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+@@ -617,6 +649,14 @@ static inv_test_param_t test_params[] =</span><br><span style="color: hsl(120, 100%, 40%);">+ 4,</span><br><span style="color: hsl(120, 100%, 40%);">+ { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS }</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ "INVITE and many UPDATE by UAC and UAS Multipart",</span><br><span style="color: hsl(120, 100%, 40%);">++ 0,</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE,</span><br><span style="color: hsl(120, 100%, 40%);">++ 4,</span><br><span style="color: hsl(120, 100%, 40%);">++ { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS },</span><br><span style="color: hsl(120, 100%, 40%);">++ PJ_TRUE</span><br><span style="color: hsl(120, 100%, 40%);">++ },</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+-- </span><br><span style="color: hsl(120, 100%, 40%);">+2.33.1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/17657">change 17657</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/17657"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: I483c7c3d413280c9e247a96ad581278347f9c71b </div>
<div style="display:none"> Gerrit-Change-Number: 17657 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>