[Asterisk-code-review] pjproject: Update bundled to 2.12 release. (asterisk[master])

Friendly Automation asteriskteam at digium.com
Wed Mar 30 07:28:15 CDT 2022


Friendly Automation has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/18114 )

Change subject: pjproject: Update bundled to 2.12 release.
......................................................................

pjproject: Update bundled to 2.12 release.

This change removes patches which have been merged into
upstream and updates some existing ones. It also adds
some additional config_site.h changes to restore previous
behavior, as well as a patch to allow multiple Authorization
headers. There seems to be some confusion or disagreement
on language in RFC 8760 in regards to whether multiple
Authorization headers are supported. The RFC implies it
is allowed, as does some past sipcore discussion. There is
also the catch all of "local policy" to allow it. In
the case of Asterisk we allow it.

ASTERISK-29351

Change-Id: Id39ece02dedb7b9f739e0e37ea47d76854af7191
---
M third-party/pjproject/patches/0000-configure-ssl-library-path.patch
M third-party/pjproject/patches/0000-remove-third-party.patch
D third-party/pjproject/patches/0000-set_apps_initial_log_level.patch
D third-party/pjproject/patches/0000-solaris.patch
D third-party/pjproject/patches/0011-sip_inv_patch.patch
D third-party/pjproject/patches/0020-pjlib_cancel_timer_0.patch
D third-party/pjproject/patches/0050-fix-race-parallel-build.patch
D third-party/pjproject/patches/0060-clone-sdp-for-sip-timer-refresh-invite.patch
D third-party/pjproject/patches/0070-fix-incorrect-copying-when-creating-cancel.patch
D third-party/pjproject/patches/0080-fix-sdp-neg-modify-local-offer.patch
D third-party/pjproject/patches/0090-Skip-unsupported-digest-algorithm-2408.patch
A third-party/pjproject/patches/0100-allow_multiple_auth_headers.patch
D third-party/pjproject/patches/0100-fix-double-stun-free.patch
D third-party/pjproject/patches/0110-tls-parent-listener-destroyed.patch
D third-party/pjproject/patches/0111-ssl-premature-destroy.patch
D third-party/pjproject/patches/0120-pjmedia_sdp_attr_get_rtpmap-Strip-param-trailing-whi.patch
D third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch
D third-party/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch
D third-party/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch
D third-party/pjproject/patches/0160-Additional-multipart-improvements.patch
M third-party/pjproject/patches/config_site.h
D third-party/pjproject/pjproject-2.10.tar.bz2.md5
A third-party/pjproject/pjproject-2.12.tar.bz2.md5
M third-party/versions.mak
24 files changed, 444 insertions(+), 2,708 deletions(-)

Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved
  Friendly Automation: Approved for Submit



diff --git a/third-party/pjproject/patches/0000-configure-ssl-library-path.patch b/third-party/pjproject/patches/0000-configure-ssl-library-path.patch
index 3c1f749..c4dbb49 100644
--- a/third-party/pjproject/patches/0000-configure-ssl-library-path.patch
+++ b/third-party/pjproject/patches/0000-configure-ssl-library-path.patch
@@ -1,19 +1,9 @@
-From e8000cc80e5f8ba02cc52852edc02cdb0e949525 Mon Sep 17 00:00:00 2001
-From: Richard Mudgett <rmudgett at digium.com>
-Date: Mon, 6 Aug 2018 11:24:25 -0500
-Subject: [PATCH 1/5] 0000-configure-ssl-library-path.patch
-
----
- aconfigure    | 6 +++++-
- aconfigure.ac | 6 +++++-
- 2 files changed, 10 insertions(+), 2 deletions(-)
-
 diff --git a/aconfigure b/aconfigure
-index 1c449b8..c4c6060 100755
+index d6f0e8809..9dcd46398 100755
 --- a/aconfigure
 +++ b/aconfigure
-@@ -7954,7 +7954,11 @@ else
-                 if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
+@@ -8986,7 +8986,11 @@ else $as_nop
+ 	        if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
                      CFLAGS="$CFLAGS -I$with_ssl/include"
                      CPPFLAGS="$CPPFLAGS -I$with_ssl/include"
 -                    LDFLAGS="$LDFLAGS -L$with_ssl/lib"
@@ -22,15 +12,15 @@
 +                    else
 +                        LDFLAGS="$LDFLAGS -L$with_ssl"
 +                    fi
-                     { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSL prefix... $with_ssl" >&5
- $as_echo "Using SSL prefix... $with_ssl" >&6; }
+                     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using SSL prefix... $with_ssl" >&5
+ printf "%s\n" "Using SSL prefix... $with_ssl" >&6; }
                  fi
 diff --git a/aconfigure.ac b/aconfigure.ac
-index 2c272cd..a5d6d97 100644
+index 16b311045..849da81ab 100644
 --- a/aconfigure.ac
 +++ b/aconfigure.ac
-@@ -1580,7 +1580,11 @@ AC_ARG_ENABLE(ssl,
-                 if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
+@@ -1838,7 +1838,11 @@ AC_ARG_ENABLE(ssl,
+ 	        if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
                      CFLAGS="$CFLAGS -I$with_ssl/include"
                      CPPFLAGS="$CPPFLAGS -I$with_ssl/include"
 -                    LDFLAGS="$LDFLAGS -L$with_ssl/lib"
@@ -42,6 +32,3 @@
                      AC_MSG_RESULT([Using SSL prefix... $with_ssl])
                  fi
  
--- 
-2.7.4
-
diff --git a/third-party/pjproject/patches/0000-remove-third-party.patch b/third-party/pjproject/patches/0000-remove-third-party.patch
index f25aeac..1de154d 100644
--- a/third-party/pjproject/patches/0000-remove-third-party.patch
+++ b/third-party/pjproject/patches/0000-remove-third-party.patch
@@ -1,14 +1,5 @@
-From 665a2fbc3a09a71cd77988ae2deb3f5d3e205f63 Mon Sep 17 00:00:00 2001
-From: Richard Mudgett <rmudgett at digium.com>
-Date: Thu, 23 Feb 2017 17:10:07 -0600
-Subject: [PATCH 2/5] 0000-remove-third-party.patch
-
----
- build.mak.in | 97 ------------------------------------------------------------
- 1 file changed, 97 deletions(-)
-
 diff --git a/build.mak.in b/build.mak.in
-index 80ccad1..41ec64e 100644
+index 4bc464f8c..80681d961 100644
 --- a/build.mak.in
 +++ b/build.mak.in
 @@ -1,4 +1,3 @@
@@ -16,7 +7,7 @@
  include $(PJDIR)/version.mak
  export PJ_DIR := $(PJDIR)
  
-@@ -37,19 +36,6 @@ export APP_THIRD_PARTY_EXT :=
+@@ -41,19 +40,6 @@ export APP_THIRD_PARTY_EXT :=
  export APP_THIRD_PARTY_LIBS :=
  export APP_THIRD_PARTY_LIB_FILES :=
  
@@ -36,7 +27,7 @@
  ifeq (@ac_pjmedia_resample@,libresample)
  APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX)
  ifeq ($(PJ_SHARED_LIBRARIES),)
-@@ -66,89 +52,6 @@ APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFI
+@@ -70,102 +56,6 @@ APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFI
  endif
  endif
  
@@ -122,10 +113,20 @@
 -endif
 -endif
 -
+-ifneq (@ac_no_webrtc_aec3@,1)
+-ifeq (@ac_external_webrtc_aec3@,1)
+-APP_THIRD_PARTY_EXT += -lwebrtc-aec3
+-else
+-APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libwebrtc-aec3-$(LIB_SUFFIX)
+-ifeq ($(PJ_SHARED_LIBRARIES),)
+-APP_THIRD_PARTY_LIBS += -lwebrtc-aec3-$(TARGET_NAME)
+-else
+-APP_THIRD_PARTY_LIBS += -lwebrtc-aec3
+-APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libwebrtc-aec3.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libwebrtc.$(SHLIB_SUFFIX)
+-endif
+-endif
+-endif
 -
+
  # Additional flags
  @ac_build_mak_vars@
- 
--- 
-2.7.4
-
diff --git a/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch
deleted file mode 100644
index b1fe02c..0000000
--- a/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From c40ad6ba454fdf6456d8ffa92faa4cd49f2c807d Mon Sep 17 00:00:00 2001
-From: Richard Mudgett <rmudgett at digium.com>
-Date: Thu, 23 Feb 2017 17:11:00 -0600
-Subject: [PATCH 3/5] 0000-set_apps_initial_log_level.patch
-
----
- pjsip-apps/src/pjsua/main.c             | 2 ++
- pjsip-apps/src/pjsystest/main_console.c | 2 ++
- pjsip-apps/src/python/_pjsua.c          | 3 ++-
- 3 files changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/pjsip-apps/src/pjsua/main.c b/pjsip-apps/src/pjsua/main.c
-index 2baaf82..11831f2 100644
---- a/pjsip-apps/src/pjsua/main.c
-+++ b/pjsip-apps/src/pjsua/main.c
-@@ -126,5 +126,7 @@ int main_func(int argc, char *argv[])
- 
- int main(int argc, char *argv[])
- {
-+    pj_log_set_level(1);
-+
-     return pj_run_app(&main_func, argc, argv, 0);
- }
-diff --git a/pjsip-apps/src/pjsystest/main_console.c b/pjsip-apps/src/pjsystest/main_console.c
-index 122cdc7..dc79eab 100644
---- a/pjsip-apps/src/pjsystest/main_console.c
-+++ b/pjsip-apps/src/pjsystest/main_console.c
-@@ -133,6 +133,8 @@ void gui_sleep(unsigned sec)
- 
- int main()
- {
-+    pj_log_set_level(1);
-+
-     if (systest_init() != PJ_SUCCESS)
- 	return 1;
- 
-diff --git a/pjsip-apps/src/python/_pjsua.c b/pjsip-apps/src/python/_pjsua.c
-index 31b835e..3e15030 100644
---- a/pjsip-apps/src/python/_pjsua.c
-+++ b/pjsip-apps/src/python/_pjsua.c
-@@ -4434,7 +4434,8 @@ init_pjsua(void)
-     PyObject* m = NULL;
- #define ADD_CONSTANT(mod,name)	PyModule_AddIntConstant(mod,#name,name)
- 
--    
-+    pj_log_set_level(1);
-+
-     PyEval_InitThreads();
- 
-     if (PyType_Ready(&PyTyp_pjsua_callback) < 0)
--- 
-2.7.4
-
diff --git a/third-party/pjproject/patches/0000-solaris.patch b/third-party/pjproject/patches/0000-solaris.patch
deleted file mode 100644
index 155cdbe..0000000
--- a/third-party/pjproject/patches/0000-solaris.patch
+++ /dev/null
@@ -1,135 +0,0 @@
-From 1ac599a0f29500a15faf0dbbdc2565cc7dce2420 Mon Sep 17 00:00:00 2001
-From: Shaun Ruffell <sruffell at digium.com>
-Date: Fri, 7 Sep 2012 14:31:19 -0500
-Subject: [PATCH 4/5] pjproject: Fix for Solaris builds. Do not undef s_addr.
-
-pjproject, in order to solve build problems on Windows [1], undefines s_addr in
-one of it's headers that is included in res_rtp_asterisk.c. On Solaris s_addr is
-not a structure member, but defined to map to the real strucuture member,
-therefore when building on Solaris it's possible to get build errors like:
-
-    [CC] res_rtp_asterisk.c -> res_rtp_asterisk.o
-    In file included from /export/home/admin/asterisk-11-svn/include/asterisk/stun.h:29,
-                     from res_rtp_asterisk.c:51:
-    /export/home/admin/asterisk-11-svn/include/asterisk/network.h: In function `inaddrcmp':
-    /export/home/admin/asterisk-11-svn/include/asterisk/network.h:92: error: structure has no member named `s_addr'
-    /export/home/admin/asterisk-11-svn/include/asterisk/network.h:92: error: structure has no member named `s_addr'
-    res_rtp_asterisk.c: In function `ast_rtp_on_ice_tx_pkt':
-    res_rtp_asterisk.c:706: warning: dereferencing type-punned pointer will break strict-aliasing rules
-    res_rtp_asterisk.c:710: warning: dereferencing type-punned pointer will break strict-aliasing rules
-    res_rtp_asterisk.c: In function `rtp_add_candidates_to_ice':
-    res_rtp_asterisk.c:1085: error: structure has no member named `s_addr'
-    make[2]: *** [res_rtp_asterisk.o] Error 1
-    make[1]: *** [res] Error 2
-    make[1]: Leaving directory `/export/home/admin/asterisk-11-svn'
-    gmake: *** [_cleantest_all] Error 2
-
-Unfortunately, in order to make this work, I also had to make sure pjproject
-only used the typdef pj_in_addr and not the struct pj_in_addr so that when
-building Asterisk I could "typedef struct in_addr pj_in_addr". It's possible
-then that the library and users of those interfaces in Asterisk have a different
-idea about the type of the argument. While on the surface it looks like they are
-all 32 bit big endian values.
-
-[1] http://trac.pjsip.org/repos/changeset/484
-
-Reported-by: Ben Klang
-(issues ASTERISK-20366)
-
-Updated by ASTERISK-27997
----
- pjlib/include/pj/sock.h         | 8 +++++++-
- pjlib/src/pj/sock_bsd.c         | 2 +-
- pjlib/src/pj/sock_symbian.cpp   | 2 +-
- pjlib/src/pj/sock_uwp.cpp       | 2 +-
- pjsip/src/test/transport_test.c | 2 +-
- 5 files changed, 11 insertions(+), 5 deletions(-)
-
-diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
-index 4daf298..c35833c 100644
---- a/pjlib/include/pj/sock.h
-+++ b/pjlib/include/pj/sock.h
-@@ -484,6 +484,7 @@ typedef enum pj_socket_sd_type
-  */
- #define PJ_INVALID_SOCKET   (-1)
- 
-+#ifndef _ASTERISK_H
- /* Must undefine s_addr because of pj_in_addr below */
- #undef s_addr
- 
-@@ -495,6 +496,11 @@ typedef struct pj_in_addr
-     pj_uint32_t	s_addr;		/**< The 32bit IP address.	    */
- } pj_in_addr;
- 
-+#else
-+#include <sys/types.h>
-+#include <netinet/in.h>
-+typedef struct in_addr pj_in_addr;
-+#endif
- 
- /**
-  * Maximum length of text representation of an IPv4 address.
-@@ -712,7 +718,7 @@ PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr);
-  *
-  * @return	nonzero if the address is valid, zero if not.
-  */
--PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp);
-+PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp);
- 
- /**
-  * This function converts an address in its standard text presentation form
-diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
-index e416991..940fce1 100644
---- a/pjlib/src/pj/sock_bsd.c
-+++ b/pjlib/src/pj/sock_bsd.c
-@@ -244,7 +244,7 @@ PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
-  * numbers-and-dots notation into binary data and stores it in the structure
-  * that inp points to. 
-  */
--PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
-+PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
- {
-     char tempaddr[PJ_INET_ADDRSTRLEN];
- 
-diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
-index 09239b0..e72bbda 100644
---- a/pjlib/src/pj/sock_symbian.cpp
-+++ b/pjlib/src/pj/sock_symbian.cpp
-@@ -299,7 +299,7 @@ PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
-  * numbers-and-dots notation into binary data and stores it in the structure
-  * that inp points to. 
-  */
--PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
-+PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
- {
-     enum { MAXIPLEN = PJ_INET_ADDRSTRLEN };
- 
-diff --git a/pjlib/src/pj/sock_uwp.cpp b/pjlib/src/pj/sock_uwp.cpp
-index 876c328..40250bf 100644
---- a/pjlib/src/pj/sock_uwp.cpp
-+++ b/pjlib/src/pj/sock_uwp.cpp
-@@ -933,7 +933,7 @@ PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
-  * numbers-and-dots notation into binary data and stores it in the structure
-  * that inp points to. 
-  */
--PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
-+PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
- {
-     char tempaddr[PJ_INET_ADDRSTRLEN];
- 
-diff --git a/pjsip/src/test/transport_test.c b/pjsip/src/test/transport_test.c
-index e5083d1..c429cc7 100644
---- a/pjsip/src/test/transport_test.c
-+++ b/pjsip/src/test/transport_test.c
-@@ -35,7 +35,7 @@ int generic_transport_test(pjsip_transport *tp)
- 
-     /* Check that local address name is valid. */
-     {
--	struct pj_in_addr addr;
-+	pj_in_addr addr;
- 
- 	if (pj_inet_pton(pj_AF_INET(), &tp->local_name.host,
- 			 &addr) == PJ_SUCCESS)
--- 
-2.7.4
-
diff --git a/third-party/pjproject/patches/0011-sip_inv_patch.patch b/third-party/pjproject/patches/0011-sip_inv_patch.patch
deleted file mode 100644
index 7f77c74..0000000
--- a/third-party/pjproject/patches/0011-sip_inv_patch.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-commit c3c1bf45cae2a35003aa16c267d59f97027f9c5e
-Author: Kevin Harwell <kharwell at digium.com>
-Date:   Thu Jun 11 11:11:13 2020 -0500
-
-    sip_inv - fix invite session ref count crash
-    
-    Ensure the session's ref count is only decremented under proper conditons.
-    
-    For more details see the following issue report:
-    https://github.com/pjsip/pjproject/issues/2443
-    
-    Patch supplied by sauwming
-
-diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
-index ca225015b..7c11b1c8e 100644
---- a/pjsip/src/pjsip-ua/sip_inv.c
-+++ b/pjsip/src/pjsip-ua/sip_inv.c
-@@ -323,9 +323,19 @@ static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
- 	(*mod_inv.cb.on_state_changed)(inv, e);
-     pjsip_inv_dec_ref(inv);
- 
--    /* Only decrement when previous state is not already DISCONNECTED */
-+    /* The above callback may change the state, so we need to be careful here
-+     * and only decrement inv under the following conditions:
-+     * 1. If the state parameter is DISCONNECTED, and previous state is not
-+     *    already DISCONNECTED.
-+     *    This is to make sure that dec_ref() is not called more than once.
-+     * 2. If current state is PJSIP_INV_STATE_DISCONNECTED.
-+     *    This is to make sure that dec_ref() is not called if user restarts
-+     *    inv within the callback. Note that this check must be last since
-+     *    inv may have already been destroyed.
-+     */
-     if (state == PJSIP_INV_STATE_DISCONNECTED &&
--	prev_state != PJSIP_INV_STATE_DISCONNECTED) 
-+	prev_state != PJSIP_INV_STATE_DISCONNECTED &&
-+	inv->state == PJSIP_INV_STATE_DISCONNECTED) 
-     {
- 	pjsip_inv_dec_ref(inv);
-     }
diff --git a/third-party/pjproject/patches/0020-pjlib_cancel_timer_0.patch b/third-party/pjproject/patches/0020-pjlib_cancel_timer_0.patch
deleted file mode 100644
index 09f72d8..0000000
--- a/third-party/pjproject/patches/0020-pjlib_cancel_timer_0.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-commit 40dd48d10911f4ff9b8dfbf16428fbc9acc434ba
-Author: Riza Sulistyo <trengginas at users.noreply.github.com>
-Date:   Thu Jul 9 17:47:24 2020 +0700
-
-    Modify timer_id check on cancel() (#2463)
-    
-    * modify timer_id check on cancel().
-    
-    * modification based on comments.
-
-diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h
-index b738a6e76..4b76ab65d 100644
---- a/pjlib/include/pj/timer.h
-+++ b/pjlib/include/pj/timer.h
-@@ -120,7 +120,10 @@ typedef struct pj_timer_entry
- 
-     /** 
-      * Internal unique timer ID, which is assigned by the timer heap. 
--     * Application should not touch this ID.
-+     * Positive values indicate that the timer entry is running, 
-+     * while -1 means that it's not. Any other value may indicate that it 
-+     * hasn't been properly initialised or is in a bad state.
-+     * Application should not touch this ID. 
-      */
-     pj_timer_id_t _timer_id;
- 
-diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
-index 66516fce8..34966c481 100644
---- a/pjlib/src/pj/timer.c
-+++ b/pjlib/src/pj/timer.c
-@@ -535,7 +535,7 @@ static int cancel( pj_timer_heap_t *ht,
-     PJ_CHECK_STACK();
- 
-     // Check to see if the timer_id is out of range
--    if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size) {
-+    if (entry->_timer_id < 1 || (pj_size_t)entry->_timer_id >= ht->max_size) {
- 	entry->_timer_id = -1;
-     	return 0;
-     }
diff --git a/third-party/pjproject/patches/0050-fix-race-parallel-build.patch b/third-party/pjproject/patches/0050-fix-race-parallel-build.patch
deleted file mode 100644
index 674baa2..0000000
--- a/third-party/pjproject/patches/0050-fix-race-parallel-build.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 78683646c8bc670ec730a42494e075f671a08e28 Mon Sep 17 00:00:00 2001
-From: Guido Falsi <mad at madpilot.net>
-Date: Mon, 11 May 2020 08:50:39 +0200
-Subject: [PATCH] Fix race condition in parallel builds (#2426)
-
-* Some targets residing in `OBJDIRS` are missing a dependency on that directory, which results in a race condition, causing build to fail sometimes due to the directory not existing when running parallel builds.
-
-* The `PJSUA_LIB` variable is not defined anywhere, resulting in an empty value, and no correct dependency on the pjsua shared library for `pjsua2`. The correct variable seems to be `PJSUA_LIB_LIB`, defined at the start of this same `Makefile`.
----
- build/rules.mak      | 12 ++++++------
- pjsip/build/Makefile |  2 +-
- 2 files changed, 7 insertions(+), 7 deletions(-)
-
-diff --git a/build/rules.mak b/build/rules.mak
-index 8fa98655e..912199c41 100644
---- a/build/rules.mak
-+++ b/build/rules.mak
-@@ -129,7 +129,7 @@ endif
- $(OBJDIR)/$(app).o: $(OBJDIRS) $(OBJS)
- 	$(CROSS_COMPILE)ld -r -o $@ $(OBJS)
- 
--$(OBJDIR)/$(app).ko: $(OBJDIR)/$(app).o
-+$(OBJDIR)/$(app).ko: $(OBJDIR)/$(app).o | $(OBJDIRS)
- 	@echo Creating kbuild Makefile...
- 	@echo "# Our module name:" > $(OBJDIR)/Makefile
- 	@echo 'obj-m += $(app).o' >> $(OBJDIR)/Makefile
-@@ -154,27 +154,27 @@ $(OBJDIR)/$(app).ko: $(OBJDIR)/$(app).o
- ../lib/$(app).ko: $(LIB) $(OBJDIR)/$(app).ko
- 	cp $(OBJDIR)/$(app).ko ../lib
- 
--$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.m
-+$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.m | $(OBJDIRS)
- 	$(CC) $($(APP)_CFLAGS) \
- 		$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
- 		$(subst /,$(HOST_PSEP),$<) 
- 
--$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.c
-+$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.c | $(OBJDIRS)
- 	$(CC) $($(APP)_CFLAGS) \
- 		$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
- 		$(subst /,$(HOST_PSEP),$<) 
- 
--$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.S
-+$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.S | $(OBJDIRS)
- 	$(CC) $($(APP)_CFLAGS) \
- 		$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
- 		$(subst /,$(HOST_PSEP),$<) 
- 
--$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.cpp
-+$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.cpp | $(OBJDIRS)
- 	$(CXX) $($(APP)_CXXFLAGS) \
- 		$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
- 		$(subst /,$(HOST_PSEP),$<)
- 
--$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.cc
-+$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.cc | $(OBJDIRS)
- 	$(CXX) $($(APP)_CXXFLAGS) \
- 		$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
- 		$(subst /,$(HOST_PSEP),$<)
-diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
-index b85c7817a..20777909f 100644
---- a/pjsip/build/Makefile
-+++ b/pjsip/build/Makefile
-@@ -262,7 +262,7 @@ $(PJSUA_LIB_LIB) $(PJSUA_LIB_SONAME): $(PJSIP_LIB) $(PJSIP_SONAME) $(PJSIP_SIMPL
- 
- pjsua2-lib: $(PJSUA2_LIB_LIB)
- $(PJSUA2_LIB_SONAME): $(PJSUA2_LIB_LIB)
--$(PJSUA2_LIB_LIB) $(PJSUA2_LIB_SONAME): $(PJSUA_LIB) $(PSJUA_LIB_SONAME) $(PJSIP_LIB) $(PJSIP_SONAME) $(PJSIP_SIMPLE_LIB) $(PJSIP_SIMPLE_SONAME) $(PJSIP_UA_LIB) $(PJSIP_UA_SONAME)
-+$(PJSUA2_LIB_LIB) $(PJSUA2_LIB_SONAME): $(PJSUA_LIB_LIB) $(PJSUA_LIB_SONAME) $(PJSIP_LIB) $(PJSIP_SONAME) $(PJSIP_SIMPLE_LIB) $(PJSIP_SIMPLE_SONAME) $(PJSIP_UA_LIB) $(PJSIP_UA_SONAME)
- 	$(MAKE) -f $(RULES_MAK) APP=PJSUA2_LIB app=pjsua2-lib $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
- 
- pjsip-test: $(TEST_EXE)
diff --git a/third-party/pjproject/patches/0060-clone-sdp-for-sip-timer-refresh-invite.patch b/third-party/pjproject/patches/0060-clone-sdp-for-sip-timer-refresh-invite.patch
deleted file mode 100644
index f1f180a..0000000
--- a/third-party/pjproject/patches/0060-clone-sdp-for-sip-timer-refresh-invite.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-diff -ur source.orig/pjmedia/src/pjmedia/sdp_neg.c source/pjmedia/src/pjmedia/sdp_neg.c
---- source.orig/pjmedia/src/pjmedia/sdp_neg.c	2020-07-02 10:35:42.022459904 +0200
-+++ source/pjmedia/src/pjmedia/sdp_neg.c	2020-07-02 10:33:24.996316867 +0200
-@@ -906,7 +906,7 @@
-  * after receiving remote answer.
-  */
- static pj_status_t process_answer(pj_pool_t *pool,
--				  pjmedia_sdp_session *offer,
-+				  pjmedia_sdp_session *local_offer,
- 				  pjmedia_sdp_session *answer,
- 				  pj_bool_t allow_asym,
- 				  pjmedia_sdp_session **p_active)
-@@ -914,10 +914,14 @@
-     unsigned omi = 0; /* Offer media index */
-     unsigned ami = 0; /* Answer media index */
-     pj_bool_t has_active = PJ_FALSE;
-+    pjmedia_sdp_session *offer;
-     pj_status_t status;
- 
-     /* Check arguments. */
--    PJ_ASSERT_RETURN(pool && offer && answer && p_active, PJ_EINVAL);
-+    PJ_ASSERT_RETURN(pool && local_offer && answer && p_active, PJ_EINVAL);
-+
-+    /* Duplicate local offer SDP. */
-+    offer = pjmedia_sdp_session_clone(pool, local_offer);
- 
-     /* Check that media count match between offer and answer */
-     // Ticket #527, different media count is allowed for more interoperability,
diff --git a/third-party/pjproject/patches/0070-fix-incorrect-copying-when-creating-cancel.patch b/third-party/pjproject/patches/0070-fix-incorrect-copying-when-creating-cancel.patch
deleted file mode 100644
index 95725c1..0000000
--- a/third-party/pjproject/patches/0070-fix-incorrect-copying-when-creating-cancel.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From ce18018cc17bef8f80c08686e3a7b28384ef3ba5 Mon Sep 17 00:00:00 2001
-From: sauwming <ming at teluu.com>
-Date: Mon, 12 Oct 2020 13:31:25 +0800
-Subject: [PATCH] Fix incorrect copying of destination info when creating
- CANCEL (#2546)
-
----
- pjsip/src/pjsip/sip_util.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
-index d10a6fa30..a1bf878ea 100644
---- a/pjsip/src/pjsip/sip_util.c
-+++ b/pjsip/src/pjsip/sip_util.c
-@@ -779,14 +779,14 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
- 	    pjsip_hdr_clone(cancel_tdata->pool, req_tdata->saved_strict_route);
-     }
- 
--    /* Copy the destination host name from the original request */
--    pj_strdup(cancel_tdata->pool, &cancel_tdata->dest_info.name,
--	      &req_tdata->dest_info.name);
--
--    /* Finally copy the destination info from the original request */
-+    /* Copy the destination info from the original request */
-     pj_memcpy(&cancel_tdata->dest_info, &req_tdata->dest_info,
- 	      sizeof(req_tdata->dest_info));
- 
-+    /* Finally, copy the destination host name from the original request */
-+    pj_strdup(cancel_tdata->pool, &cancel_tdata->dest_info.name,
-+	      &req_tdata->dest_info.name);
-+
-     /* Done.
-      * Return the transmit buffer containing the CANCEL request.
-      */
--- 
-2.25.1
-
diff --git a/third-party/pjproject/patches/0080-fix-sdp-neg-modify-local-offer.patch b/third-party/pjproject/patches/0080-fix-sdp-neg-modify-local-offer.patch
deleted file mode 100644
index c27a489..0000000
--- a/third-party/pjproject/patches/0080-fix-sdp-neg-modify-local-offer.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c
-index 3b85b4273..a14009662 100644
---- a/pjmedia/src/pjmedia/sdp_neg.c
-+++ b/pjmedia/src/pjmedia/sdp_neg.c
-@@ -304,7 +304,6 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
- {
-     pjmedia_sdp_session *new_offer;
-     pjmedia_sdp_session *old_offer;
--    char media_used[PJMEDIA_MAX_SDP_MEDIA];
-     unsigned oi; /* old offer media index */
-     pj_status_t status;
- 
-@@ -323,8 +322,19 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
-     /* Change state to STATE_LOCAL_OFFER */
-     neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;
- 
-+    /* When there is no active local SDP in state PJMEDIA_SDP_NEG_STATE_DONE,
-+     * it means that the previous initial SDP nego must have been failed,
-+     * so we'll just set the local SDP offer here.
-+     */
-+    if (!neg->active_local_sdp) {
-+	neg->initial_sdp_tmp = NULL;
-+	neg->initial_sdp = pjmedia_sdp_session_clone(pool, local);
-+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);
-+
-+	return PJ_SUCCESS;
-+    }
-+
-     /* Init vars */
--    pj_bzero(media_used, sizeof(media_used));
-     old_offer = neg->active_local_sdp;
-     new_offer = pjmedia_sdp_session_clone(pool, local);
- 
diff --git a/third-party/pjproject/patches/0090-Skip-unsupported-digest-algorithm-2408.patch b/third-party/pjproject/patches/0090-Skip-unsupported-digest-algorithm-2408.patch
deleted file mode 100644
index a2db220..0000000
--- a/third-party/pjproject/patches/0090-Skip-unsupported-digest-algorithm-2408.patch
+++ /dev/null
@@ -1,212 +0,0 @@
->From bdbeb7c4b2b11efc2e59f5dee7aa4360a2bc9fff Mon Sep 17 00:00:00 2001
-From: sauwming <ming at teluu.com>
-Date: Thu, 22 Apr 2021 14:03:28 +0800
-Subject: [PATCH 90/90] Skip unsupported digest algorithm (#2408)
-
-Co-authored-by: Nanang Izzuddin <nanang at teluu.com>
----
- pjsip/src/pjsip/sip_auth_client.c             | 32 +++++--
- tests/pjsua/scripts-sipp/uas-auth-two-algo.py |  7 ++
- .../pjsua/scripts-sipp/uas-auth-two-algo.xml  | 83 +++++++++++++++++++
- 3 files changed, 117 insertions(+), 5 deletions(-)
- create mode 100644 tests/pjsua/scripts-sipp/uas-auth-two-algo.py
- create mode 100644 tests/pjsua/scripts-sipp/uas-auth-two-algo.xml
-
-diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
-index 828b04db9..7eb2f5cd1 100644
---- a/pjsip/src/pjsip/sip_auth_client.c
-+++ b/pjsip/src/pjsip/sip_auth_client.c
-@@ -1042,7 +1042,7 @@ static pj_status_t process_auth( pj_pool_t *req_pool,
-     pjsip_hdr *hdr;
-     pj_status_t status;
- 
--    /* See if we have sent authorization header for this realm */
-+    /* See if we have sent authorization header for this realm (and scheme) */
-     hdr = tdata->msg->hdr.next;
-     while (hdr != &tdata->msg->hdr) {
- 	if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&
-@@ -1052,7 +1052,8 @@ static pj_status_t process_auth( pj_pool_t *req_pool,
- 	{
- 	    sent_auth = (pjsip_authorization_hdr*) hdr;
- 	    if (pj_stricmp(&hchal->challenge.common.realm,
--			   &sent_auth->credential.common.realm )==0)
-+			   &sent_auth->credential.common.realm)==0 &&
-+		pj_stricmp(&hchal->scheme, &sent_auth->scheme)==0)
- 	    {
- 		/* If this authorization has empty response, remove it. */
- 		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
-@@ -1062,6 +1063,14 @@ static pj_status_t process_auth( pj_pool_t *req_pool,
- 		    hdr = hdr->next;
- 		    pj_list_erase(sent_auth);
- 		    continue;
-+		} else
-+		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
-+		    pj_stricmp(&sent_auth->credential.digest.algorithm,
-+		               &hchal->challenge.digest.algorithm)!=0)
-+		{
-+		    /* Same 'digest' scheme but different algo */
-+		    hdr = hdr->next;
-+		    continue;
- 		} else {
- 		    /* Found previous authorization attempt */
- 		    break;
-@@ -1155,9 +1164,10 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req(	pjsip_auth_clt_sess *sess,
- {
-     pjsip_tx_data *tdata;
-     const pjsip_hdr *hdr;
--    unsigned chal_cnt;
-+    unsigned chal_cnt, auth_cnt;
-     pjsip_via_hdr *via;
-     pj_status_t status;
-+    pj_status_t last_auth_err;
- 
-     PJ_ASSERT_RETURN(sess && rdata && old_request && new_request,
- 		     PJ_EINVAL);
-@@ -1178,6 +1188,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req(	pjsip_auth_clt_sess *sess,
-      */
-     hdr = rdata->msg_info.msg->hdr.next;
-     chal_cnt = 0;
-+    auth_cnt = 0;
-+    last_auth_err = PJSIP_EAUTHNOAUTH;
-     while (hdr != &rdata->msg_info.msg->hdr) {
- 	pjsip_cached_auth *cached_auth;
- 	const pjsip_www_authenticate_hdr *hchal;
-@@ -1222,8 +1234,13 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req(	pjsip_auth_clt_sess *sess,
- 	 */
- 	status = process_auth(tdata->pool, hchal, tdata->msg->line.req.uri,
- 			      tdata, sess, cached_auth, &hauth);
--	if (status != PJ_SUCCESS)
--	    return status;
-+	if (status != PJ_SUCCESS) {
-+	    last_auth_err = status;
-+
-+	    /* Process next header. */
-+	    hdr = hdr->next;
-+	    continue;
-+	}
- 
- 	if (pj_pool_get_used_size(cached_auth->pool) >
- 	    PJSIP_AUTH_CACHED_POOL_MAX_SIZE) 
-@@ -1236,12 +1253,17 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req(	pjsip_auth_clt_sess *sess,
- 
- 	/* Process next header. */
- 	hdr = hdr->next;
-+	auth_cnt++;
-     }
- 
-     /* Check if challenge is present */
-     if (chal_cnt == 0)
- 	return PJSIP_EAUTHNOCHAL;
- 
-+    /* Check if any authorization header has been created */
-+    if (auth_cnt == 0)
-+	return last_auth_err;
-+
-     /* Remove branch param in Via header. */
-     via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
-     via->branch_param.slen = 0;
-diff --git a/tests/pjsua/scripts-sipp/uas-auth-two-algo.py b/tests/pjsua/scripts-sipp/uas-auth-two-algo.py
-new file mode 100644
-index 000000000..c79c9f6d3
---- /dev/null
-+++ b/tests/pjsua/scripts-sipp/uas-auth-two-algo.py
-@@ -0,0 +1,7 @@
-+# $Id$
-+#
-+import inc_const as const
-+
-+PJSUA = ["--null-audio --max-calls=1 --id=sip:a at localhost --username=a --realm=* --registrar=$SIPP_URI"]
-+
-+PJSUA_EXPECTS = [[0, "registration success", ""]]
-diff --git a/tests/pjsua/scripts-sipp/uas-auth-two-algo.xml b/tests/pjsua/scripts-sipp/uas-auth-two-algo.xml
-new file mode 100644
-index 000000000..bd4871940
---- /dev/null
-+++ b/tests/pjsua/scripts-sipp/uas-auth-two-algo.xml
-@@ -0,0 +1,83 @@
-+<?xml version="1.0" encoding="ISO-8859-1" ?>
-+<!DOCTYPE scenario SYSTEM "sipp.dtd">
-+
-+<scenario name="Basic UAS responder">
-+  <recv request="REGISTER" crlf="true">
-+  </recv>
-+
-+  <send>
-+    <![CDATA[
-+      SIP/2.0 100 Trying
-+      [last_Via:];received=1.1.1.1;rport=1111
-+      [last_From:]
-+      [last_To:];tag=[call_number]
-+      [last_Call-ID:]
-+      [last_CSeq:]
-+      Content-Length: 0
-+    ]]>
-+  </send>
-+
-+  <send>
-+    <![CDATA[
-+      SIP/2.0 401 Unauthorized
-+      [last_Via:];received=1.1.1.1;rport=1111
-+      [last_From:]
-+      [last_To:];tag=[call_number]
-+      [last_Call-ID:]
-+      [last_CSeq:]
-+      WWW-Authenticate: Digest realm="sip.linphone.org", nonce="PARV4gAAAADgw3asAADW8zsi5BEAAAAA", opaque="+GNywA==", algorithm=SHA-256, qop="auth"
-+      WWW-Authenticate: Digest realm="sip.linphone.org", nonce="PARV4gAAAADgw3asAADW8zsi5BEAAAAA", opaque="+GNywA==", algorithm=MD5, qop="auth"
-+      WWW-Authenticate: Digest realm="sip.linphone.org", nonce="PARV4gAAAADgw3asAADW8zsi5BEAAAAA", opaque="+GNywA==", algorithm=MD2, qop="auth"
-+      Content-Length: 0
-+    ]]>
-+  </send>
-+
-+  <recv request="REGISTER" crlf="true">
-+    <action>
-+      <ereg regexp=".*"
-+            search_in="hdr"
-+	    header="Authorization:"
-+	    assign_to="have_auth" />
-+    </action>
-+  </recv>
-+
-+  <nop next="resp_okay" test="have_auth" />
-+  
-+  <send next="end">
-+    <![CDATA[
-+      SIP/2.0 403 no auth
-+      [last_Via:];received=1.1.1.1;rport=1111
-+      [last_From:]
-+      [last_To:];tag=[call_number]
-+      [last_Call-ID:]
-+      [last_CSeq:]
-+      [last_Contact:]
-+      Content-Length: 0
-+    ]]>
-+  </send>
-+
-+  <label id="resp_okay" />
-+  
-+  <send>
-+    <![CDATA[
-+      SIP/2.0 200 OK
-+      [last_Via:];received=1.1.1.1;rport=1111
-+      [last_From:]
-+      [last_To:];tag=[call_number]
-+      [last_Call-ID:]
-+      [last_CSeq:]
-+      [last_Contact:]
-+      Content-Length: 0
-+    ]]>
-+  </send>
-+
-+  <label id="end" />
-+
-+  <!-- definition of the response time repartition table (unit is ms)   -->
-+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
-+
-+  <!-- definition of the call length repartition table (unit is ms)     -->
-+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
-+
-+</scenario>
-+
--- 
-2.31.1
-
diff --git a/third-party/pjproject/patches/0100-allow_multiple_auth_headers.patch b/third-party/pjproject/patches/0100-allow_multiple_auth_headers.patch
new file mode 100644
index 0000000..e291eeb
--- /dev/null
+++ b/third-party/pjproject/patches/0100-allow_multiple_auth_headers.patch
@@ -0,0 +1,413 @@
+commit 8e95490e37938f45d9d812905246036c3185b94f
+Author: Riza Sulistyo <trengginas at users.noreply.github.com>
+Date:   Thu Mar 24 12:53:03 2022 +0700
+
+    Add compile time option to allow multiple Authorization header (#3010)
+
+diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
+index dfd9ce977..ccce6ed01 100644
+--- a/pjsip/include/pjsip/sip_config.h
++++ b/pjsip/include/pjsip/sip_config.h
+@@ -1280,6 +1280,18 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+ #   define PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY	1
+ #endif
+ 
++/**
++ * Allow client to send multiple Authorization header when receiving multiple 
++ * WWW-Authenticate header fields. If this is disabled, the stack will send
++ * Authorization header field containing credentials that match the
++ * topmost header field.
++ *
++ * Default is 0
++ */
++#ifndef PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER
++#   define PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER 0
++#endif
++
+ /*****************************************************************************
+  *  SIP Event framework and presence settings.
+  */
+@@ -1458,6 +1470,11 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+ #   define PJSIP_INV_ACCEPT_UNKNOWN_BODY    PJ_FALSE
+ #endif
+ 
++/**
++ * Dump configuration to log with verbosity equal to info(3).
++ */
++PJ_DECL(void) pjsip_dump_config(void);
++
+ PJ_END_DECL
+ 
+ /**
+diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
+index 35460d01e..ab1a0cd87 100644
+--- a/pjsip/src/pjsip/sip_auth_client.c
++++ b/pjsip/src/pjsip/sip_auth_client.c
+@@ -1367,7 +1367,7 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req(	pjsip_auth_clt_sess *sess,
+     chal_cnt = 0;
+     auth_cnt = 0;
+     last_auth_err = PJSIP_EAUTHNOAUTH;
+-    while (hdr != &rdata->msg_info.msg->hdr && auth_cnt == 0) {
++    while (hdr != &rdata->msg_info.msg->hdr) {
+ 	pjsip_cached_auth *cached_auth;
+ 	const pjsip_www_authenticate_hdr *hchal;
+ 	pjsip_authorization_hdr *hauth;
+@@ -1431,6 +1431,11 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req(	pjsip_auth_clt_sess *sess,
+ 	/* Process next header. */
+ 	hdr = hdr->next;
+ 	auth_cnt++;
++
++#if defined(PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER) && \
++	    PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER==0
++	break;
++#endif
+     }
+ 
+     /* Check if challenge is present */
+diff --git a/pjsip/src/pjsip/sip_config.c b/pjsip/src/pjsip/sip_config.c
+index 957f9fad4..6920b3dfe 100644
+--- a/pjsip/src/pjsip/sip_config.c
++++ b/pjsip/src/pjsip/sip_config.c
+@@ -19,6 +19,9 @@
+  */
+ 
+ #include <pjsip/sip_config.h>
++#include <pj/log.h>
++
++static const char *id = "sip_config.c";
+ 
+ /* pjsip configuration instance, initialized with default values */
+ pjsip_cfg_t pjsip_sip_cfg_var =
+@@ -65,6 +68,195 @@ pjsip_cfg_t pjsip_sip_cfg_var =
+     }
+ };
+ 
++PJ_DEF(void) pjsip_dump_config(void)
++{
++    PJ_LOG(3, (id, "Dumping PJSIP configurations:"));
++    PJ_LOG(3, (id, " PJSIP_MAX_DIALOG_COUNT                             : %d", 
++	       PJSIP_MAX_DIALOG_COUNT));
++    PJ_LOG(3, (id, " PJSIP_MAX_TRANSPORTS                               : %d", 
++	       PJSIP_MAX_TRANSPORTS));
++    PJ_LOG(3, (id, " PJSIP_TPMGR_HTABLE_SIZE                            : %d", 
++	       PJSIP_TPMGR_HTABLE_SIZE));
++    PJ_LOG(3, (id, " PJSIP_MAX_URL_SIZE                                 : %d", 
++	       PJSIP_MAX_URL_SIZE));
++    PJ_LOG(3, (id, " PJSIP_MAX_MODULE                                   : %d", 
++	       PJSIP_MAX_MODULE));
++    PJ_LOG(3, (id, " PJSIP_MAX_PKT_LEN                                  : %d", 
++	       PJSIP_MAX_PKT_LEN));
++    PJ_LOG(3, (id, " PJSIP_HANDLE_EVENTS_HAS_SLEEP_ON_ERR               : %d", 
++	       PJSIP_HANDLE_EVENTS_HAS_SLEEP_ON_ERR));
++    PJ_LOG(3, (id, " PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS                  : %d", 
++	       PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS));
++    PJ_LOG(3, (id, " PJSIP_UDP_SIZE_THRESHOLD                           : %d", 
++	       PJSIP_UDP_SIZE_THRESHOLD));
++    PJ_LOG(3, (id, " PJSIP_INCLUDE_ALLOW_HDR_IN_DLG                     : %d", 
++	       PJSIP_INCLUDE_ALLOW_HDR_IN_DLG));
++    PJ_LOG(3, (id, " PJSIP_SAFE_MODULE                                  : %d", 
++	       PJSIP_SAFE_MODULE));
++    PJ_LOG(3, (id, " PJSIP_CHECK_VIA_SENT_BY                            : %d", 
++	       PJSIP_CHECK_VIA_SENT_BY));
++    PJ_LOG(3, (id, " PJSIP_UNESCAPE_IN_PLACE                            : %d", 
++	       PJSIP_UNESCAPE_IN_PLACE));
++    PJ_LOG(3, (id, " PJSIP_MAX_NET_EVENTS                               : %d", 
++	       PJSIP_MAX_NET_EVENTS));
++    PJ_LOG(3, (id, " PJSIP_MAX_TIMED_OUT_ENTRIES                        : %d", 
++	       PJSIP_MAX_TIMED_OUT_ENTRIES));
++    PJ_LOG(3, (id, " PJSIP_TRANSPORT_IDLE_TIME                          : %d", 
++	       PJSIP_TRANSPORT_IDLE_TIME));
++    PJ_LOG(3, (id, " PJSIP_TRANSPORT_SERVER_IDLE_TIME                   : %d", 
++	       PJSIP_TRANSPORT_SERVER_IDLE_TIME));
++    PJ_LOG(3, (id, " PJSIP_MAX_TRANSPORT_USAGE                          : %d", 
++	       PJSIP_MAX_TRANSPORT_USAGE));
++    PJ_LOG(3, (id, " PJSIP_TCP_TRANSPORT_BACKLOG                        : %d", 
++	       PJSIP_TCP_TRANSPORT_BACKLOG));
++    PJ_LOG(3, (id, " PJSIP_TCP_TRANSPORT_REUSEADDR                      : %d", 
++	       PJSIP_TCP_TRANSPORT_REUSEADDR));
++    PJ_LOG(3, (id, " PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER           : %d", 
++	       PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER));
++    PJ_LOG(3, (id, " PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER           : %d", 
++	       PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER));
++    PJ_LOG(3, (id, " PJSIP_TCP_KEEP_ALIVE_INTERVAL                      : %d", 
++	       PJSIP_TCP_KEEP_ALIVE_INTERVAL));
++    PJ_LOG(3, (id, " PJSIP_POOL_INC_TRANSPORT                           : %d", 
++	       PJSIP_POOL_INC_TRANSPORT));
++    PJ_LOG(3, (id, " PJSIP_POOL_LEN_TDATA                               : %d", 
++	       PJSIP_POOL_LEN_TDATA));
++    PJ_LOG(3, (id, " PJSIP_POOL_INC_TDATA                               : %d", 
++	       PJSIP_POOL_INC_TDATA));
++    PJ_LOG(3, (id, " PJSIP_POOL_LEN_UA                                  : %d", 
++	       PJSIP_POOL_LEN_UA));
++    PJ_LOG(3, (id, " PJSIP_POOL_INC_UA                                  : %d", 
++	       PJSIP_POOL_INC_UA));
++    PJ_LOG(3, (id, " PJSIP_POOL_EVSUB_LEN                               : %d", 
++	       PJSIP_POOL_EVSUB_LEN));
++    PJ_LOG(3, (id, " PJSIP_POOL_EVSUB_INC                               : %d", 
++	       PJSIP_POOL_EVSUB_INC));
++    PJ_LOG(3, (id, " PJSIP_MAX_FORWARDS_VALUE                           : %d", 
++	       PJSIP_MAX_FORWARDS_VALUE));
++    PJ_LOG(3, (id, " PJSIP_RFC3261_BRANCH_ID                            : %s", 
++	       PJSIP_RFC3261_BRANCH_ID));
++    PJ_LOG(3, (id, " PJSIP_RFC3261_BRANCH_LEN                           : %d", 
++	       PJSIP_RFC3261_BRANCH_LEN));
++    PJ_LOG(3, (id, " PJSIP_POOL_TSX_LAYER_LEN                           : %d", 
++	       PJSIP_POOL_TSX_LAYER_LEN));
++    PJ_LOG(3, (id, " PJSIP_POOL_TSX_LAYER_INC                           : %d", 
++	       PJSIP_POOL_TSX_LAYER_INC));
++    PJ_LOG(3, (id, " PJSIP_POOL_TSX_LEN                                 : %d", 
++	       PJSIP_POOL_TSX_LEN));
++    PJ_LOG(3, (id, " PJSIP_POOL_TSX_INC                                 : %d", 
++	       PJSIP_POOL_TSX_INC));
++    PJ_LOG(3, (id, " PJSIP_TSX_1XX_RETRANS_DELAY                        : %d", 
++	       PJSIP_TSX_1XX_RETRANS_DELAY));
++    PJ_LOG(3, (id, " PJSIP_TSX_UAS_CONTINUE_ON_TP_ERROR                 : %d", 
++	       PJSIP_TSX_UAS_CONTINUE_ON_TP_ERROR));
++    PJ_LOG(3, (id, " PJSIP_MAX_TSX_KEY_LEN                              : %d", 
++	       PJSIP_MAX_TSX_KEY_LEN));
++    PJ_LOG(3, (id, " PJSIP_POOL_LEN_USER_AGENT                          : %d", 
++	       PJSIP_POOL_LEN_USER_AGENT));
++    PJ_LOG(3, (id, " PJSIP_POOL_INC_USER_AGENT                          : %d", 
++	       PJSIP_POOL_INC_USER_AGENT));
++    PJ_LOG(3, (id, " PJSIP_MAX_BRANCH_LEN                               : %d", 
++	       PJSIP_MAX_HNAME_LEN));
++    PJ_LOG(3, (id, " PJSIP_POOL_LEN_DIALOG                              : %d", 
++	       PJSIP_POOL_LEN_DIALOG));
++    PJ_LOG(3, (id, " PJSIP_POOL_INC_DIALOG                              : %d", 
++	       PJSIP_POOL_INC_DIALOG));
++    PJ_LOG(3, (id, " PJSIP_MAX_HEADER_TYPES                             : %d", 
++	       PJSIP_MAX_HEADER_TYPES));
++    PJ_LOG(3, (id, " PJSIP_MAX_URI_TYPES                                : %d", 
++	       PJSIP_MAX_URI_TYPES));
++    PJ_LOG(3, (id, " PJSIP_AUTH_HEADER_CACHING                          : %d", 
++	       PJSIP_AUTH_HEADER_CACHING));
++    PJ_LOG(3, (id, " PJSIP_AUTH_AUTO_SEND_NEXT                          : %d", 
++	       PJSIP_AUTH_AUTO_SEND_NEXT));
++    PJ_LOG(3, (id, " PJSIP_AUTH_QOP_SUPPORT                             : %d", 
++	       PJSIP_AUTH_QOP_SUPPORT));
++    PJ_LOG(3, (id, " PJSIP_MAX_STALE_COUNT                              : %d", 
++	       PJSIP_MAX_STALE_COUNT));
++    PJ_LOG(3, (id, " PJSIP_HAS_DIGEST_AKA_AUTH                          : %d", 
++	       PJSIP_HAS_DIGEST_AKA_AUTH));
++    PJ_LOG(3, (id, " PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH         : %d", 
++	       PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH));
++    PJ_LOG(3, (id, " PJSIP_REGISTER_ALLOW_EXP_REFRESH                   : %d", 
++	       PJSIP_REGISTER_ALLOW_EXP_REFRESH));
++    PJ_LOG(3, (id, " PJSIP_AUTH_CACHED_POOL_MAX_SIZE                    : %d", 
++	       PJSIP_AUTH_CACHED_POOL_MAX_SIZE));
++    PJ_LOG(3, (id, " PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY                  : %d", 
++	       PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY));
++    PJ_LOG(3, (id, " PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER              : %d", 
++	       PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER));
++    PJ_LOG(3, (id, " PJSIP_EVSUB_TIME_UAC_REFRESH                       : %d", 
++	       PJSIP_EVSUB_TIME_UAC_REFRESH));
++    PJ_LOG(3, (id, " PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH                : %d", 
++	       PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH));
++    PJ_LOG(3, (id, " PJSIP_EVSUB_TIME_UAC_TERMINATE                     : %d", 
++	       PJSIP_EVSUB_TIME_UAC_TERMINATE));
++    PJ_LOG(3, (id, " PJSIP_EVSUB_TIME_UAC_WAIT_NOTIFY                   : %d", 
++	       PJSIP_EVSUB_TIME_UAC_WAIT_NOTIFY));
++    PJ_LOG(3, (id, " PJSIP_PRES_DEFAULT_EXPIRES                         : %d", 
++	       PJSIP_PRES_DEFAULT_EXPIRES));
++    PJ_LOG(3, (id, " PJSIP_PRES_BAD_CONTENT_RESPONSE                    : %d", 
++	       PJSIP_PRES_BAD_CONTENT_RESPONSE));
++    PJ_LOG(3, (id, " PJSIP_PRES_PIDF_ADD_TIMESTAMP                      : %d", 
++	       PJSIP_PRES_PIDF_ADD_TIMESTAMP));
++    PJ_LOG(3, (id, " PJSIP_SESS_TIMER_DEF_SE                            : %d", 
++	       PJSIP_SESS_TIMER_DEF_SE));
++    PJ_LOG(3, (id, " PJSIP_SESS_TIMER_RETRY_DELAY                       : %d", 
++	       PJSIP_SESS_TIMER_RETRY_DELAY));
++    PJ_LOG(3, (id, " PJSIP_PUBLISHC_QUEUE_REQUEST                       : %d", 
++	       PJSIP_PUBLISHC_QUEUE_REQUEST));
++    PJ_LOG(3, (id, " PJSIP_MWI_DEFAULT_EXPIRES                          : %d", 
++	       PJSIP_MWI_DEFAULT_EXPIRES));
++    PJ_LOG(3, (id, " PJSIP_HAS_TX_DATA_LIST                             : %d", 
++	       PJSIP_HAS_TX_DATA_LIST));
++    PJ_LOG(3, (id, " PJSIP_INV_ACCEPT_UNKNOWN_BODY                      : %d", 
++	       PJSIP_INV_ACCEPT_UNKNOWN_BODY));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.allow_port_in_fromto_hdr        : %d", 
++	       pjsip_cfg()->endpt.allow_port_in_fromto_hdr));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.accept_replace_in_early_state   : %d", 
++	       pjsip_cfg()->endpt.accept_replace_in_early_state));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.allow_tx_hash_in_uri            : %d", 
++	       pjsip_cfg()->endpt.allow_tx_hash_in_uri));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.disable_rport                   : %d", 
++	       pjsip_cfg()->endpt.disable_rport));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.disable_tcp_switch              : %d", 
++	       pjsip_cfg()->endpt.disable_tcp_switch));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.disable_tls_switch              : %d", 
++	       pjsip_cfg()->endpt.disable_tls_switch));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.follow_early_media_fork         : %d", 
++	       pjsip_cfg()->endpt.follow_early_media_fork));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.req_has_via_alias               : %d", 
++	       pjsip_cfg()->endpt.req_has_via_alias));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.resolve_hostname_to_get_interface:%d", 
++	       pjsip_cfg()->endpt.resolve_hostname_to_get_interface));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.disable_secure_dlg_check        : %d", 
++	       pjsip_cfg()->endpt.disable_secure_dlg_check));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.use_compact_form                : %d", 
++	       pjsip_cfg()->endpt.use_compact_form));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.accept_multiple_sdp_answers     : %d", 
++	       pjsip_cfg()->endpt.accept_multiple_sdp_answers));
++    PJ_LOG(3, (id, " pjsip_cfg()->endpt.keep_inv_after_tsx_timeout      : %d", 
++	       pjsip_cfg()->endpt.keep_inv_after_tsx_timeout));
++    PJ_LOG(3, (id, " pjsip_cfg()->tsx.max_count                         : %d", 
++	       pjsip_cfg()->tsx.max_count));
++    PJ_LOG(3, (id, " pjsip_cfg()->tsx.t1                                : %d", 
++	       pjsip_cfg()->tsx.t1));
++    PJ_LOG(3, (id, " pjsip_cfg()->tsx.t2                                : %d", 
++	       pjsip_cfg()->tsx.t2));
++    PJ_LOG(3, (id, " pjsip_cfg()->tsx.t4                                : %d", 
++	       pjsip_cfg()->tsx.t4));
++    PJ_LOG(3, (id, " pjsip_cfg()->td                                    : %d", 
++	       pjsip_cfg()->tsx.td));
++    PJ_LOG(3, (id, " pjsip_cfg()->regc.check_contact                    : %d", 
++	       pjsip_cfg()->regc.check_contact));
++    PJ_LOG(3, (id, " pjsip_cfg()->regc.add_xuid_param                   : %d", 
++	       pjsip_cfg()->regc.add_xuid_param));
++    PJ_LOG(3, (id, " pjsip_cfg()->tcp.keep_alive_interval               : %d", 
++	       pjsip_cfg()->tcp.keep_alive_interval));
++    PJ_LOG(3, (id, " pjsip_cfg()->tls.keep_alive_interval               : %d", 
++	       pjsip_cfg()->tls.keep_alive_interval));
++}
++
+ 
+ #ifdef PJ_DLL
+ PJ_DEF(pjsip_cfg_t*) pjsip_cfg(void)
+diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
+index c437011b5..343316b56 100644
+--- a/pjsip/src/pjsua-lib/pjsua_core.c
++++ b/pjsip/src/pjsua-lib/pjsua_core.c
+@@ -3443,8 +3443,10 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
+     old_decor = pj_log_get_decor();
+     pj_log_set_decor(old_decor & (PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR));
+ 
+-    if (detail)
++    if (detail) {
+ 	pj_dump_config();
++	pjsip_dump_config();
++    }
+ 
+     pjsip_endpt_dump(pjsua_get_pjsip_endpt(), detail);
+ 
+diff --git a/tests/pjsua/inc_sip.py b/tests/pjsua/inc_sip.py
+index f7e64816e..2cc1a17a8 100644
+--- a/tests/pjsua/inc_sip.py
++++ b/tests/pjsua/inc_sip.py
+@@ -306,9 +306,11 @@ class RecvfromTransaction:
+ 	body = None
+ 	# Pattern to be expected on pjsua when receiving the response
+ 	expect = ""
++	# Required config
++	pj_config = ""
+ 	
+ 	def __init__(self, title, resp_code, check_cseq=True,
+-			include=[], exclude=[], cmds=[], resp_hdr=[], resp_body=None, expect=""):
++			include=[], exclude=[], cmds=[], resp_hdr=[], resp_body=None, expect="", pj_config=""):
+ 		self.title = title
+ 		self.cmds = cmds
+ 		self.include = include
+@@ -317,6 +319,7 @@ class RecvfromTransaction:
+ 		self.resp_hdr = resp_hdr
+ 		self.body = resp_body
+ 		self.expect = expect
++		self.pj_config=pj_config
+ 			
+ 
+ class RecvfromCfg:
+@@ -328,15 +331,18 @@ class RecvfromCfg:
+ 	transaction = None
+ 	# Use TCP?
+ 	tcp = False
++	# Required config
++	pj_config = ""
+ 
+ 	# Note:
+ 	#  Any "$PORT" string in the pjsua_args will be replaced
+ 	#  by server port
+-	def __init__(self, name, pjsua_args, transaction, tcp=False):
++	def __init__(self, name, pjsua_args, transaction, tcp=False, pj_config=""):
+ 		self.name = name
+ 		self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
+ 		self.transaction = transaction
+ 		self.tcp=tcp
++		self.pj_config=pj_config
+ 
+ 
+ 
+diff --git a/tests/pjsua/mod_recvfrom.py b/tests/pjsua/mod_recvfrom.py
+index 918006aff..4305bfb42 100644
+--- a/tests/pjsua/mod_recvfrom.py
++++ b/tests/pjsua/mod_recvfrom.py
+@@ -18,10 +18,20 @@ def test_func(test):
+              local_port=srv_port, 
+              tcp=cfg_file.recvfrom_cfg.tcp)
+ 
++    config = pjsua.get_config(cfg_file.recvfrom_cfg.pj_config)
++    print "Config : " + config
++
+     last_cseq = 0
+     last_method = ""
+     last_call_id = ""
+     for t in cfg_file.recvfrom_cfg.transaction:
++        # Check if transaction requires configuration
++        if t.pj_config != "":
++            r = re.compile(t.pj_config, re.I)
++            if r.search(config) == None:
++                print "Configuration : " + t.pj_config + " not found, skipping"
++                continue
++
+         # Print transaction title
+         if t.title != "":
+             dlg.trace(t.title)
+diff --git a/tests/pjsua/run.py b/tests/pjsua/run.py
+index 35b00dec5..cffc38470 100644
+--- a/tests/pjsua/run.py
++++ b/tests/pjsua/run.py
+@@ -249,6 +249,10 @@ class Expect(threading.Thread):
+                     time.sleep(0.01)
+         return None
+                             
++    def get_config(self, key_config):
++        self.send("dd")
++        line = self.expect(key_config);
++        return line
+ 
+     def sync_stdout(self):
+         if not self.use_telnet:
+diff --git a/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py b/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
+index a98b8b1d8..909ba229b 100644
+--- a/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
++++ b/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
+@@ -14,16 +14,27 @@ req1 = sip.RecvfromTransaction("Initial registration", 401,
+ 				expect="SIP/2.0 401"
+ 			  )
+ 
+-req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
++req2 = sip.RecvfromTransaction("Registration retry with auth (not allowed multiple auth)", 200,
+ 				include=["REGISTER sip", 
+-					 # Must only have 1 Auth hdr since #2887
+ 					 "Authorization:", # [\\s\\S]+Authorization:"
+ 					 "realm=\"python1\"", # "realm=\"python2\"", 
+ 					 "username=\"theuser1\"", # "username=\"theuser2\"", 
+ 					 "nonce=\"1234\"", # "nonce=\"6789\"", 
+ 					 "response="],
+-				expect="registration success"	     
++				expect="registration success",
++				pj_config="PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER.*: 0"
+ 			  )
+ 
++req3 = sip.RecvfromTransaction("Registration retry with auth (allowed multiple auth)", 200,
++				include=["REGISTER sip", 
++					 "Authorization:[\\s\\S]+Authorization:", # Must have 2 Auth hdrs
++					 "realm=\"python1\"", "realm=\"python2\"", 
++					 "username=\"theuser1\"", "username=\"theuser2\"", 
++					 "nonce=\"1234\"", "nonce=\"6789\"", 
++					 "response="],
++				expect="registration success",
++				pj_config="PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER.*: 1"	     
++			  )                          
++
+ recvfrom_cfg = sip.RecvfromCfg("Multiple authentication challenges",
+-			       pjsua, [req1, req2])
++			       pjsua, [req1, req2, req3], pj_config="PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER")
diff --git a/third-party/pjproject/patches/0100-fix-double-stun-free.patch b/third-party/pjproject/patches/0100-fix-double-stun-free.patch
deleted file mode 100644
index b1cfcfd..0000000
--- a/third-party/pjproject/patches/0100-fix-double-stun-free.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-commit f0ff5817d0647bdecd1ec99488db9378e304cf83
-Author: sauwming <ming at teluu.com>
-Date:   Mon May 17 09:56:27 2021 +0800
-
-    Fix double free of stun session (#2709)
-
-diff --git a/pjnath/include/pjnath/stun_session.h b/pjnath/include/pjnath/stun_session.h
-index bee630ab4..afca06911 100644
---- a/pjnath/include/pjnath/stun_session.h
-+++ b/pjnath/include/pjnath/stun_session.h
-@@ -341,6 +341,7 @@ struct pj_stun_tx_data
-     pj_pool_t		*pool;		/**< Pool.			    */
-     pj_stun_session	*sess;		/**< The STUN session.		    */
-     pj_stun_msg		*msg;		/**< The STUN message.		    */
-+    pj_bool_t		 is_destroying; /**< Is destroying?		    */
- 
-     void		*token;		/**< The token.			    */
- 
-diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c
-index f2b4f7058..d436b94bf 100644
---- a/pjnath/src/pjnath/stun_session.c
-+++ b/pjnath/src/pjnath/stun_session.c
-@@ -167,16 +167,27 @@ static void tdata_on_destroy(void *arg)
- {
-     pj_stun_tx_data *tdata = (pj_stun_tx_data*)arg;
- 
-+    if (tdata->grp_lock) {
-+	pj_grp_lock_dec_ref(tdata->sess->grp_lock);
-+    }
-+
-     pj_pool_safe_release(&tdata->pool);
- }
- 
- static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force)
- {
--    TRACE_((THIS_FILE, "tdata %p destroy request, force=%d, tsx=%p", tdata,
--	    force, tdata->client_tsx));
-+    TRACE_((THIS_FILE,
-+	    "tdata %p destroy request, force=%d, tsx=%p, destroying=%d",
-+	    tdata, force, tdata->client_tsx, tdata->is_destroying));
-+
-+    /* Just return if destroy has been requested before */
-+    if (tdata->is_destroying)
-+	return;
- 
-     /* STUN session may have been destroyed, except when tdata is cached. */
- 
-+    tdata->is_destroying = PJ_TRUE;
-+
-     if (tdata->res_timer.id != PJ_FALSE) {
- 	pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap,
- 				       &tdata->res_timer, PJ_FALSE);
-@@ -189,7 +200,6 @@ static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force)
- 	    pj_stun_client_tsx_set_data(tdata->client_tsx, NULL);
- 	}
- 	if (tdata->grp_lock) {
--	    pj_grp_lock_dec_ref(tdata->sess->grp_lock);
- 	    pj_grp_lock_dec_ref(tdata->grp_lock);
- 	} else {
- 	    tdata_on_destroy(tdata);
-@@ -200,11 +210,11 @@ static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force)
- 	    /* "Probably" this is to absorb retransmission */
- 	    pj_time_val delay = {0, 300};
- 	    pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay);
-+	    tdata->is_destroying = PJ_FALSE;
- 
- 	} else {
- 	    pj_list_erase(tdata);
- 	    if (tdata->grp_lock) {
--		pj_grp_lock_dec_ref(tdata->sess->grp_lock);
- 		pj_grp_lock_dec_ref(tdata->grp_lock);
- 	    } else {
- 		tdata_on_destroy(tdata);
-@@ -238,7 +248,7 @@ static void on_cache_timeout(pj_timer_heap_t *timer_heap,
-     sess = tdata->sess;
- 
-     pj_grp_lock_acquire(sess->grp_lock);
--    if (sess->is_destroying) {
-+    if (sess->is_destroying || tdata->is_destroying) {
- 	pj_grp_lock_release(sess->grp_lock);
- 	return;
-     }
diff --git a/third-party/pjproject/patches/0110-tls-parent-listener-destroyed.patch b/third-party/pjproject/patches/0110-tls-parent-listener-destroyed.patch
deleted file mode 100644
index 81781f2..0000000
--- a/third-party/pjproject/patches/0110-tls-parent-listener-destroyed.patch
+++ /dev/null
@@ -1,166 +0,0 @@
-From bb92c97ea512aa0ef316c9b2335c7d57b84dfc9a Mon Sep 17 00:00:00 2001
-From: Nanang Izzuddin <nanang at teluu.com>
-Date: Wed, 16 Jun 2021 12:12:35 +0700
-Subject: [PATCH 1/2] - Avoid SSL socket parent/listener getting destroyed
- during handshake by increasing parent's reference count. - Add missing SSL
- socket close when the newly accepted SSL socket is discarded in SIP TLS
- transport.
-
----
- pjlib/src/pj/ssl_sock_imp_common.c  | 44 +++++++++++++++++++++--------
- pjsip/src/pjsip/sip_transport_tls.c | 23 ++++++++++++++-
- 2 files changed, 55 insertions(+), 12 deletions(-)
-
-diff --git a/pjlib/src/pj/ssl_sock_imp_common.c b/pjlib/src/pj/ssl_sock_imp_common.c
-index bc468bcb3..abec31805 100644
---- a/pjlib/src/pj/ssl_sock_imp_common.c
-+++ b/pjlib/src/pj/ssl_sock_imp_common.c
-@@ -224,6 +224,8 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
- 
-     /* Accepting */
-     if (ssock->is_server) {
-+	pj_bool_t ret = PJ_TRUE;
-+
- 	if (status != PJ_SUCCESS) {
- 	    /* Handshake failed in accepting, destroy our self silently. */
- 
-@@ -241,6 +243,12 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
- 		      status);
- 	    }
- 
-+	    /* Decrement ref count of parent */
-+	    if (ssock->parent->param.grp_lock) {
-+		pj_grp_lock_dec_ref(ssock->parent->param.grp_lock);
-+		ssock->parent = NULL;
-+	    }
-+
- 	    /* Originally, this is a workaround for ticket #985. However,
- 	     * a race condition may occur in multiple worker threads
- 	     * environment when we are destroying SSL objects while other
-@@ -284,23 +292,29 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
- 
- 	    return PJ_FALSE;
- 	}
-+
- 	/* Notify application the newly accepted SSL socket */
- 	if (ssock->param.cb.on_accept_complete2) {
--	    pj_bool_t ret;
- 	    ret = (*ssock->param.cb.on_accept_complete2) 
- 		    (ssock->parent, ssock, (pj_sockaddr_t*)&ssock->rem_addr, 
- 		    pj_sockaddr_get_len((pj_sockaddr_t*)&ssock->rem_addr), 
- 		    status);
--	    if (ret == PJ_FALSE)
--		return PJ_FALSE;	
- 	} else if (ssock->param.cb.on_accept_complete) {
--	    pj_bool_t ret;
- 	    ret = (*ssock->param.cb.on_accept_complete)
- 		      (ssock->parent, ssock, (pj_sockaddr_t*)&ssock->rem_addr,
- 		       pj_sockaddr_get_len((pj_sockaddr_t*)&ssock->rem_addr));
--	    if (ret == PJ_FALSE)
--		return PJ_FALSE;
- 	}
-+
-+	/* Decrement ref count of parent and reset parent (we don't need it
-+	 * anymore, right?).
-+	 */
-+	if (ssock->parent->param.grp_lock) {
-+	    pj_grp_lock_dec_ref(ssock->parent->param.grp_lock);
-+	    ssock->parent = NULL;
-+	}
-+
-+	if (ret == PJ_FALSE)
-+	    return PJ_FALSE;
-     }
- 
-     /* Connecting */
-@@ -864,9 +878,13 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
-     if (status != PJ_SUCCESS)
- 	goto on_return;
- 
-+    /* Set parent and add ref count (avoid parent destroy during handshake) */
-+    ssock->parent = ssock_parent;
-+    if (ssock->parent->param.grp_lock)
-+	pj_grp_lock_add_ref(ssock->parent->param.grp_lock);
-+
-     /* Update new SSL socket attributes */
-     ssock->sock = newsock;
--    ssock->parent = ssock_parent;
-     ssock->is_server = PJ_TRUE;
-     if (ssock_parent->cert) {
- 	status = pj_ssl_sock_set_certificate(ssock, ssock->pool, 
-@@ -913,16 +931,20 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
-     ssock->asock_rbuf = (void**)pj_pool_calloc(ssock->pool, 
- 					       ssock->param.async_cnt,
- 					       sizeof(void*));
--    if (!ssock->asock_rbuf)
--        return PJ_ENOMEM;
-+    if (!ssock->asock_rbuf) {
-+		status = PJ_ENOMEM;
-+		goto on_return;
-+	}
- 
-     for (i = 0; i<ssock->param.async_cnt; ++i) {
--	ssock->asock_rbuf[i] = (void*) pj_pool_alloc(
-+		ssock->asock_rbuf[i] = (void*) pj_pool_alloc(
- 					    ssock->pool, 
- 					    ssock->param.read_buffer_size + 
- 					    sizeof(read_data_t*));
--        if (!ssock->asock_rbuf[i])
--            return PJ_ENOMEM;
-+		if (!ssock->asock_rbuf[i]) {
-+			status = PJ_ENOMEM;
-+			goto on_return;
-+		}
-     }
- 
-     /* Create active socket */
-diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
-index 17b7ae3de..ce524d53f 100644
---- a/pjsip/src/pjsip/sip_transport_tls.c
-+++ b/pjsip/src/pjsip/sip_transport_tls.c
-@@ -1325,9 +1325,26 @@ static pj_bool_t on_accept_complete2(pj_ssl_sock_t *ssock,
-     PJ_UNUSED_ARG(src_addr_len);
- 
-     listener = (struct tls_listener*) pj_ssl_sock_get_user_data(ssock);
-+    if (!listener) {
-+	/* Listener already destroyed, e.g: after TCP accept but before SSL
-+	 * handshake is completed.
-+	 */
-+	if (new_ssock && accept_status == PJ_SUCCESS) {
-+	    /* Close the SSL socket if the accept op is successful */
-+	    PJ_LOG(4,(THIS_FILE,
-+		      "Incoming TLS connection from %s (sock=%d) is discarded "
-+		      "because listener is already destroyed",
-+		      pj_sockaddr_print(src_addr, addr, sizeof(addr), 3),
-+		      new_ssock));
-+
-+	    pj_ssl_sock_close(new_ssock);
-+	}
-+
-+	return PJ_FALSE;
-+    }
- 
-     if (accept_status != PJ_SUCCESS) {
--	if (listener && listener->tls_setting.on_accept_fail_cb) {
-+	if (listener->tls_setting.on_accept_fail_cb) {
- 	    pjsip_tls_on_accept_fail_param param;
- 	    pj_ssl_sock_info ssi;
- 
-@@ -1350,6 +1367,8 @@ static pj_bool_t on_accept_complete2(pj_ssl_sock_t *ssock,
-     PJ_ASSERT_RETURN(new_ssock, PJ_TRUE);
- 
-     if (!listener->is_registered) {
-+	pj_ssl_sock_close(new_ssock);
-+
- 	if (listener->tls_setting.on_accept_fail_cb) {
- 	    pjsip_tls_on_accept_fail_param param;
- 	    pj_bzero(&param, sizeof(param));
-@@ -1401,6 +1420,8 @@ static pj_bool_t on_accept_complete2(pj_ssl_sock_t *ssock,
- 			 ssl_info.grp_lock, &tls);
-     
-     if (status != PJ_SUCCESS) {
-+	pj_ssl_sock_close(new_ssock);
-+
- 	if (listener->tls_setting.on_accept_fail_cb) {
- 	    pjsip_tls_on_accept_fail_param param;
- 	    pj_bzero(&param, sizeof(param));
diff --git a/third-party/pjproject/patches/0111-ssl-premature-destroy.patch b/third-party/pjproject/patches/0111-ssl-premature-destroy.patch
deleted file mode 100644
index 9de2915..0000000
--- a/third-party/pjproject/patches/0111-ssl-premature-destroy.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-From 68c69f516f95df1faa42e5647e9ce7cfdc41ac38 Mon Sep 17 00:00:00 2001
-From: Nanang Izzuddin <nanang at teluu.com>
-Date: Wed, 16 Jun 2021 12:15:29 +0700
-Subject: [PATCH 2/2] - Fix silly mistake: accepted active socket created
- without group lock in SSL socket. - Replace assertion with normal validation
- check of SSL socket instance in OpenSSL verification callback (verify_cb())
- to avoid crash, e.g: if somehow race condition with SSL socket destroy
- happens or OpenSSL application data index somehow gets corrupted.
-
----
- pjlib/src/pj/ssl_sock_imp_common.c |  3 +-
- pjlib/src/pj/ssl_sock_ossl.c       | 45 +++++++++++++++++++++++++-----
- 2 files changed, 40 insertions(+), 8 deletions(-)
-
-diff --git a/pjlib/src/pj/ssl_sock_imp_common.c b/pjlib/src/pj/ssl_sock_imp_common.c
-index bc468bcb3..c2b8a846b 100644
---- a/pjlib/src/pj/ssl_sock_imp_common.c
-+++ b/pjlib/src/pj/ssl_sock_imp_common.c
-@@ -927,6 +927,7 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
- 
-     /* Create active socket */
-     pj_activesock_cfg_default(&asock_cfg);
-+    asock_cfg.grp_lock = ssock->param.grp_lock;
-     asock_cfg.async_cnt = ssock->param.async_cnt;
-     asock_cfg.concurrency = ssock->param.concurrency;
-     asock_cfg.whole_data = PJ_TRUE;
-@@ -942,7 +943,7 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
- 	    goto on_return;
- 
- 	pj_grp_lock_add_ref(glock);
--	asock_cfg.grp_lock = ssock->param.grp_lock = glock;
-+	ssock->param.grp_lock = glock;
- 	pj_grp_lock_add_handler(ssock->param.grp_lock, ssock->pool, ssock,
- 				ssl_on_destroy);
-     }
-diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
-index a95b339a5..56841f80a 100644
---- a/pjlib/src/pj/ssl_sock_ossl.c
-+++ b/pjlib/src/pj/ssl_sock_ossl.c
-@@ -327,7 +327,8 @@ static pj_status_t STATUS_FROM_SSL_ERR(char *action, pj_ssl_sock_t *ssock,
- 	ERROR_LOG("STATUS_FROM_SSL_ERR", err, ssock);
-     }
- 
--    ssock->last_err = err;
-+    if (ssock)
-+	ssock->last_err = err;
-     return GET_STATUS_FROM_SSL_ERR(err);
- }
- 
-@@ -344,7 +345,8 @@ static pj_status_t STATUS_FROM_SSL_ERR2(char *action, pj_ssl_sock_t *ssock,
-     /* Dig for more from OpenSSL error queue */
-     SSLLogErrors(action, ret, err, len, ssock);
- 
--    ssock->last_err = ssl_err;
-+    if (ssock)
-+	ssock->last_err = ssl_err;
-     return GET_STATUS_FROM_SSL_ERR(ssl_err);
- }
- 
-@@ -587,6 +589,13 @@ static pj_status_t init_openssl(void)
- 
-     /* Create OpenSSL application data index for SSL socket */
-     sslsock_idx = SSL_get_ex_new_index(0, "SSL socket", NULL, NULL, NULL);
-+	if (sslsock_idx == -1) {
-+		status = STATUS_FROM_SSL_ERR2("Init", NULL, -1, ERR_get_error(), 0);
-+		PJ_LOG(1,(THIS_FILE,
-+				  "Fatal error: failed to get application data index for "
-+				  "SSL socket"));
-+		return status;
-+	}
- 
-     return status;
- }
-@@ -614,21 +623,36 @@ static int password_cb(char *buf, int num, int rwflag, void *user_data)
- }
- 
- 
--/* SSL password callback. */
-+/* SSL certificate verification result callback.
-+ * Note that this callback seems to be always called from library worker
-+ * thread, e.g: active socket on_read_complete callback, which should have
-+ * already been equipped with race condition avoidance mechanism (should not
-+ * be destroyed while callback is being invoked).
-+ */
- static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
- {
--    pj_ssl_sock_t *ssock;
--    SSL *ossl_ssl;
-+    pj_ssl_sock_t *ssock = NULL;
-+    SSL *ossl_ssl = NULL;
-     int err;
- 
-     /* Get SSL instance */
-     ossl_ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 
- 				    SSL_get_ex_data_X509_STORE_CTX_idx());
--    pj_assert(ossl_ssl);
-+    if (!ossl_ssl) {
-+	PJ_LOG(1,(THIS_FILE,
-+		  "SSL verification callback failed to get SSL instance"));
-+	goto on_return;
-+    }
- 
-     /* Get SSL socket instance */
-     ssock = SSL_get_ex_data(ossl_ssl, sslsock_idx);
--    pj_assert(ssock);
-+    if (!ssock) {
-+	/* SSL socket may have been destroyed */
-+	PJ_LOG(1,(THIS_FILE,
-+		  "SSL verification callback failed to get SSL socket "
-+		  "instance (sslsock_idx=%d).", sslsock_idx));
-+	goto on_return;
-+    }
- 
-     /* Store verification status */
-     err = X509_STORE_CTX_get_error(x509_ctx);
-@@ -706,6 +730,7 @@ static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
-     if (PJ_FALSE == ssock->param.verify_peer)
- 	preverify_ok = 1;
- 
-+on_return:
-     return preverify_ok;
- }
- 
-@@ -1213,6 +1238,12 @@ static void ssl_destroy(pj_ssl_sock_t *ssock)
- static void ssl_reset_sock_state(pj_ssl_sock_t *ssock)
- {
-     ossl_sock_t *ossock = (ossl_sock_t *)ssock;
-+
-+    /* Detach from SSL instance */
-+    if (ossock->ossl_ssl) {
-+	SSL_set_ex_data(ossock->ossl_ssl, sslsock_idx, NULL);
-+    }
-+
-     /**
-      * Avoid calling SSL_shutdown() if handshake wasn't completed.
-      * OpenSSL 1.0.2f complains if SSL_shutdown() is called during an
diff --git a/third-party/pjproject/patches/0120-pjmedia_sdp_attr_get_rtpmap-Strip-param-trailing-whi.patch b/third-party/pjproject/patches/0120-pjmedia_sdp_attr_get_rtpmap-Strip-param-trailing-whi.patch
deleted file mode 100644
index 1b1fcad..0000000
--- a/third-party/pjproject/patches/0120-pjmedia_sdp_attr_get_rtpmap-Strip-param-trailing-whi.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 2ae784030b0d9cf217c3d562af20e4967f19a3dc Mon Sep 17 00:00:00 2001
-From: George Joseph <gjoseph at sangoma.com>
-Date: Tue, 14 Sep 2021 10:47:29 -0600
-Subject: [PATCH] pjmedia_sdp_attr_get_rtpmap: Strip param trailing whitespace
-
-Use pj_scan_get() to parse the param part of rtpmap so
-trailing whitespace is automatically stripped.
-
-Fixes #2827
----
- pjmedia/src/pjmedia/sdp.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/pjmedia/src/pjmedia/sdp.c b/pjmedia/src/pjmedia/sdp.c
-index 5d05a0d9c..3448749c9 100644
---- a/pjmedia/src/pjmedia/sdp.c
-+++ b/pjmedia/src/pjmedia/sdp.c
-@@ -313,9 +313,9 @@ PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtpmap( const pjmedia_sdp_attr *attr,
- 
- 	/* Expecting either '/' or EOF */
- 	if (*scanner.curptr == '/') {
-+	    /* Skip the '/' */
- 	    pj_scan_get_char(&scanner);
--	    rtpmap->param.ptr = scanner.curptr;
--	    rtpmap->param.slen = scanner.end - scanner.curptr;
-+	    pj_scan_get(&scanner, &cs_token, &rtpmap->param);
- 	} else {
- 	    rtpmap->param.slen = 0;
- 	}
--- 
-2.31.1
-
diff --git a/third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch b/third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch
deleted file mode 100644
index 91feefb..0000000
--- a/third-party/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch
+++ /dev/null
@@ -1,661 +0,0 @@
-From 0ed41eb5fd0e4192e1b7dc374f819d17aef3e805 Mon Sep 17 00:00:00 2001
-From: George Joseph <gtjoseph at 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(-)
-
-diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
-index 14f2d23fa..c33551786 100644
---- 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;
- 
- 
- /**
-@@ -1045,6 +1053,44 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_body(pj_pool_t *pool,
- 					   pjmedia_sdp_session *sdp,
- 					   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
-@@ -1061,6 +1107,60 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_body(pj_pool_t *pool,
- 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
- 
- /**
-diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
-index ca225015b..b68ae0f16 100644
---- 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(pjsip_inv_session *inv,
- 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,
-@@ -946,66 +948,170 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
-     return PJ_SUCCESS;
- }
- 
--PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)
-+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_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;
-+    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;
-+}
- 
--	sdp_info->sdp_err = status;
-+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;
-+
-+    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.
-@@ -1730,13 +1836,55 @@ PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
-     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);
- 
-@@ -2059,6 +2207,7 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
- 	       )
- 	   )
- 	{
-+	    pjsip_sdp_info *tdata_sdp_info;
- 	    const pjmedia_sdp_session *reoffer_sdp = NULL;
- 
- 	    PJ_LOG(4,(inv->obj_name, "Received %s response "
-@@ -2067,14 +2216,15 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
- 		      (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));
-diff --git a/pjsip/src/test/inv_offer_answer_test.c b/pjsip/src/test/inv_offer_answer_test.c
-index ad5fcd409..9cdd2654b 100644
---- 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_session *inv_ses,
- 	    }
- 	}
- 
-+	/* 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_data *rdata)
- 					  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 *param)
- 	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 *param)
-     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
-+    },
- 
- };
- 
--- 
-2.33.1
-
diff --git a/third-party/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch b/third-party/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch
deleted file mode 100644
index 22df638..0000000
--- a/third-party/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch
+++ /dev/null
@@ -1,123 +0,0 @@
-From 3faf1d2b4da553bbaee04f9a13a5d084b381e5fb Mon Sep 17 00:00:00 2001
-From: sauwming <ming at teluu.com>
-Date: Tue, 4 Jan 2022 15:28:49 +0800
-Subject: [PATCH] Fix incorrect unescaping of tokens during parsing (#2933)
-
----
- pjsip/src/pjsip/sip_parser.c | 29 +++++++++++++++++++++++++----
- pjsip/src/test/msg_test.c    |  6 +++---
- 2 files changed, 28 insertions(+), 7 deletions(-)
-
-diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
-index c2add3299..b9a7c6a5c 100644
---- a/pjsip/src/pjsip/sip_parser.c
-+++ b/pjsip/src/pjsip/sip_parser.c
-@@ -378,17 +378,23 @@ static pj_status_t init_parser()
-     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-     pj_cis_add_str( &pconst.pjsip_TOKEN_SPEC, TOKEN);
- 
-+    /* Token is allowed to have '%' so we do not need this. */
-+    /*
-     status = pj_cis_dup(&pconst.pjsip_TOKEN_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC);
-     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-     pj_cis_del_str(&pconst.pjsip_TOKEN_SPEC_ESC, "%");
-+    */
- 
-     status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC, &pconst.pjsip_TOKEN_SPEC);
-     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-     pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC, "[:]");
- 
-+    /* Token is allowed to have '%' */
-+    /*
-     status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC_ESC);
-     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-     pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC_ESC, "[:]");
-+    */
- 
-     status = pj_cis_dup(&pconst.pjsip_HOST_SPEC, &pconst.pjsip_ALNUM_SPEC);
-     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-@@ -1210,7 +1216,11 @@ static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool,
- 			     unsigned option)
- {
-     /* pname */
--    parser_get_and_unescape(scanner, pool, spec, esc_spec, pname);
-+    if (!esc_spec) {
-+    	pj_scan_get(scanner, spec, pname);
-+    } else {
-+	parser_get_and_unescape(scanner, pool, spec, esc_spec, pname);
-+    }
- 
-     /* init pvalue */
-     pvalue->ptr = NULL;
-@@ -1240,7 +1250,12 @@ static void parse_param_imp( pj_scanner *scanner, pj_pool_t *pool,
- 		// pj_scan_get_until_ch(scanner, ']', pvalue);
- 		// pj_scan_get_char(scanner);
- 	    } else if(pj_cis_match(spec, *scanner->curptr)) {
--		parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue);
-+	    	if (!esc_spec) {
-+    		    pj_scan_get(scanner, spec, pvalue);
-+    		} else {
-+		    parser_get_and_unescape(scanner, pool, spec, esc_spec,
-+		    			    pvalue);
-+		}
- 	    }
- 	}
-     }
-@@ -1252,7 +1267,10 @@ PJ_DEF(void) pjsip_parse_param_imp(pj_scanner *scanner, pj_pool_t *pool,
- 			     	   unsigned option)
- {
-     parse_param_imp(scanner, pool, pname, pvalue, &pconst.pjsip_TOKEN_SPEC,
--		    &pconst.pjsip_TOKEN_SPEC_ESC, option);
-+		    // Token does not need to be unescaped.
-+		    // Refer to PR #2933.
-+		    // &pconst.pjsip_TOKEN_SPEC_ESC,
-+		    NULL, option);
- }
- 
- 
-@@ -2168,7 +2186,10 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
- 	pj_scan_get_char(scanner);
- 	parse_param_imp(scanner, pool, &pname, &pvalue,
- 			&pconst.pjsip_VIA_PARAM_SPEC,
--			&pconst.pjsip_VIA_PARAM_SPEC_ESC,
-+		    	// Token does not need to be unescaped.
-+		     	// Refer to PR #2933.
-+		    	// &pconst.pjsip_VIA_PARAM_SPEC_ESC,
-+			NULL,
- 			0);
- 
- 	if (!parser_stricmp(pname, pconst.pjsip_BRANCH_STR) && pvalue.slen) {
-diff --git a/pjsip/src/test/msg_test.c b/pjsip/src/test/msg_test.c
-index c511e1cf6..24e3d405d 100644
---- a/pjsip/src/test/msg_test.c
-+++ b/pjsip/src/test/msg_test.c
-@@ -953,7 +953,7 @@ static int hdr_test_subject_utf(pjsip_hdr *h);
- 
- 
- #define GENERIC_PARAM	     "p0=a;p1=\"ab:;cd\";p2=ab%3acd;p3"
--#define GENERIC_PARAM_PARSED "p0=a;p1=\"ab:;cd\";p2=ab:cd;p3"
-+#define GENERIC_PARAM_PARSED "p0=a;p1=\"ab:;cd\";p2=ab%3acd;p3"
- #define PARAM_CHAR	     "][/:&+$"
- #define SIMPLE_ADDR_SPEC     "sip:host"
- #define ADDR_SPEC	     SIMPLE_ADDR_SPEC ";"PARAM_CHAR"="PARAM_CHAR ";p1=\";\""
-@@ -1401,7 +1401,7 @@ static int generic_param_test(pjsip_param *param_head)
-     param = param->next;
-     if (pj_strcmp2(&param->name, "p2"))
- 	return -956;
--    if (pj_strcmp2(&param->value, "ab:cd"))
-+    if (pj_strcmp2(&param->value, "ab%3acd"))
- 	return -957;
- 
-     param = param->next;
-@@ -1621,7 +1621,7 @@ static int hdr_test_content_type(pjsip_hdr *h)
-     prm = prm->next;
-     if (prm == &hdr->media.param) return -1960;
-     if (pj_strcmp2(&prm->name, "p2")) return -1961;
--    if (pj_strcmp2(&prm->value, "ab:cd")) return -1962;
-+    if (pj_strcmp2(&prm->value, "ab%3acd")) return -1962;
- 
-     prm = prm->next;
-     if (prm == &hdr->media.param) return -1970;
--- 
-2.32.0
-
diff --git a/third-party/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch b/third-party/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch
deleted file mode 100644
index 6ddb346..0000000
--- a/third-party/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch
+++ /dev/null
@@ -1,176 +0,0 @@
-From 7e3dfd8a15fd0f98dbf0e04d2d7a5bded90ee401 Mon Sep 17 00:00:00 2001
-From: George Joseph <gjoseph at sangoma.com>
-Date: Tue, 11 Jan 2022 09:27:23 -0700
-Subject: [PATCH] Create generic pjsip_hdr_find functions
-
-pjsip_msg_find_hdr(), pjsip_msg_find_hdr_by_name(), and
-pjsip_msg_find_hdr_by_names() require a pjsip_msg to be passed in
-so if you need to search a header list that's not in a pjsip_msg,
-you have to do it yourself.  This commit adds generic versions of
-those 3 functions that take in the actual header list head instead
-of a pjsip_msg so if you need to search a list of headers in
-something like a pjsip_multipart_part, you can do so easily.
----
- pjsip/include/pjsip/sip_msg.h | 53 +++++++++++++++++++++++++++++++++++
- pjsip/src/pjsip/sip_msg.c     | 51 +++++++++++++++++++++++----------
- 2 files changed, 89 insertions(+), 15 deletions(-)
-
-diff --git a/pjsip/include/pjsip/sip_msg.h b/pjsip/include/pjsip/sip_msg.h
-index 4c9100d39..e3502e94e 100644
---- a/pjsip/include/pjsip/sip_msg.h
-+++ b/pjsip/include/pjsip/sip_msg.h
-@@ -362,6 +362,59 @@ PJ_DECL(void*) pjsip_hdr_shallow_clone( pj_pool_t *pool, const void *hdr );
-  */
- PJ_DECL(int) pjsip_hdr_print_on( void *hdr, char *buf, pj_size_t len);
- 
-+/**
-+ * Find a header in a header list by the header type.
-+ *
-+ * @param hdr_list  The "head" of the header list.
-+ * @param type      The header type to find.
-+ * @param start     The first header field where the search should begin.
-+ *                  If NULL is specified, then the search will begin from the
-+ *                  first header, otherwise the search will begin at the
-+ *                  specified header.
-+ *
-+ * @return          The header field, or NULL if no header with the specified
-+ *                  type is found.
-+ */
-+PJ_DECL(void*)  pjsip_hdr_find( const void *hdr_list,
-+				pjsip_hdr_e type,
-+				const void *start);
-+
-+/**
-+ * Find a header in a header list by its name.
-+ *
-+ * @param hdr_list  The "head" of the header list.
-+ * @param name      The header name to find.
-+ * @param start     The first header field where the search should begin.
-+ *                  If NULL is specified, then the search will begin from the
-+ *                  first header, otherwise the search will begin at the
-+ *                  specified header.
-+ *
-+ * @return          The header field, or NULL if no header with the specified
-+ *                  type is found.
-+ */
-+PJ_DECL(void*)  pjsip_hdr_find_by_name( const void *hdr_list,
-+					const pj_str_t *name,
-+					const void *start);
-+
-+/**
-+ * Find a header in a header list by its name and short name version.
-+ *
-+ * @param hdr_list  The "head" of the header list.
-+ * @param name      The header name to find.
-+ * @param sname     The short name version of the header name.
-+ * @param start     The first header field where the search should begin.
-+ *                  If NULL is specified, then the search will begin from the
-+ *                  first header, otherwise the search will begin at the
-+ *                  specified header.
-+ *
-+ * @return	    The header field, or NULL if no header with the specified
-+ *		    type is found.
-+ */
-+PJ_DECL(void*)  pjsip_hdr_find_by_names( const void *hdr_list,
-+					 const pj_str_t *name,
-+					 const pj_str_t *sname,
-+					 const void *start);
-+
- /**
-  * @}
-  */
-diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
-index 6ba3054da..2a6a96af0 100644
---- a/pjsip/src/pjsip/sip_msg.c
-+++ b/pjsip/src/pjsip/sip_msg.c
-@@ -356,13 +356,13 @@ PJ_DEF(pjsip_msg*) pjsip_msg_clone( pj_pool_t *pool, const pjsip_msg *src)
-     return dst;
- }
- 
--PJ_DEF(void*)  pjsip_msg_find_hdr( const pjsip_msg *msg, 
--				   pjsip_hdr_e hdr_type, const void *start)
-+PJ_DEF(void*)  pjsip_hdr_find( const void *hdr_list,
-+			       pjsip_hdr_e hdr_type, const void *start)
- {
--    const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=&msg->hdr;
-+    const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=hdr_list;
- 
-     if (hdr == NULL) {
--	hdr = msg->hdr.next;
-+	hdr = end->next;
-     }
-     for (; hdr!=end; hdr = hdr->next) {
- 	if (hdr->type == hdr_type)
-@@ -371,14 +371,14 @@ PJ_DEF(void*)  pjsip_msg_find_hdr( const pjsip_msg *msg,
-     return NULL;
- }
- 
--PJ_DEF(void*)  pjsip_msg_find_hdr_by_name( const pjsip_msg *msg, 
--					   const pj_str_t *name, 
--					   const void *start)
-+PJ_DEF(void*)  pjsip_hdr_find_by_name( const void *hdr_list,
-+				       const pj_str_t *name,
-+				       const void *start)
- {
--    const pjsip_hdr *hdr=(const pjsip_hdr*)start, *end=&msg->hdr;
-+    const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=hdr_list;
- 
-     if (hdr == NULL) {
--	hdr = msg->hdr.next;
-+	hdr = end->next;
-     }
-     for (; hdr!=end; hdr = hdr->next) {
- 	if (pj_stricmp(&hdr->name, name) == 0)
-@@ -387,15 +387,15 @@ PJ_DEF(void*)  pjsip_msg_find_hdr_by_name( const pjsip_msg *msg,
-     return NULL;
- }
- 
--PJ_DEF(void*)  pjsip_msg_find_hdr_by_names( const pjsip_msg *msg, 
--					    const pj_str_t *name, 
--					    const pj_str_t *sname,
--					    const void *start)
-+PJ_DEF(void*)  pjsip_hdr_find_by_names( const void *hdr_list,
-+					const pj_str_t *name,
-+					const pj_str_t *sname,
-+					const void *start)
- {
--    const pjsip_hdr *hdr=(const pjsip_hdr*)start, *end=&msg->hdr;
-+    const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=hdr_list;
- 
-     if (hdr == NULL) {
--	hdr = msg->hdr.next;
-+	hdr = end->next;
-     }
-     for (; hdr!=end; hdr = hdr->next) {
- 	if (pj_stricmp(&hdr->name, name) == 0)
-@@ -406,6 +406,27 @@ PJ_DEF(void*)  pjsip_msg_find_hdr_by_names( const pjsip_msg *msg,
-     return NULL;
- }
- 
-+PJ_DEF(void*)  pjsip_msg_find_hdr( const pjsip_msg *msg,
-+				   pjsip_hdr_e hdr_type, const void *start)
-+{
-+    return pjsip_hdr_find(&msg->hdr, hdr_type, start);
-+}
-+
-+PJ_DEF(void*)  pjsip_msg_find_hdr_by_name( const pjsip_msg *msg,
-+					   const pj_str_t *name,
-+					   const void *start)
-+{
-+    return pjsip_hdr_find_by_name(&msg->hdr, name, start);
-+}
-+
-+PJ_DEF(void*)  pjsip_msg_find_hdr_by_names( const pjsip_msg *msg,
-+					    const pj_str_t *name,
-+					    const pj_str_t *sname,
-+					    const void *start)
-+{
-+    return pjsip_hdr_find_by_names(&msg->hdr, name, sname, start);
-+}
-+
- PJ_DEF(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, 
- 				         pjsip_hdr_e hdr_type, void *start)
- {
--- 
-2.34.1
-
diff --git a/third-party/pjproject/patches/0160-Additional-multipart-improvements.patch b/third-party/pjproject/patches/0160-Additional-multipart-improvements.patch
deleted file mode 100644
index 373f9b8..0000000
--- a/third-party/pjproject/patches/0160-Additional-multipart-improvements.patch
+++ /dev/null
@@ -1,644 +0,0 @@
-From b7ecff22e77887626fd8e8608c4dd73bc7b7366f Mon Sep 17 00:00:00 2001
-From: George Joseph <gjoseph at sangoma.com>
-Date: Tue, 18 Jan 2022 06:14:31 -0700
-Subject: [PATCH] Additional multipart improvements
-
-Added the following APIs:
-pjsip_multipart_find_part_by_header()
-pjsip_multipart_find_part_by_header_str()
-pjsip_multipart_find_part_by_cid_str()
-pjsip_multipart_find_part_by_cid_uri()
----
- pjsip/include/pjsip/sip_multipart.h |  83 ++++++++++
- pjsip/src/pjsip/sip_multipart.c     | 223 +++++++++++++++++++++++++++
- pjsip/src/test/multipart_test.c     | 225 +++++++++++++++++++++++++++-
- 3 files changed, 530 insertions(+), 1 deletion(-)
-
-diff --git a/pjsip/include/pjsip/sip_multipart.h b/pjsip/include/pjsip/sip_multipart.h
-index 1c05767c5..c6b82b0b4 100644
---- a/pjsip/include/pjsip/sip_multipart.h
-+++ b/pjsip/include/pjsip/sip_multipart.h
-@@ -153,6 +153,89 @@ pjsip_multipart_find_part( const pjsip_msg_body *mp,
- 			   const pjsip_media_type *content_type,
- 			   const pjsip_multipart_part *start);
- 
-+/**
-+ * Find a body inside multipart bodies which has a header matching the
-+ * supplied one. Most useful for finding a part with a specific Content-ID.
-+ *
-+ * @param pool		Memory pool to use for temp space.
-+ * @param mp		The multipart body.
-+ * @param search_hdr	Header to search for.
-+ * @param start		If specified, the search will begin at
-+ * 			start->next part. Otherwise it will begin at
-+ * 			the first part in the multipart bodies.
-+ *
-+ * @return		The first part which has a header matching the
-+ * 			specified one, or NULL if not found.
-+ */
-+PJ_DECL(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_header(pj_pool_t *pool,
-+				    const pjsip_msg_body *mp,
-+				    void *search_hdr,
-+				    const pjsip_multipart_part *start);
-+
-+/**
-+ * Find a body inside multipart bodies which has a header matching the
-+ * supplied name and value. Most useful for finding a part with a specific
-+ * Content-ID.
-+ *
-+ * @param pool		Memory pool to use for temp space.
-+ * @param mp		The multipart body.
-+ * @param hdr_name	Header name to search for.
-+ * @param hdr_value	Header value search for.
-+ * @param start		If specified, the search will begin at
-+ * 			start->next part. Otherwise it will begin at
-+ * 			the first part in the multipart bodies.
-+ *
-+ * @return		The first part which has a header matching the
-+ * 			specified one, or NULL if not found.
-+ */
-+PJ_DECL(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_header_str(pj_pool_t *pool,
-+				    const pjsip_msg_body *mp,
-+				    const pj_str_t *hdr_name,
-+				    const pj_str_t *hdr_value,
-+				    const pjsip_multipart_part *start);
-+
-+
-+
-+/**
-+ * Find a body inside multipart bodies which has a Content-ID value matching the
-+ * supplied "cid" URI in pj_str form.  The "cid:" scheme will be assumed if the
-+ * URL doesn't start with it.  Enclosing angle brackets will also be handled
-+ * correctly if they exist.
-+ *
-+ * @see RFC2392 Content-ID and Message-ID Uniform Resource Locators
-+ *
-+ * @param pool	Memory pool to use for temp space.
-+ * @param mp	The multipart body.
-+ * @param cid	The "cid" URI to search for in pj_str form.
-+ *
-+ * @return		The first part which has a Content-ID header matching the
-+ * 			specified "cid" URI. or NULL if not found.
-+ */
-+PJ_DECL(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_cid_str(pj_pool_t *pool,
-+				 const pjsip_msg_body *mp,
-+				 pj_str_t *cid);
-+
-+/**
-+ * Find a body inside multipart bodies which has a Content-ID value matching the
-+ * supplied "cid" URI.
-+ *
-+ * @see RFC2392 Content-ID and Message-ID Uniform Resource Locators
-+ *
-+ * @param pool	Memory pool to use for temp space.
-+ * @param mp	The multipart body.
-+ * @param cid	The "cid" URI to search for.
-+ *
-+ * @return		The first part which had a Content-ID header matching the
-+ * 			specified "cid" URI. or NULL if not found.
-+ */
-+PJ_DECL(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_cid_uri(pj_pool_t *pool,
-+				 const pjsip_msg_body *mp,
-+				 pjsip_other_uri *cid_uri);
-+
- /**
-  * Parse multipart message.
-  *
-diff --git a/pjsip/src/pjsip/sip_multipart.c b/pjsip/src/pjsip/sip_multipart.c
-index e7d722d2e..9d8be55b0 100644
---- a/pjsip/src/pjsip/sip_multipart.c
-+++ b/pjsip/src/pjsip/sip_multipart.c
-@@ -19,6 +19,7 @@
- #include <pjsip/sip_multipart.h>
- #include <pjsip/sip_parser.h>
- #include <pjlib-util/scanner.h>
-+#include <pjlib-util/string.h>
- #include <pj/assert.h>
- #include <pj/ctype.h>
- #include <pj/errno.h>
-@@ -416,6 +417,220 @@ pjsip_multipart_find_part( const pjsip_msg_body *mp,
-     return NULL;
- }
- 
-+/*
-+ * Find a body inside multipart bodies which has the header and value.
-+ */
-+PJ_DEF(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_header_str(pj_pool_t *pool,
-+				    const pjsip_msg_body *mp,
-+				    const pj_str_t *hdr_name,
-+				    const pj_str_t *hdr_value,
-+				    const pjsip_multipart_part *start)
-+{
-+    struct multipart_data *m_data;
-+    pjsip_multipart_part *part;
-+    pjsip_hdr *found_hdr;
-+    pj_str_t found_hdr_str;
-+    pj_str_t found_hdr_value;
-+    pj_size_t expected_hdr_slen;
-+    pj_size_t buf_size;
-+    int hdr_name_len;
-+#define REASONABLE_PADDING 32
-+#define SEPARATOR_LEN 2
-+    /* Must specify mandatory params */
-+    PJ_ASSERT_RETURN(mp && hdr_name && hdr_value, NULL);
-+
-+    /* mp must really point to an actual multipart msg body */
-+    PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL);
-+
-+    /*
-+     * We'll need to "print" each header we find to test it but
-+     * allocating a buffer of PJSIP_MAX_URL_SIZE is overkill.
-+     * Instead, we'll allocate one large enough to hold the search
-+     * header name, the ": " separator, the search hdr value, and
-+     * the NULL terminator.  If we can't print the found header
-+     * into that buffer then it can't be a match.
-+     *
-+     * Some header print functions such as generic_int require enough
-+     * space to print the maximum possible header length so we'll
-+     * add a reasonable amount to the print buffer size.
-+     */
-+    expected_hdr_slen = hdr_name->slen + SEPARATOR_LEN + hdr_value->slen;
-+    buf_size = expected_hdr_slen + REASONABLE_PADDING;
-+    found_hdr_str.ptr = pj_pool_alloc(pool, buf_size);
-+    found_hdr_str.slen = 0;
-+    hdr_name_len = hdr_name->slen + SEPARATOR_LEN;
-+
-+    m_data = (struct multipart_data*)mp->data;
-+
-+    if (start)
-+	part = start->next;
-+    else
-+	part = m_data->part_head.next;
-+
-+    while (part != &m_data->part_head) {
-+	found_hdr = NULL;
-+	while ((found_hdr = pjsip_hdr_find_by_name(&part->hdr, hdr_name,
-+	    (found_hdr ? found_hdr->next : NULL))) != NULL) {
-+
-+	    found_hdr_str.slen = pjsip_hdr_print_on((void*) found_hdr, found_hdr_str.ptr, buf_size);
-+	    /*
-+	     * If the buffer was too small (slen = -1) or the result wasn't
-+	     * the same length as the search header, it can't be a match.
-+	     */
-+	    if (found_hdr_str.slen != expected_hdr_slen) {
-+		continue;
-+	    }
-+	    /*
-+	     * Set the value overlay to start at the found header value...
-+	     */
-+	    found_hdr_value.ptr = found_hdr_str.ptr + hdr_name_len;
-+	    found_hdr_value.slen = found_hdr_str.slen - hdr_name_len;
-+	    /* ...and compare it to the supplied header value. */
-+	    if (pj_strcmp(hdr_value, &found_hdr_value) == 0) {
-+		return part;
-+	    }
-+	}
-+	part = part->next;
-+    }
-+    return NULL;
-+#undef SEPARATOR_LEN
-+#undef REASONABLE_PADDING
-+}
-+
-+PJ_DEF(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_header(pj_pool_t *pool,
-+				    const pjsip_msg_body *mp,
-+				    void *search_for,
-+				    const pjsip_multipart_part *start)
-+{
-+    struct multipart_data *m_data;
-+    pjsip_hdr *search_hdr = search_for;
-+    pj_str_t search_buf;
-+
-+    /* Must specify mandatory params */
-+    PJ_ASSERT_RETURN(mp && search_hdr, NULL);
-+
-+    /* mp must really point to an actual multipart msg body */
-+    PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL);
-+
-+    /*
-+     * Unfortunately, there isn't enough information to determine
-+     * the maximum printed size of search_hdr at this point so we
-+     * have to allocate a reasonable max.
-+     */
-+    search_buf.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-+    search_buf.slen = pjsip_hdr_print_on(search_hdr, search_buf.ptr, PJSIP_MAX_URL_SIZE - 1);
-+    if (search_buf.slen <= 0) {
-+	return NULL;
-+    }
-+    /*
-+     * Set the header value to start after the header name plus the ":", then
-+     * strip leading and trailing whitespace.
-+     */
-+    search_buf.ptr += (search_hdr->name.slen + 1);
-+    search_buf.slen -= (search_hdr->name.slen + 1);
-+    pj_strtrim(&search_buf);
-+
-+    return pjsip_multipart_find_part_by_header_str(pool, mp, &search_hdr->name, &search_buf, start);
-+}
-+
-+/*
-+ * Convert a Content-ID URI to it's corresponding header value.
-+ * RFC2392 says...
-+ * A "cid" URL is converted to the corresponding Content-ID message
-+ * header by removing the "cid:" prefix, converting the % encoded
-+ * character(s) to their equivalent US-ASCII characters, and enclosing
-+ * the remaining parts with an angle bracket pair, "<" and ">".
-+ *
-+ * This implementation will accept URIs with or without the "cid:"
-+ * scheme and optional angle brackets.
-+ */
-+static pj_str_t cid_uri_to_hdr_value(pj_pool_t *pool, pj_str_t *cid_uri)
-+{
-+    pj_size_t cid_len = pj_strlen(cid_uri);
-+    pj_size_t alloc_len = cid_len + 2 /* for the leading and trailing angle brackets */;
-+    pj_str_t uri_overlay;
-+    pj_str_t cid_hdr;
-+    pj_str_t hdr_overlay;
-+
-+    pj_strassign(&uri_overlay, cid_uri);
-+    /* If the URI is already enclosed in angle brackets, remove them. */
-+    if (uri_overlay.ptr[0] == '<') {
-+	uri_overlay.ptr++;
-+	uri_overlay.slen -= 2;
-+    }
-+    /* If the URI starts with the "cid:" scheme, skip over it. */
-+    if (pj_strncmp2(&uri_overlay, "cid:", 4) == 0) {
-+	uri_overlay.ptr += 4;
-+	uri_overlay.slen -= 4;
-+    }
-+    /* Start building */
-+    cid_hdr.ptr = pj_pool_alloc(pool, alloc_len);
-+    cid_hdr.ptr[0] = '<';
-+    cid_hdr.slen = 1;
-+    hdr_overlay.ptr = cid_hdr.ptr + 1;
-+    hdr_overlay.slen = 0;
-+    pj_strcpy_unescape(&hdr_overlay, &uri_overlay);
-+    cid_hdr.slen += hdr_overlay.slen;
-+    cid_hdr.ptr[cid_hdr.slen] = '>';
-+    cid_hdr.slen++;
-+
-+    return cid_hdr;
-+}
-+
-+PJ_DEF(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_cid_str(pj_pool_t *pool,
-+				 const pjsip_msg_body *mp,
-+				 pj_str_t *cid)
-+{
-+    struct multipart_data *m_data;
-+    pjsip_multipart_part *part;
-+    pjsip_generic_string_hdr *found_hdr;
-+    pj_str_t found_hdr_value;
-+    static pj_str_t hdr_name = { "Content-ID", 10};
-+    pj_str_t hdr_value;
-+
-+    PJ_ASSERT_RETURN(pool && mp && cid && (pj_strlen(cid) > 0), NULL);
-+
-+    hdr_value = cid_uri_to_hdr_value(pool, cid);
-+    if (pj_strlen(&hdr_value) == 0) {
-+	return NULL;
-+    }
-+
-+    m_data = (struct multipart_data*)mp->data;
-+    part = m_data->part_head.next;
-+
-+    while (part != &m_data->part_head) {
-+	found_hdr = NULL;
-+	while ((found_hdr = pjsip_hdr_find_by_name(&part->hdr, &hdr_name,
-+	    (found_hdr ? found_hdr->next : NULL))) != NULL) {
-+	    if (pj_strcmp(&hdr_value, &found_hdr->hvalue) == 0) {
-+		return part;
-+	    }
-+	}
-+	part = part->next;
-+    }
-+    return NULL;
-+}
-+
-+PJ_DEF(pjsip_multipart_part*)
-+pjsip_multipart_find_part_by_cid_uri(pj_pool_t *pool,
-+				 const pjsip_msg_body *mp,
-+				 pjsip_other_uri *cid_uri)
-+{
-+    PJ_ASSERT_RETURN(pool && mp && cid_uri, NULL);
-+
-+    if (pj_strcmp2(&cid_uri->scheme, "cid") != 0) {
-+	return NULL;
-+    }
-+    /*
-+     * We only need to pass the URI content so we
-+     * can do that directly.
-+     */
-+    return pjsip_multipart_find_part_by_cid_str(pool, mp, &cid_uri->content);
-+}
-+
- /* Parse a multipart part. "pct" is parent content-type  */
- static pjsip_multipart_part *parse_multipart_part(pj_pool_t *pool,
- 						  char *start,
-@@ -584,6 +799,7 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
- 		(int)boundary.slen, boundary.ptr));
-     }
- 
-+
-     /* Build the delimiter:
-      *   delimiter = "--" boundary
-      */
-@@ -630,6 +846,8 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
- 	if (*curptr=='\r') ++curptr;
- 	if (*curptr!='\n') {
- 	    /* Expecting a newline here */
-+	    PJ_LOG(2, (THIS_FILE, "Failed to find newline"));
-+
- 	    return NULL;
- 	}
- 	++curptr;
-@@ -645,6 +863,7 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
- 	    curptr = pj_strstr(&subbody, &delim);
- 	    if (!curptr) {
- 		/* We're really expecting end delimiter to be found. */
-+		PJ_LOG(2, (THIS_FILE, "Failed to find end-delimiter"));
- 		return NULL;
- 	    }
- 	}
-@@ -670,9 +889,13 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
- 	part = parse_multipart_part(pool, start_body, end_body - start_body,
- 				    ctype);
- 	if (part) {
-+	    TRACE_((THIS_FILE, "Adding part"));
- 	    pjsip_multipart_add_part(pool, body, part);
-+	} else {
-+	    PJ_LOG(2, (THIS_FILE, "Failed to add part"));
- 	}
-     }
-+    TRACE_((THIS_FILE, "pjsip_multipart_parse finished: %p", body));
- 
-     return body;
- }
-diff --git a/pjsip/src/test/multipart_test.c b/pjsip/src/test/multipart_test.c
-index 4f16e68bf..97267a290 100644
---- a/pjsip/src/test/multipart_test.c
-+++ b/pjsip/src/test/multipart_test.c
-@@ -28,6 +28,7 @@
- typedef pj_status_t (*verify_ptr)(pj_pool_t*,pjsip_msg_body*);
- 
- static pj_status_t verify1(pj_pool_t *pool, pjsip_msg_body *body);
-+static pj_status_t verify2(pj_pool_t *pool, pjsip_msg_body *body);
- 
- static struct test_t
- {
-@@ -68,7 +69,41 @@ static struct test_t
- 		"This is epilogue, which should be ignored too",
- 
- 		&verify1
-+	},
-+	{
-+		/* Content-type */
-+		"multipart", "mixed", "12345",
-+
-+		/* Body: */
-+		"This is the prolog, which should be ignored.\r\n"
-+		"--12345\r\n"
-+		"Content-Type: text/plain\r\n"
-+		"Content-ID: <header1 at example.org>\r\n"
-+		"Content-ID: <\"header1\"@example.org>\r\n"
-+		"Content-Length: 13\r\n"
-+		"\r\n"
-+		"has header1\r\n"
-+		"--12345 \t\r\n"
-+		"Content-Type: application/pidf+xml\r\n"
-+		"Content-ID: <my header2 at example.org>\r\n"
-+		"Content-ID: <my\xffheader2 at example.org>\r\n"
-+		"Content-Length: 13\r\n"
-+		"\r\n"
-+		"has header2\r\n"
-+		"--12345\r\n"
-+		"Content-Type: text/plain\r\n"
-+		"Content-ID: <my header3 at example.org>\r\n"
-+		"Content-ID: <header1 at example.org>\r\n"
-+		"Content-ID: <my header4 at example.org>\r\n"
-+		"Content-Length: 13\r\n"
-+		"\r\n"
-+		"has header4\r\n"
-+		"--12345--\r\n"
-+		"This is epilogue, which should be ignored too",
-+
-+		&verify2
- 	}
-+
- };
- 
- static void init_media_type(pjsip_media_type *mt,
-@@ -87,6 +122,192 @@ static void init_media_type(pjsip_media_type *mt,
-     }
- }
- 
-+static int verify_hdr(pj_pool_t *pool, pjsip_msg_body *multipart_body,
-+    void *hdr, char *part_body)
-+{
-+    pjsip_media_type mt;
-+    pjsip_multipart_part *part;
-+    pj_str_t the_body;
-+
-+
-+    part = pjsip_multipart_find_part_by_header(pool, multipart_body, hdr, NULL);
-+    if (!part) {
-+	return -1;
-+    }
-+
-+    the_body.ptr = (char*)part->body->data;
-+    the_body.slen = part->body->len;
-+
-+    if (pj_strcmp2(&the_body, part_body) != 0) {
-+	return -2;
-+    }
-+
-+    return 0;
-+}
-+
-+static int verify_cid_str(pj_pool_t *pool, pjsip_msg_body *multipart_body,
-+    pj_str_t cid_url, char *part_body)
-+{
-+    pjsip_media_type mt;
-+    pjsip_multipart_part *part;
-+    pj_str_t the_body;
-+
-+    part = pjsip_multipart_find_part_by_cid_str(pool, multipart_body, &cid_url);
-+    if (!part) {
-+	return -3;
-+    }
-+
-+    the_body.ptr = (char*)part->body->data;
-+    the_body.slen = part->body->len;
-+
-+    if (pj_strcmp2(&the_body, part_body) != 0) {
-+	return -4;
-+    }
-+
-+    return 0;
-+}
-+
-+static int verify_cid_uri(pj_pool_t *pool, pjsip_msg_body *multipart_body,
-+    pjsip_other_uri *cid_uri, char *part_body)
-+{
-+    pjsip_media_type mt;
-+    pjsip_multipart_part *part;
-+    pj_str_t the_body;
-+
-+    part = pjsip_multipart_find_part_by_cid_uri(pool, multipart_body, cid_uri);
-+    if (!part) {
-+	return -5;
-+    }
-+
-+    the_body.ptr = (char*)part->body->data;
-+    the_body.slen = part->body->len;
-+
-+    if (pj_strcmp2(&the_body, part_body) != 0) {
-+	return -6;
-+    }
-+
-+    return 0;
-+}
-+
-+static pj_status_t verify2(pj_pool_t *pool, pjsip_msg_body *body)
-+{
-+    int rc = 0;
-+    int rcbase = 300;
-+    pjsip_other_uri *cid_uri;
-+    pjsip_ctype_hdr *ctype_hdr = pjsip_ctype_hdr_create(pool);
-+
-+    ctype_hdr->media.type = pj_str("application");
-+    ctype_hdr->media.subtype = pj_str("pidf+xml");
-+
-+    rc = verify_hdr(pool, body, ctype_hdr, "has header2");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("cid:header1 at example.org"), "has header1");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("%22header1%22 at example.org"), "has header1");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "<cid:%22header1%22 at example.org>",
-+	strlen("<cid:%22header1%22 at example.org>"), 0));
-+    rcbase += 10;
-+    rc = verify_cid_uri(pool, body, cid_uri, "has header1");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("<cid:my%20header2 at example.org>"), "has header2");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("cid:my%ffheader2 at example.org"), "has header2");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "<cid:my%ffheader2 at example.org>",
-+	strlen("<cid:my%ffheader2 at example.org>"), 0));
-+    rcbase += 10;
-+    rc = verify_cid_uri(pool, body, cid_uri, "has header2");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("cid:my%20header3 at example.org"), "has header4");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("<cid:my%20header4 at example.org>"), "has header4");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "<cid:my%20header4 at example.org>",
-+	strlen("<cid:my%20header4 at example.org>"), 0));
-+    rcbase += 10;
-+    rc = verify_cid_uri(pool, body, cid_uri, "has header4");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("<my%20header3 at example.org>"), "has header4");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    /* These should all fail for malformed or missing URI */
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("cid:"), "has header4");
-+    if (!rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str(""), "has header4");
-+    if (!rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("<>"), "has header4");
-+    if (!rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("<cid>"), "has header4");
-+    if (!rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    /*
-+     * This is going to pass but the ' ' in the uri is un-encoded which is invalid
-+     * so we should never see it.
-+     */
-+    rcbase += 10;
-+    rc = verify_cid_str(pool, body, pj_str("cid:my header3 at example.org"), "has header4");
-+    if (rc) {
-+	return (rc - rcbase);
-+    }
-+
-+    return 0;
-+}
-+
- static int verify_part(pjsip_multipart_part *part,
- 		       char *h_content_type,
- 		       char *h_content_subtype,
-@@ -236,8 +457,10 @@ static int parse_test(void)
- 
- 	pj_strdup2_with_null(pool, &str, p_tests[i].msg);
- 	body = pjsip_multipart_parse(pool, str.ptr, str.slen, &ctype, 0);
--	if (!body)
-+	if (!body) {
-+	    pj_pool_release(pool);
- 	    return -100;
-+	}
- 
- 	if (p_tests[i].verify) {
- 	    rc = p_tests[i].verify(pool, body);
--- 
-2.34.1
-
diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h
index 5884108..1cde66e 100644
--- a/third-party/pjproject/patches/config_site.h
+++ b/third-party/pjproject/patches/config_site.h
@@ -87,3 +87,7 @@
  */
 #define PJSIP_TCP_KEEP_ALIVE_INTERVAL	0
 #define PJSIP_TLS_KEEP_ALIVE_INTERVAL	0
+
+#define PJSIP_TSX_UAS_CONTINUE_ON_TP_ERROR 0
+#define PJ_SSL_SOCK_OSSL_USE_THREAD_CB 0
+#define PJSIP_AUTH_ALLOW_MULTIPLE_AUTH_HEADER 1
diff --git a/third-party/pjproject/pjproject-2.10.tar.bz2.md5 b/third-party/pjproject/pjproject-2.10.tar.bz2.md5
deleted file mode 100644
index 57261b4..0000000
--- a/third-party/pjproject/pjproject-2.10.tar.bz2.md5
+++ /dev/null
@@ -1,2 +0,0 @@
-5d0202f79a7aeb14873c45b0e4c14a70 *pjproject-2.10.zip
-4fffc49b461133f0a4143b05a22fb30e  pjproject-2.10.tar.bz2
diff --git a/third-party/pjproject/pjproject-2.12.tar.bz2.md5 b/third-party/pjproject/pjproject-2.12.tar.bz2.md5
new file mode 100644
index 0000000..ab9b9d4
--- /dev/null
+++ b/third-party/pjproject/pjproject-2.12.tar.bz2.md5
@@ -0,0 +1 @@
+ad796d38f5f0357cb5b2fe1b4460b581  pjproject-2.12.tar.bz2
diff --git a/third-party/versions.mak b/third-party/versions.mak
index 2a59cf4..b95d687 100644
--- a/third-party/versions.mak
+++ b/third-party/versions.mak
@@ -1,2 +1,2 @@
 JANSSON_VERSION = 2.14
-PJPROJECT_VERSION = 2.10
+PJPROJECT_VERSION = 2.12

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/18114
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: Id39ece02dedb7b9f739e0e37ea47d76854af7191
Gerrit-Change-Number: 18114
Gerrit-PatchSet: 4
Gerrit-Owner: Joshua Colp <jcolp at sangoma.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20220330/a1d81a75/attachment-0001.html>


More information about the asterisk-code-review mailing list