Merge pull request #793 from micmac1/ast-18.5.1-21.02
[feed/telephony.git] / libs / pjproject / patches / 0130-sip_inv-Additional-multipart-support-2919-2920.patch
diff --git a/libs/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch b/libs/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch
deleted file mode 100644 (file)
index 8db8aab..0000000
+++ /dev/null
@@ -1,653 +0,0 @@
-From 0ed41eb5fd0e4192e1b7dc374f819d17aef3e805 Mon Sep 17 00:00:00 2001
-From: George Joseph <gtjoseph@users.noreply.github.com>
-Date: Tue, 21 Dec 2021 19:32:22 -0700
-Subject: [PATCH] sip_inv:  Additional multipart support (#2919) (#2920)
-
----
- pjsip/include/pjsip-ua/sip_inv.h       | 108 ++++++++++-
- pjsip/src/pjsip-ua/sip_inv.c           | 240 ++++++++++++++++++++-----
- pjsip/src/test/inv_offer_answer_test.c | 103 ++++++++++-
- 3 files changed, 394 insertions(+), 57 deletions(-)
-
---- a/pjsip/include/pjsip-ua/sip_inv.h
-+++ b/pjsip/include/pjsip-ua/sip_inv.h
-@@ -451,11 +451,11 @@ struct pjsip_inv_session
- /**
-- * This structure represents SDP information in a pjsip_rx_data. Application
-- * retrieve this information by calling #pjsip_rdata_get_sdp_info(). This
-+ * This structure represents SDP information in a pjsip_(rx|tx)_data. Application
-+ * retrieve this information by calling #pjsip_get_sdp_info(). This
-  * mechanism supports multipart message body.
-  */
--typedef struct pjsip_rdata_sdp_info
-+typedef struct pjsip_sdp_info
- {
-     /**
-      * Pointer and length of the text body in the incoming message. If
-@@ -475,7 +475,15 @@ typedef struct pjsip_rdata_sdp_info
-      */
-     pjmedia_sdp_session *sdp;
--} pjsip_rdata_sdp_info;
-+} pjsip_sdp_info;
-+
-+/**
-+ * For backwards compatibility and completeness,
-+ * pjsip_rdata_sdp_info and pjsip_tdata_sdp_info
-+ * are typedef'd to pjsip_sdp_info.
-+ */
-+typedef pjsip_sdp_info pjsip_rdata_sdp_info;
-+typedef pjsip_sdp_info pjsip_tdata_sdp_info;
- /**
-@@ -1046,6 +1054,44 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_bo
-                                          pjsip_msg_body **p_body);
- /**
-+ * This is a utility function to create a multipart body with the
-+ * SIP body as the first part.
-+ *
-+ * @param pool                Pool to allocate memory.
-+ * @param sdp         SDP session to be put in the SIP message body.
-+ * @param p_body      Pointer to receive SIP message body containing
-+ *                    the SDP session.
-+ *
-+ * @return            PJ_SUCCESS on success.
-+ */
-+PJ_DECL(pj_status_t) pjsip_create_multipart_sdp_body( pj_pool_t *pool,
-+                                           pjmedia_sdp_session *sdp,
-+                                           pjsip_msg_body **p_body);
-+
-+/**
-+ * Retrieve SDP information from a message body. Application should
-+ * prefer to use this function rather than parsing the SDP manually since
-+ * this function supports multipart message body.
-+ *
-+ * This function will only parse the SDP once, the first time it is called
-+ * on the same message. Subsequent call on the same message will just pick
-+ * up the already parsed SDP from the message.
-+ *
-+ * @param pool               Pool to allocate memory.
-+ * @param body               The message body.
-+ * @param msg_media_type     From the rdata or tdata Content-Type header, if available.
-+ *                           If NULL, the content_type from the body will be used.
-+ * @param search_media_type  The media type to search for.
-+ *                           If NULL, "application/sdp" will be used.
-+ *
-+ * @return                   The SDP info.
-+ */
-+PJ_DECL(pjsip_sdp_info*) pjsip_get_sdp_info(pj_pool_t *pool,
-+                                         pjsip_msg_body *body,
-+                                         pjsip_media_type *msg_media_type,
-+                                         const pjsip_media_type *search_media_type);
-+
-+/**
-  * Retrieve SDP information from an incoming message. Application should
-  * prefer to use this function rather than parsing the SDP manually since
-  * this function supports multipart message body.
-@@ -1061,6 +1107,60 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_bo
- PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata);
-+/**
-+ * Retrieve SDP information from an incoming message. Application should
-+ * prefer to use this function rather than parsing the SDP manually since
-+ * this function supports multipart message body.
-+ *
-+ * This function will only parse the SDP once, the first time it is called
-+ * on the same message. Subsequent call on the same message will just pick
-+ * up the already parsed SDP from the message.
-+ *
-+ * @param rdata               The incoming message.
-+ * @param search_media_type   The SDP media type to search for.
-+ *                            If NULL, "application/sdp" will be used.
-+ *
-+ * @return                    The SDP info.
-+ */
-+PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info2(
-+                                          pjsip_rx_data *rdata,
-+                                          const pjsip_media_type *search_media_type);
-+
-+/**
-+ * Retrieve SDP information from an outgoing message. Application should
-+ * prefer to use this function rather than parsing the SDP manually since
-+ * this function supports multipart message body.
-+ *
-+ * This function will only parse the SDP once, the first time it is called
-+ * on the same message. Subsequent call on the same message will just pick
-+ * up the already parsed SDP from the message.
-+ *
-+ * @param tdata    The outgoing message.
-+ *
-+ * @return         The SDP info.
-+ */
-+PJ_DECL(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info(pjsip_tx_data *tdata);
-+
-+/**
-+ * Retrieve SDP information from an outgoing message. Application should
-+ * prefer to use this function rather than parsing the SDP manually since
-+ * this function supports multipart message body.
-+ *
-+ * This function will only parse the SDP once, the first time it is called
-+ * on the same message. Subsequent call on the same message will just pick
-+ * up the already parsed SDP from the message.
-+ *
-+ * @param tdata               The outgoing message.
-+ * @param search_media_type   The SDP media type to search for.
-+ *                            If NULL, "application/sdp" will be used.
-+ *
-+ * @return                    The SDP info.
-+ */
-+PJ_DECL(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info2(
-+                                          pjsip_tx_data *tdata,
-+                                          const pjsip_media_type *search_media_type);
-+
-+
- PJ_END_DECL
- /**
---- a/pjsip/src/pjsip-ua/sip_inv.c
-+++ b/pjsip/src/pjsip-ua/sip_inv.c
-@@ -118,6 +118,8 @@ static pj_status_t handle_timer_response
- static pj_bool_t inv_check_secure_dlg(pjsip_inv_session *inv,
-                                     pjsip_event *e);
-+static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len);
-+
- static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) = 
- {
-     &inv_on_state_null,
-@@ -956,66 +958,170 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac
-     return PJ_SUCCESS;
- }
--PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)
--{
--    pjsip_rdata_sdp_info *sdp_info;
--    pjsip_msg_body *body = rdata->msg_info.msg->body;
--    pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
--    pjsip_media_type app_sdp;
-+PJ_DEF(pjsip_sdp_info*) pjsip_get_sdp_info(pj_pool_t *pool,
-+                                           pjsip_msg_body *body,
-+                                           pjsip_media_type *msg_media_type,
-+                                           const pjsip_media_type *search_media_type)
-+{
-+    pjsip_sdp_info *sdp_info;
-+    pjsip_media_type search_type;
-+    pjsip_media_type multipart_mixed;
-+    pjsip_media_type multipart_alternative;
-+    pjsip_media_type *msg_type;
-+    pj_status_t status;
--    sdp_info = (pjsip_rdata_sdp_info*)
--             rdata->endpt_info.mod_data[mod_inv.mod.id];
--    if (sdp_info)
--      return sdp_info;
-+    sdp_info = PJ_POOL_ZALLOC_T(pool,
-+                                pjsip_sdp_info);
--    sdp_info = PJ_POOL_ZALLOC_T(rdata->tp_info.pool,
--                              pjsip_rdata_sdp_info);
-     PJ_ASSERT_RETURN(mod_inv.mod.id >= 0, sdp_info);
--    rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info;
--    pjsip_media_type_init2(&app_sdp, "application", "sdp");
-+    if (!body) {
-+        return sdp_info;
-+    }
--    if (body && ctype_hdr &&
--      pj_stricmp(&ctype_hdr->media.type, &app_sdp.type)==0 &&
--      pj_stricmp(&ctype_hdr->media.subtype, &app_sdp.subtype)==0)
-+    if (msg_media_type) {
-+      msg_type = msg_media_type;
-+    } else {
-+      if (body->content_type.type.slen == 0) {
-+          return sdp_info;
-+      }
-+      msg_type = &body->content_type;
-+    }
-+
-+    if (!search_media_type) {
-+        pjsip_media_type_init2(&search_type, "application", "sdp");
-+    } else {
-+        pj_memcpy(&search_type, search_media_type, sizeof(search_type));
-+    }
-+
-+    pjsip_media_type_init2(&multipart_mixed, "multipart", "mixed");
-+    pjsip_media_type_init2(&multipart_alternative, "multipart", "alternative");
-+
-+    if (pjsip_media_type_cmp(msg_type, &search_type, PJ_FALSE) == 0)
-     {
--      sdp_info->body.ptr = (char*)body->data;
--      sdp_info->body.slen = body->len;
--    } else if  (body && ctype_hdr &&
--              pj_stricmp2(&ctype_hdr->media.type, "multipart")==0 &&
--              (pj_stricmp2(&ctype_hdr->media.subtype, "mixed")==0 ||
--               pj_stricmp2(&ctype_hdr->media.subtype, "alternative")==0))
-+      /*
-+       * If the print_body function is print_sdp, we know that
-+       * body->data is a pjmedia_sdp_session object and came from
-+       * a tx_data.  If not, it's the text representation of the
-+       * sdp from an rx_data.
-+       */
-+        if (body->print_body == print_sdp) {
-+            sdp_info->sdp = body->data;
-+        } else {
-+            sdp_info->body.ptr = (char*)body->data;
-+            sdp_info->body.slen = body->len;
-+        }
-+    } else if (pjsip_media_type_cmp(&multipart_mixed, msg_type, PJ_FALSE) == 0 ||
-+      pjsip_media_type_cmp(&multipart_alternative, msg_type, PJ_FALSE) == 0)
-     {
--      pjsip_multipart_part *part;
-+        pjsip_multipart_part *part;
-+        part = pjsip_multipart_find_part(body, &search_type, NULL);
-+        if (part) {
-+            if (part->body->print_body == print_sdp) {
-+                sdp_info->sdp = part->body->data;
-+            } else {
-+                sdp_info->body.ptr = (char*)part->body->data;
-+                sdp_info->body.slen = part->body->len;
-+            }
-+        }
-+    }
--      part = pjsip_multipart_find_part(body, &app_sdp, NULL);
--      if (part) {
--          sdp_info->body.ptr = (char*)part->body->data;
--          sdp_info->body.slen = part->body->len;
--      }
-+    /*
-+     * If the body was already a pjmedia_sdp_session, we can just
-+     * return it.  If not and there wasn't a text representation
-+     * of the sdp either, we can also just return.
-+     */
-+    if (sdp_info->sdp || !sdp_info->body.ptr) {
-+      return sdp_info;
-     }
--    if (sdp_info->body.ptr) {
--      pj_status_t status;
--      status = pjmedia_sdp_parse(rdata->tp_info.pool,
--                                 sdp_info->body.ptr,
--                                 sdp_info->body.slen,
--                                 &sdp_info->sdp);
--      if (status == PJ_SUCCESS)
--          status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE);
-+    /*
-+     * If the body was the text representation of teh SDP, we need
-+     * to parse it to create a pjmedia_sdp_session object.
-+     */
-+    status = pjmedia_sdp_parse(pool,
-+                              sdp_info->body.ptr,
-+                              sdp_info->body.slen,
-+                              &sdp_info->sdp);
-+    if (status == PJ_SUCCESS)
-+      status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE);
--      if (status != PJ_SUCCESS) {
--          sdp_info->sdp = NULL;
--          PJ_PERROR(1,(THIS_FILE, status,
--                       "Error parsing/validating SDP body"));
--      }
-+    if (status != PJ_SUCCESS) {
-+      sdp_info->sdp = NULL;
-+      PJ_PERROR(1, (THIS_FILE, status,
-+          "Error parsing/validating SDP body"));
-+    }
-+
-+    sdp_info->sdp_err = status;
-+
-+    return sdp_info;
-+}
-+
-+PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info2(
-+                                            pjsip_rx_data *rdata,
-+                                            const pjsip_media_type *search_media_type)
-+{
-+    pjsip_media_type *msg_media_type = NULL;
-+    pjsip_rdata_sdp_info *sdp_info;
--      sdp_info->sdp_err = status;
-+    if (rdata->endpt_info.mod_data[mod_inv.mod.id]) {
-+      return (pjsip_rdata_sdp_info *)rdata->endpt_info.mod_data[mod_inv.mod.id];
-+    }
-+
-+    /*
-+     * rdata should have a Content-Type header at this point but we'll
-+     * make sure.
-+     */
-+    if (rdata->msg_info.ctype) {
-+      msg_media_type = &rdata->msg_info.ctype->media;
-     }
-+    sdp_info = pjsip_get_sdp_info(rdata->tp_info.pool,
-+                                 rdata->msg_info.msg->body,
-+                                 msg_media_type,
-+                                 search_media_type);
-+    rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info;
-     return sdp_info;
- }
-+PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)
-+{
-+    return pjsip_rdata_get_sdp_info2(rdata, NULL);
-+}
-+
-+PJ_DEF(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info2(
-+                                            pjsip_tx_data *tdata,
-+                                            const pjsip_media_type *search_media_type)
-+{
-+    pjsip_ctype_hdr *ctype_hdr = NULL;
-+    pjsip_media_type *msg_media_type = NULL;
-+    pjsip_tdata_sdp_info *sdp_info;
-+
-+    if (tdata->mod_data[mod_inv.mod.id]) {
-+      return (pjsip_tdata_sdp_info *)tdata->mod_data[mod_inv.mod.id];
-+    }
-+    /*
-+     * tdata won't usually have a Content-Type header at this point
-+     * but we'll check just the same,
-+     */
-+    ctype_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTENT_TYPE, NULL);
-+    if (ctype_hdr) {
-+      msg_media_type = &ctype_hdr->media;
-+    }
-+
-+    sdp_info = pjsip_get_sdp_info(tdata->pool,
-+                                 tdata->msg->body,
-+                                 msg_media_type,
-+                                 search_media_type);
-+    tdata->mod_data[mod_inv.mod.id] = sdp_info;
-+
-+    return sdp_info;
-+}
-+
-+PJ_DEF(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info(pjsip_tx_data *tdata)
-+{
-+    return pjsip_tdata_get_sdp_info2(tdata, NULL);
-+}
- /*
-  * Verify incoming INVITE request.
-@@ -1740,13 +1846,55 @@ PJ_DEF(pj_status_t) pjsip_create_sdp_bod
-     return PJ_SUCCESS;
- }
-+static pjsip_multipart_part* create_sdp_part(pj_pool_t *pool, pjmedia_sdp_session *sdp)
-+{
-+    pjsip_multipart_part *sdp_part;
-+    pjsip_media_type media_type;
-+
-+    pjsip_media_type_init2(&media_type, "application", "sdp");
-+
-+    sdp_part = pjsip_multipart_create_part(pool);
-+    PJ_ASSERT_RETURN(sdp_part != NULL, NULL);
-+
-+    sdp_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
-+    PJ_ASSERT_RETURN(sdp_part->body != NULL, NULL);
-+
-+    pjsip_media_type_cp(pool, &sdp_part->body->content_type, &media_type);
-+
-+    sdp_part->body->data = sdp;
-+    sdp_part->body->clone_data = clone_sdp;
-+    sdp_part->body->print_body = print_sdp;
-+
-+    return sdp_part;
-+}
-+
-+PJ_DEF(pj_status_t) pjsip_create_multipart_sdp_body(pj_pool_t *pool,
-+                                                   pjmedia_sdp_session *sdp,
-+                                                   pjsip_msg_body **p_body)
-+{
-+    pjsip_media_type media_type;
-+    pjsip_msg_body *multipart;
-+    pjsip_multipart_part *sdp_part;
-+
-+    pjsip_media_type_init2(&media_type, "multipart", "mixed");
-+    multipart = pjsip_multipart_create(pool, &media_type, NULL);
-+    PJ_ASSERT_RETURN(multipart != NULL, PJ_ENOMEM);
-+
-+    sdp_part = create_sdp_part(pool, sdp);
-+    PJ_ASSERT_RETURN(sdp_part != NULL, PJ_ENOMEM);
-+    pjsip_multipart_add_part(pool, multipart, sdp_part);
-+    *p_body = multipart;
-+
-+    return PJ_SUCCESS;
-+}
-+
- static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
-                                      const pjmedia_sdp_session *c_sdp)
- {
-     pjsip_msg_body *body;
-     pj_status_t status;
--    status = pjsip_create_sdp_body(pool, 
-+    status = pjsip_create_sdp_body(pool,
-                                  pjmedia_sdp_session_clone(pool, c_sdp),
-                                  &body);
-@@ -2069,6 +2217,7 @@ static pj_status_t inv_check_sdp_in_inco
-              )
-          )
-       {
-+          pjsip_sdp_info *tdata_sdp_info;
-           const pjmedia_sdp_session *reoffer_sdp = NULL;
-           PJ_LOG(4,(inv->obj_name, "Received %s response "
-@@ -2077,14 +2226,15 @@ static pj_status_t inv_check_sdp_in_inco
-                     (st_code/10==18? "early" : "final" )));
-           /* Retrieve original SDP offer from INVITE request */
--          reoffer_sdp = (const pjmedia_sdp_session*) 
--                        tsx->last_tx->msg->body->data;
-+          tdata_sdp_info = pjsip_tdata_get_sdp_info(tsx->last_tx);
-+          reoffer_sdp = tdata_sdp_info->sdp;
-           /* Feed the original offer to negotiator */
-           status = pjmedia_sdp_neg_modify_local_offer2(inv->pool_prov, 
-                                                        inv->neg,
-                                                          inv->sdp_neg_flags,
-                                                        reoffer_sdp);
-+
-           if (status != PJ_SUCCESS) {
-               PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
-                         "forked 2xx/18x response (err=%d)", status));
---- a/pjsip/src/test/inv_offer_answer_test.c
-+++ b/pjsip/src/test/inv_offer_answer_test.c
-@@ -137,6 +137,7 @@ typedef struct inv_test_param_t
-     pj_bool_t need_established;
-     unsigned  count;
-     oa_t      oa[4];
-+    pj_bool_t multipart_body;
- } inv_test_param_t;
- typedef struct inv_test_t
-@@ -257,6 +258,17 @@ static void on_media_update(pjsip_inv_se
-           }
-       }
-+      /* Special handling for standard offer/answer */
-+      if (inv_test.param.count == 1 &&
-+          inv_test.param.oa[0] == OFFERER_UAC &&
-+          inv_test.param.need_established)
-+      {
-+          jobs[job_cnt].type = ESTABLISH_CALL;
-+          jobs[job_cnt].who = PJSIP_ROLE_UAS;
-+          job_cnt++;
-+          TRACE_((THIS_FILE, "      C+++"));
-+      }
-+
-       pj_assert(job_cnt <= PJ_ARRAY_SIZE(jobs));
-     }
- }
-@@ -333,6 +345,15 @@ static pj_bool_t on_rx_request(pjsip_rx_
-                                         NULL, &tdata);
-       pj_assert(status == PJ_SUCCESS);
-+      /* Use multipart body, if configured */
-+      if (sdp && inv_test.param.multipart_body) {
-+           status = pjsip_create_multipart_sdp_body(
-+                              tdata->pool,
-+                              pjmedia_sdp_session_clone(tdata->pool, sdp),
-+                              &tdata->msg->body);
-+      }
-+      pj_assert(status == PJ_SUCCESS);
-+
-       status = pjsip_inv_send_msg(inv_test.uas, tdata);
-       pj_assert(status == PJ_SUCCESS);
-@@ -426,6 +447,7 @@ static int perform_test(inv_test_param_t
-       sdp = NULL;
-     status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac);
-+    //inv_test.uac->create_multipart = param->multipart_body;
-     PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20);
-     TRACE_((THIS_FILE, "    Sending INVITE %s offer", (sdp ? "with" : "without")));
-@@ -436,8 +458,17 @@ static int perform_test(inv_test_param_t
-     status = pjsip_inv_invite(inv_test.uac, &tdata);
-     PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30);
-+    /* Use multipart body, if configured */
-+    if (sdp && param->multipart_body) {
-+       status = pjsip_create_multipart_sdp_body(
-+                          tdata->pool,
-+                          pjmedia_sdp_session_clone(tdata->pool, sdp),
-+                          &tdata->msg->body);
-+    }
-+    PJ_ASSERT_RETURN(status==PJ_SUCCESS, -40);
-+
-     status = pjsip_inv_send_msg(inv_test.uac, tdata);
--    PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30);
-+    PJ_ASSERT_RETURN(status==PJ_SUCCESS, -50);
-     /*
-      * Wait until test completes
-@@ -525,13 +556,14 @@ static inv_test_param_t test_params[] =
-     200/INVITE (answer)       <--
-     ACK               -->
-  */
--#if 0
-+#if 1
-     {
-       "Standard INVITE with offer",
-       0,
-       PJ_TRUE,
-       1,
--      { OFFERER_UAC }
-+      { OFFERER_UAC },
-+      PJ_FALSE
-     },
-     {
-@@ -539,7 +571,25 @@ static inv_test_param_t test_params[] =
-       PJSIP_INV_REQUIRE_100REL,
-       PJ_TRUE,
-       1,
--      { OFFERER_UAC }
-+      { OFFERER_UAC },
-+      PJ_FALSE
-+    },
-+    {
-+      "Standard INVITE with offer, with Multipart",
-+      0,
-+      PJ_TRUE,
-+      1,
-+      { OFFERER_UAC },
-+      PJ_TRUE
-+    },
-+
-+    {
-+      "Standard INVITE with offer, with 100rel, with Multipart",
-+      PJSIP_INV_REQUIRE_100REL,
-+      PJ_TRUE,
-+      1,
-+      { OFFERER_UAC },
-+      PJ_TRUE
-     },
- #endif
-@@ -555,7 +605,8 @@ static inv_test_param_t test_params[] =
-       0,
-       PJ_TRUE,
-       1,
--      { OFFERER_UAS }
-+      { OFFERER_UAS },
-+      PJ_FALSE
-     },
-     {
-@@ -563,7 +614,25 @@ static inv_test_param_t test_params[] =
-       PJSIP_INV_REQUIRE_100REL,
-       PJ_TRUE,
-       1,
--      { OFFERER_UAS }
-+      { OFFERER_UAS },
-+      PJ_FALSE
-+    },
-+    {
-+      "INVITE with no offer, with Multipart",
-+      0,
-+      PJ_TRUE,
-+      1,
-+      { OFFERER_UAS },
-+      PJ_TRUE
-+    },
-+
-+    {
-+      "INVITE with no offer, with 100rel, with Multipart",
-+      PJSIP_INV_REQUIRE_100REL,
-+      PJ_TRUE,
-+      1,
-+      { OFFERER_UAS },
-+      PJ_TRUE
-     },
- #endif
-@@ -584,14 +653,24 @@ static inv_test_param_t test_params[] =
-       0,
-       PJ_TRUE,
-       2,
--      { OFFERER_UAC, OFFERER_UAC }
-+      { OFFERER_UAC, OFFERER_UAC },
-+      PJ_FALSE
-+    },
-+    {
-+      "INVITE and UPDATE by UAC, with Multipart",
-+      0,
-+      PJ_TRUE,
-+      2,
-+      { OFFERER_UAC, OFFERER_UAC },
-+      PJ_TRUE
-     },
-     {
-       "INVITE and UPDATE by UAC, with 100rel",
-       PJSIP_INV_REQUIRE_100REL,
-       PJ_TRUE,
-       2,
--      { OFFERER_UAC, OFFERER_UAC }
-+      { OFFERER_UAC, OFFERER_UAC },
-+      PJ_FALSE
-     },
- #endif
-@@ -617,6 +696,14 @@ static inv_test_param_t test_params[] =
-       4,
-       { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS }
-     },
-+    {
-+      "INVITE and many UPDATE by UAC and UAS, with Multipart",
-+      0,
-+      PJ_TRUE,
-+      4,
-+      { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS },
-+      PJ_TRUE
-+    },
- };