654 lines
20 KiB
Diff
654 lines
20 KiB
Diff
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
|
|
+ },
|
|
|
|
};
|
|
|