diff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml
index e3792a5ab..3926a9084 100644
--- a/.github/workflows/abi.yml
+++ b/.github/workflows/abi.yml
@@ -1,6 +1,12 @@
 name: ABI Checks
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   abicheck:
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index fc73f06a5..a1b2cb479 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -1,6 +1,15 @@
 name: Android
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
+
+env:
+  openssl: 3.2.1
 
 jobs:
   android:
@@ -9,11 +18,18 @@ jobs:
     steps:
     - uses: actions/checkout@v4
 
+    - uses: actions/cache@v4
+      id: openssl
+      with:
+        path: openssl
+        key: ${{ runner.os }}-android-openssl-${{ env.openssl }}
+
     - name: "build openssl"
+      if: steps.openssl.outputs.cache-hit != 'true'
       run: |
-        wget -q https://www.openssl.org/source/openssl-3.2.0.tar.gz
-        tar -xzf openssl-3.2.0.tar.gz
-        mv openssl-3.2.0 openssl
+        wget -q https://www.openssl.org/source/openssl-$openssl.tar.gz
+        tar -xzf openssl-$openssl.tar.gz
+        mv openssl-$openssl openssl
         cd openssl && ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME PATH=$ANDROID_NDK_LATEST_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH ./Configure android-arm64 no-shared no-tests -U__ANDROID_API__ -D__ANDROID_API__=21 && PATH=$ANDROID_NDK_LATEST_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH make build_libs && cd ..
 
     - name: build
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index cf5baf6fb..5d4e1dd44 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -21,7 +21,7 @@ jobs:
       uses: actions/checkout@v4
 
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v2
+      uses: github/codeql-action/init@v3
       with:
         languages: cpp
         queries: security-extended
@@ -34,5 +34,5 @@ jobs:
         cmake -B build && cmake --build build
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v2
+      uses: github/codeql-action/analyze@v3
 
diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml
index 75fa3e069..6415e43dc 100644
--- a/.github/workflows/ios.yml
+++ b/.github/workflows/ios.yml
@@ -1,6 +1,12 @@
 name: iOS
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   ios:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 68d68d01a..fe39d96e4 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -1,6 +1,12 @@
 name: lint
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   lint:
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index 64d765139..2b6a1f95f 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -1,6 +1,12 @@
 name: MinGW-w64 Test
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   MinGW-w64-build:
@@ -32,7 +38,7 @@ jobs:
       with:
         path: baresip-win32/re
 
-    - uses: actions/cache@v2
+    - uses: actions/cache@v4
       id: openssl
       with:
         path: baresip-win32/openssl
@@ -50,7 +56,7 @@ jobs:
       run: |
         cd baresip-win32 && make retest
     
-    - uses: actions/upload-artifact@v2
+    - uses: actions/upload-artifact@v4
       with:
         name: retest-exe
         path: baresip-win32/re/build/test/retest.exe
@@ -62,7 +68,7 @@ jobs:
 
     steps:
     - uses: actions/checkout@v4
-    - uses: actions/download-artifact@v2
+    - uses: actions/download-artifact@v4
     - uses: sreimers/pr-dependency-action@v0.6
       with:
         name: re
diff --git a/.github/workflows/run-on-arch.yml b/.github/workflows/run-on-arch.yml
index 6be3488ce..5a2c66137 100644
--- a/.github/workflows/run-on-arch.yml
+++ b/.github/workflows/run-on-arch.yml
@@ -1,4 +1,10 @@
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   build_job:
diff --git a/.github/workflows/ssl.yml b/.github/workflows/ssl.yml
index 510346c89..39822f776 100644
--- a/.github/workflows/ssl.yml
+++ b/.github/workflows/ssl.yml
@@ -1,6 +1,12 @@
 name: OpenSSL no-deprecated and LibreSSL
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   ssl:
diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml
index 6cfa3a44e..201a5fa15 100644
--- a/.github/workflows/valgrind.yml
+++ b/.github/workflows/valgrind.yml
@@ -1,6 +1,12 @@
 name: valgrind leak check
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+    branches:
+    - main
 
 jobs:
   valgrind:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58f299ab1..e8fc0b66c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,39 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 
+## [v3.9.0] - 2024-01-31
+
+## What's Changed
+* http: fix doxygen by @cspiel1 in https://github.com/baresip/re/pull/1033
+* types: remove old ARRAY_SIZE macro by @alfredh in https://github.com/baresip/re/pull/1034
+* cmake: bump minimum to version 3.14 by @alfredh in https://github.com/baresip/re/pull/1030
+* test: use re_is_aligned() by @alfredh in https://github.com/baresip/re/pull/1035
+* sipsess: refactor and simplify SDP negotiation state by @maximilianfridrich in https://github.com/baresip/re/pull/1016
+* bump year by @sreimers in https://github.com/baresip/re/pull/1038
+* cmake,pc: fix static library build by @alfredh in https://github.com/baresip/re/pull/1036
+* rx thread activate by @cspiel1 in https://github.com/baresip/re/pull/1037
+* test: fix cppcheck warnings by @alfredh in https://github.com/baresip/re/pull/1040
+* test: move test_rtcp_decode_badmsg() to separate testcase by @alfredh in https://github.com/baresip/re/pull/1041
+* rtp: lock more fields from rtcp_sess by @cspiel1 in https://github.com/baresip/re/pull/1039
+* rtp: lock rtcp_set_srate() by @cspiel1 in https://github.com/baresip/re/pull/1043
+* test: HAVE_INET6 is always defined by @alfredh in https://github.com/baresip/re/pull/1046
+* ci: add run-on-arch for ARM64 linux by @alfredh in https://github.com/baresip/re/pull/1045
+* httpauth: digest verification rfc 7616 by @cHuberCoffee in https://github.com/baresip/re/pull/1044
+* tmr: prevent race condition on cancel by @sreimers in https://github.com/baresip/re/pull/1048
+* aubuf: fix coverity defect by @alfredh in https://github.com/baresip/re/pull/1051
+* btrace: fix coverity warning by @alfredh in https://github.com/baresip/re/pull/1049
+* ci/win: downgrade openssl by @sreimers in https://github.com/baresip/re/pull/1054
+* docs: update README by @alfredh in https://github.com/baresip/re/pull/1053
+* http: client - set scopeid fixes HTTP requests for IPv6ll by @cspiel1 in https://github.com/baresip/re/pull/1055
+* rtp: add rtp_source_ prefix to RTP source api by @alfredh in https://github.com/baresip/re/pull/1052
+* rtp: make struct rtp_source public by @alfredh in https://github.com/baresip/re/pull/1057
+* rtp: sess - fix coverity warning by @cspiel1 in https://github.com/baresip/re/pull/1058
+* mk: bump version to 3.9.0 by @alfredh in https://github.com/baresip/re/pull/1060
+
+
+**Full Changelog**: https://github.com/baresip/re/compare/v3.8.0...v3.9.0
+
+
 ## [v3.8.0] - 2023-12-27
 
 ## What's Changed
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 355355ec0..6f9af1f6e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,13 +14,13 @@
 cmake_minimum_required(VERSION 3.14)
 
 project(re
-  VERSION 3.8.0
+  VERSION 3.9.0
   LANGUAGES C
   HOMEPAGE_URL https://github.com/baresip/re
   DESCRIPTION "Generic library for real-time communications"
 )
 
-set(PROJECT_SOVERSION 20) # bump if ABI breaks
+set(PROJECT_SOVERSION 21) # bump if ABI breaks
 
 # Pre-release identifier, comment out on a release
 # Increment for breaking changes (dev2, dev3...)
@@ -242,6 +242,7 @@ set(SRCS
   src/fmt/regex.c
   src/fmt/str.c
   src/fmt/str_error.c
+  src/fmt/text2pcap.c
   src/fmt/time.c
   src/fmt/unicode.c
 
diff --git a/include/re_fmt.h b/include/re_fmt.h
index af4cd1841..ff694dea5 100644
--- a/include/re_fmt.h
+++ b/include/re_fmt.h
@@ -179,9 +179,10 @@ static inline bool str_isset(const char *s)
 
 
 /* time */
-int  fmt_gmtime(struct re_printf *pf, void *ts);
-int  fmt_timestamp(struct re_printf *pf, void *ts);
-int  fmt_human_time(struct re_printf *pf, const uint32_t *seconds);
+int fmt_gmtime(struct re_printf *pf, void *ts);
+int fmt_timestamp(struct re_printf *pf, void *ts);
+int fmt_timestamp_us(struct re_printf *pf, void *arg);
+int fmt_human_time(struct re_printf *pf, const uint32_t *seconds);
 
 
 void hexdump(FILE *f, const void *p, size_t len);
@@ -202,3 +203,15 @@ void fmt_param_apply(const struct pl *pl, fmt_param_h *ph, void *arg);
 int utf8_encode(struct re_printf *pf, const char *str);
 int utf8_decode(struct re_printf *pf, const struct pl *pl);
 size_t utf8_byteseq(char u[4], unsigned cp);
+
+
+/* text2pcap */
+struct re_text2pcap {
+	bool in;
+	const struct mbuf *mb;
+	const char *id;
+};
+
+int re_text2pcap(struct re_printf *pf, struct re_text2pcap *pcap);
+void re_text2pcap_trace(const char *name, const char *id, bool in,
+			const struct mbuf *mb);
diff --git a/include/re_sipsess.h b/include/re_sipsess.h
index ad4f11544..b1f0087e1 100644
--- a/include/re_sipsess.h
+++ b/include/re_sipsess.h
@@ -7,13 +7,13 @@
 struct sipsess_sock;
 struct sipsess;
 
-/* SDP Negotiation state */
+/** SDP Negotiation state */
 enum sdp_neg_state {
 	SDP_NEG_NONE = 0,
-	SDP_NEG_LOCAL_OFFER,		/** SDP offer sent */
-	SDP_NEG_REMOTE_OFFER,		/** SDP offer received */
-	SDP_NEG_PREVIEW_ANSWER,		/** SDP preview answer sent */
-	SDP_NEG_DONE			/** SDP negotiation done */
+	SDP_NEG_LOCAL_OFFER,		/**< SDP offer sent */
+	SDP_NEG_REMOTE_OFFER,		/**< SDP offer received */
+	SDP_NEG_PREVIEW_ANSWER,		/**< SDP preview answer sent */
+	SDP_NEG_DONE			/**< SDP negotiation done */
 };
 
 
diff --git a/include/re_tls.h b/include/re_tls.h
index dcfc62958..61e28548f 100644
--- a/include/re_tls.h
+++ b/include/re_tls.h
@@ -69,10 +69,12 @@ int tls_srtp_keyinfo(const struct tls_conn *tc, enum srtp_suite *suite,
 const char *tls_cipher_name(const struct tls_conn *tc);
 int tls_set_ciphers(struct tls *tls, const char *cipherv[], size_t count);
 int tls_set_verify_server(struct tls_conn *tc, const char *host);
+int tls_verify_client(struct tls_conn *tc);
 
 int tls_get_issuer(struct tls *tls, struct mbuf *mb);
 int tls_get_subject(struct tls *tls, struct mbuf *mb);
 void tls_disable_verify_server(struct tls *tls);
+void tls_enable_verify_client(struct tls *tls, bool enable);
 
 int tls_set_min_proto_version(struct tls *tls, int version);
 int tls_set_max_proto_version(struct tls *tls, int version);
diff --git a/mk/Doxyfile b/mk/Doxyfile
index 8ee292170..fcca5223e 100644
--- a/mk/Doxyfile
+++ b/mk/Doxyfile
@@ -4,7 +4,7 @@
 # Project related configuration options
 #---------------------------------------------------------------------------
 PROJECT_NAME           = libre
-PROJECT_NUMBER         = 3.8.0
+PROJECT_NUMBER         = 3.9.0
 OUTPUT_DIRECTORY       = ../re-dox
 CREATE_SUBDIRS         = NO
 OUTPUT_LANGUAGE        = English
diff --git a/rem/aufile/aufile.c b/rem/aufile/aufile.c
index f5ceb7eaa..8f18e0a35 100644
--- a/rem/aufile/aufile.c
+++ b/rem/aufile/aufile.c
@@ -271,6 +271,7 @@ size_t aufile_get_length(struct aufile *af, const struct aufile_prm *prm)
  *
  * @param af  Audio-file
  * @param prm Audio file parameters from aufile_open
+ * @param pos_ms Playing position in milliseconds
  *
  * @return 0 if success, otherwise errorcode
  */
diff --git a/src/fmt/text2pcap.c b/src/fmt/text2pcap.c
new file mode 100644
index 000000000..d131323fa
--- /dev/null
+++ b/src/fmt/text2pcap.c
@@ -0,0 +1,47 @@
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_trace.h>
+#include <re_mem.h>
+
+
+int re_text2pcap(struct re_printf *pf, struct re_text2pcap *pcap)
+{
+	if (!pcap)
+		return EINVAL;
+
+	uint8_t *buf = mbuf_buf(pcap->mb);
+	if (!buf)
+		return EINVAL;
+
+	re_hprintf(pf, "%s %H 000000", pcap->in ? "I" : "O", fmt_timestamp_us,
+		   NULL);
+
+	size_t sz = mbuf_get_left(pcap->mb);
+	for (size_t i = 0; i < sz; i++) {
+		re_hprintf(pf, " %02x", buf[i]);
+	}
+
+	re_hprintf(pf, " %s", pcap->id);
+
+	return 0;
+}
+
+
+void re_text2pcap_trace(const char *name, const char *id, bool in,
+			const struct mbuf *mb)
+{
+	struct re_text2pcap pcap = {.in = in, .mb = mb, .id = id};
+	size_t pcap_buf_sz = (mbuf_get_left(mb) * 3) + 64;
+
+	char *pcap_buf = mem_alloc(pcap_buf_sz, NULL);
+	if (!pcap_buf)
+		return;
+
+	re_snprintf(pcap_buf, pcap_buf_sz, "%H", re_text2pcap, &pcap);
+
+	re_trace_event("pcap", name, 'I', NULL, RE_TRACE_ARG_STRING_COPY,
+		       "pcap", pcap_buf);
+
+	mem_deref(pcap_buf);
+}
diff --git a/src/fmt/time.c b/src/fmt/time.c
index a0001fd89..76410c438 100644
--- a/src/fmt/time.c
+++ b/src/fmt/time.c
@@ -4,6 +4,10 @@
  * Copyright (C) 2010 Creytiv.com
  */
 
+#ifdef __MINGW32__
+#define _POSIX_C_SOURCE 200809L
+#endif
+
 #include <time.h>
 
 #ifdef WIN32
@@ -129,3 +133,39 @@ int fmt_timestamp(struct re_printf *pf, void *arg)
 
 	return re_hprintf(pf, "%02u:%02u:%02u.%03llu", h, m, s, ms);
 }
+
+
+/**
+ * Print local time stamp including microseconds relative to user's timezone
+ *
+ * @param pf  Print function for output
+ * @param arg Not used
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int fmt_timestamp_us(struct re_printf *pf, void *arg)
+{
+	int h, m, s;
+	uint64_t us;
+	struct timespec tspec;
+	struct tm tm;
+
+#if defined(WIN32) && !defined(__MINGW32__)
+	timespec_get(&tspec, TIME_UTC);
+	int err = localtime_s(&tm, &tspec.tv_sec);
+	if (err)
+		return err;
+#else
+	(void)clock_gettime(CLOCK_REALTIME, &tspec);
+	if (!localtime_r(&tspec.tv_sec, &tm))
+		return EINVAL;
+#endif
+
+	h  = tm.tm_hour;
+	m  = tm.tm_min;
+	s  = tm.tm_sec;
+	us = tspec.tv_nsec / 1000;
+	(void)arg;
+
+	return re_hprintf(pf, "%02u:%02u:%02u.%06llu", h, m, s, us);
+}
diff --git a/src/rtp/rtp.c b/src/rtp/rtp.c
index 76d73cf5f..e889f86c8 100644
--- a/src/rtp/rtp.c
+++ b/src/rtp/rtp.c
@@ -17,7 +17,6 @@
 #include <re_atomic.h>
 #include "rtcp.h"
 
-
 #define DEBUG_MODULE "rtp"
 #define DEBUG_LEVEL 5
 #include <re_dbg.h>
@@ -167,6 +166,10 @@ static void rtcp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg)
 	struct rtp_sock *rs = arg;
 	struct rtcp_msg *msg;
 
+#ifdef RE_RTP_PCAP
+	re_text2pcap_trace("rtcp_recv", "RTCP", true, mb);
+#endif
+
 	while (0 == rtcp_decode(&msg, mb)) {
 
 		/* handle internally first */
@@ -202,10 +205,15 @@ static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg)
 		}
 	}
 
+#ifdef RE_RTP_PCAP
+	re_text2pcap_trace("rtp_udp_recv", "RTP", true, mb);
+#endif
+
 	err = rtp_decode(rs, mb, &hdr);
 	if (err)
 		return;
 
+
 	if (rs->rtcp)
 		rtcp_sess_rx_rtp(rs->rtcp, &hdr, mbuf_get_left(mb), src);
 
@@ -525,6 +533,10 @@ int rtp_send(struct rtp_sock *rs, const struct sa *dst, bool ext,
 
 	mb->pos = pos;
 
+#ifdef RE_RTP_PCAP
+	re_text2pcap_trace("rtp_send", "RTP", false, mb);
+#endif
+
 	return udp_send(rs->sock_rtp, dst, mb);
 }
 
@@ -569,6 +581,10 @@ int rtp_resend(struct rtp_sock *rs, uint16_t seq, const struct sa *dst,
 
 	mb->pos = pos;
 
+#ifdef RE_RTP_PCAP
+	re_text2pcap_trace("rtp_resend", "RTP", false, mb);
+#endif
+
 	return udp_send(rs->sock_rtp, dst, mb);
 }
 
@@ -704,6 +720,9 @@ int rtcp_send(struct rtp_sock *rs, struct mbuf *mb)
 	if (!sock || !sa_isset(&rs->rtcp_peer, SA_ALL))
 		return EINVAL;
 
+#ifdef RE_RTP_PCAP
+	re_text2pcap_trace("rtcp_send", "RTCP", false, mb);
+#endif
 	return udp_send(sock, &rs->rtcp_peer, mb);
 }
 
diff --git a/src/sip/transp.c b/src/sip/transp.c
index ada515522..eb6062fd6 100644
--- a/src/sip/transp.c
+++ b/src/sip/transp.c
@@ -261,15 +261,14 @@ static void conn_close(struct sip_conn *conn, int err)
 
 		struct sip_connqent *qent = le->data;
 		le = le->next;
-
-		if (qent->qentp) {
-			*qent->qentp = NULL;
-			qent->qentp = NULL;
-		}
+		bool qentp_set = qent->qentp ? true : false;
 
 		qent->transph(err, qent->arg);
-		list_unlink(&qent->le);
-		mem_deref(qent);
+
+		if (!qentp_set) {
+			list_unlink(&qent->le);
+			mem_deref(qent);
+		}
 	}
 
 	sip_keepalive_signal(&conn->kal, err);
@@ -618,13 +617,9 @@ static void tcp_estab_handler(void *arg)
 	while (le) {
 
 		struct sip_connqent *qent = le->data;
+		bool qentp_set = qent->qentp ? true : false;
 		le = le->next;
 
-		if (qent->qentp) {
-			*qent->qentp = NULL;
-			qent->qentp = NULL;
-		}
-
 		trace_send(conn->sip,
 			   conn->sc ? SIP_TRANSP_TLS : SIP_TRANSP_TCP,
 			   conn,
@@ -634,8 +629,10 @@ static void tcp_estab_handler(void *arg)
 		if (err)
 			qent->transph(err, qent->arg);
 
-		list_unlink(&qent->le);
-		mem_deref(qent);
+		if (!qentp_set) {
+			list_unlink(&qent->le);
+			mem_deref(qent);
+		}
 	}
 }
 
@@ -682,6 +679,10 @@ static void tcp_connect_handler(const struct sa *paddr, void *arg)
 		err = tls_start_tcp(&conn->sc, transp->tls, conn->tc, 0);
 		if (err)
 			goto out;
+
+		err = tls_verify_client(conn->sc);
+		if (err)
+			goto out;
 	}
 #endif
 
@@ -896,13 +897,9 @@ static void websock_estab_handler(void *arg)
 	while (le) {
 
 		struct sip_connqent *qent = le->data;
+		bool qentp_set = qent->qentp ? true : false;
 		le = le->next;
 
-		if (qent->qentp) {
-			*qent->qentp = NULL;
-			qent->qentp = NULL;
-		}
-
 		trace_send(conn->sip,
 			   conn->tp,
 			   conn,
@@ -917,8 +914,10 @@ static void websock_estab_handler(void *arg)
 		if (err)
 			qent->transph(err, qent->arg);
 
-		list_unlink(&qent->le);
-		mem_deref(qent);
+		if (!qentp_set) {
+			list_unlink(&qent->le);
+			mem_deref(qent);
+		}
 	}
 }
 
diff --git a/src/tls/openssl/tls.c b/src/tls/openssl/tls.c
index ac1f5b676..a5b983ae9 100644
--- a/src/tls/openssl/tls.c
+++ b/src/tls/openssl/tls.c
@@ -45,6 +45,7 @@ struct tls {
 	X509 *cert;
 	char *pass;          /**< password for private key             */
 	bool verify_server;  /**< Enable SIP TLS server verification   */
+	bool verify_client;  /**< Enable SIP TLS client verification   */
 	struct session_reuse reuse;
 	struct list certs;   /**< Certificates for SNI selection       */
 };
@@ -1459,6 +1460,35 @@ int tls_set_verify_server(struct tls_conn *tc, const char *host)
 }
 
 
+/**
+ * Enable verification of client certificate
+ *
+ * @param tc   TLS Connection
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int tls_verify_client(struct tls_conn *tc)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER)
+
+	if (!tc)
+		return EINVAL;
+
+	if (!tc->tls->verify_client)
+		return 0;
+
+	SSL_set_verify(tc->ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
+		       tls_verify_handler);
+
+	return 0;
+#else
+	(void)tc;
+
+	return ENOSYS;
+#endif
+}
+
+
 static int print_error(const char *str, size_t len, void *unused)
 {
 	(void)unused;
@@ -1597,6 +1627,21 @@ void tls_disable_verify_server(struct tls *tls)
 }
 
 
+/**
+ * Enables SIP TLS client verifications for following requests
+ *
+ * @param tls     TLS Object
+ * @param enable  true to enable client verification, false to disable
+ */
+void tls_enable_verify_client(struct tls *tls, bool enable)
+{
+	if (!tls)
+		return;
+
+	tls->verify_client = enable;
+}
+
+
 /**
  * Set minimum TLS version
  *
diff --git a/src/trace/trace.c b/src/trace/trace.c
index 832d0f977..397d48989 100644
--- a/src/trace/trace.c
+++ b/src/trace/trace.c
@@ -164,7 +164,7 @@ int re_trace_init(const char *json_file)
 	trace.event_buffer_flush = mem_zalloc(
 		TRACE_BUFFER_SIZE * sizeof(struct trace_event), NULL);
 	if (!trace.event_buffer_flush) {
-		mem_deref(trace.event_buffer);
+		trace.event_buffer = mem_deref(trace.event_buffer);
 		return ENOMEM;
 	}
 
@@ -191,8 +191,8 @@ int re_trace_init(const char *json_file)
 out:
 	if (err) {
 		re_atomic_rlx_set(&trace.init, false);
-		mem_deref(trace.event_buffer);
-		mem_deref(trace.event_buffer_flush);
+		trace.event_buffer	 = mem_deref(trace.event_buffer);
+		trace.event_buffer_flush = mem_deref(trace.event_buffer_flush);
 	}
 
 	return err;
@@ -245,12 +245,12 @@ int re_trace_close(void)
 int re_trace_flush(void)
 {
 #ifdef RE_TRACE_ENABLED
-	int i, flush_count;
+	int flush_count;
 	struct trace_event *event_tmp;
 	struct trace_event *e;
-	char json_arg[256] = {0};
-	char name[128]	   = {0};
-	char id_str[128]   = {0};
+	char *json_arg;
+	char name[128]	 = {0};
+	char id_str[128] = {0};
 
 	if (!re_atomic_rlx(&trace.init))
 		return 0;
@@ -264,7 +264,21 @@ int re_trace_flush(void)
 	trace.event_count = 0;
 	mtx_unlock(&trace.lock);
 
-	for (i = 0; i < flush_count; i++)
+	size_t json_arg_sz = 4096;
+	json_arg = mem_zalloc(json_arg_sz, NULL);
+	if (!json_arg) {
+		for (int i = 0; i < flush_count; i++) {
+			e = &trace.event_buffer_flush[i];
+			if (e->arg_type == RE_TRACE_ARG_STRING_COPY)
+				mem_deref((void *)e->arg.a_str);
+
+			if (e->id)
+				mem_deref(e->id);
+		}
+		return ENOMEM;
+	}
+
+	for (int i = 0; i < flush_count; i++)
 	{
 		e = &trace.event_buffer_flush[i];
 
@@ -273,17 +287,17 @@ int re_trace_flush(void)
 			json_arg[0] = '\0';
 			break;
 		case RE_TRACE_ARG_INT:
-			(void)re_snprintf(json_arg, sizeof(json_arg),
+			(void)re_snprintf(json_arg, json_arg_sz,
 					", \"args\":{\"%s\":%i}",
 					e->arg_name, e->arg.a_int);
 			break;
 		case RE_TRACE_ARG_STRING_CONST:
-			(void)re_snprintf(json_arg, sizeof(json_arg),
+			(void)re_snprintf(json_arg, json_arg_sz,
 					", \"args\":{\"%s\":\"%s\"}",
 					e->arg_name, e->arg.a_str);
 			break;
 		case RE_TRACE_ARG_STRING_COPY:
-			(void)re_snprintf(json_arg, sizeof(json_arg),
+			(void)re_snprintf(json_arg, json_arg_sz,
 					", \"args\":{\"%s\":\"%s\"}",
 					e->arg_name, e->arg.a_str);
 
@@ -310,6 +324,8 @@ int re_trace_flush(void)
 		trace.new = false;
 	}
 
+	mem_deref(json_arg);
+
 	(void)fflush(trace.f);
 	return 0;
 #else
diff --git a/test/fmt.c b/test/fmt.c
index 7b82deebb..297346c3f 100644
--- a/test/fmt.c
+++ b/test/fmt.c
@@ -1158,3 +1158,30 @@ int test_fmt_hexdump(void)
 
 	return 0;
 }
+
+
+int test_text2pcap(void)
+{
+	char test[64];
+	struct mbuf *mb;
+	int err = 0;
+
+	mb = mbuf_alloc(2);
+	if (!mb)
+		return ENOMEM;
+
+	mbuf_write_u8(mb, 42);
+	mbuf_write_u8(mb, 23);
+
+	mbuf_set_pos(mb, 0);
+
+	struct re_text2pcap pcap = {.id = "test", .in = true, .mb = mb};
+
+	int ret = re_snprintf(test, sizeof(test), "%H", re_text2pcap, &pcap);
+
+	TEST_EQUALS(35, ret);
+
+out:
+	mem_deref(mb);
+	return err;
+}
diff --git a/test/test.c b/test/test.c
index 261c1d96f..6bfc024f9 100644
--- a/test/test.c
+++ b/test/test.c
@@ -214,6 +214,7 @@ static const struct test tests[] = {
 	TEST(test_sys_getenv),
 	TEST(test_tcp),
 	TEST(test_telev),
+	TEST(test_text2pcap),
 #ifdef USE_TLS
 	TEST(test_tls),
 	TEST(test_tls_ec),
diff --git a/test/test.h b/test/test.h
index 68a681e2c..cee4a3401 100644
--- a/test/test.h
+++ b/test/test.h
@@ -330,6 +330,7 @@ int test_sys_fs_fopen(void);
 int test_sys_getenv(void);
 int test_tcp(void);
 int test_telev(void);
+int test_text2pcap(void);
 int test_thread(void);
 int test_thread_cnd_timedwait(void);
 int test_tmr_jiffies(void);
diff --git a/test/trace.c b/test/trace.c
index be85c828e..6966be3e2 100644
--- a/test/trace.c
+++ b/test/trace.c
@@ -67,5 +67,7 @@ int test_trace(void)
 #endif
 
 out:
+	if (err)
+		re_trace_close();
 	return err;
 }