From 79d3c4e325ee1becb43307112f5ab644a6670bd5 Mon Sep 17 00:00:00 2001 From: Dmitry Verenitsin Date: Thu, 28 May 2026 16:31:18 +0500 Subject: [PATCH] Capture HEP messages after parsing instead of per recv HEP capture fired in each transport's recv hook, on the raw recv buffer. For a datagram that buffer is a whole message, but on a stream (TCP/TLS/WS/SCTP) one `recv` returns an arbitrary slice of the byte stream, so capture emitted byte fragments that did not align with SIP message boundaries: several HEP packets per message, each starting mid-message. Move capture into `tport_deliver()`, which runs once per fully parsed message, and rebuild the wire image with `msg_iovec()`. The five per-transport capture calls are removed. Now every transport produces exactly one HEP packet per SIP message, starting at the request or status line. For `msg_iovec()` to reproduce the header bytes the parser must keep the wire image, so `tport_msg_alloc()` sets `MSG_DO_EXTRACT_COPY` while the capture socket is open; a `tp_rcaptured` marker dedupes the per-message delivery, mirroring `tp_rlogged`. --- libsofia-sip-ua/tport/tport.c | 40 +++++++++++++++++++++++-- libsofia-sip-ua/tport/tport_internal.h | 1 + libsofia-sip-ua/tport/tport_type_sctp.c | 3 -- libsofia-sip-ua/tport/tport_type_tcp.c | 4 --- libsofia-sip-ua/tport/tport_type_tls.c | 3 -- libsofia-sip-ua/tport/tport_type_udp.c | 3 -- libsofia-sip-ua/tport/tport_type_ws.c | 3 -- 7 files changed, 39 insertions(+), 18 deletions(-) diff --git a/libsofia-sip-ua/tport/tport.c b/libsofia-sip-ua/tport/tport.c index 339d8e384..06ce0852a 100644 --- a/libsofia-sip-ua/tport/tport.c +++ b/libsofia-sip-ua/tport/tport.c @@ -102,6 +102,11 @@ static char const __func__[] = "tport"; #define TP_STACK tp_master->mr_stack +/* Upper bound on how much of a received message is reassembled for HEP + * capture. Large or heavily fragmented messages may be captured truncated; + * raise this if that happens. */ +#define TPORT_CAPT_IOVMAX 80 + /* Define macros for rbtree implementation */ #define TP_LEFT(tp) ((tp)->tp_left) #define TP_RIGHT(tp) ((tp)->tp_right) @@ -2743,8 +2748,17 @@ msg_t *tport_msg_alloc(tport_t const *self, usize_t size) { if (self) { tport_master_t *mr = self->tp_master; - msg_t *msg = mr->mr_tpac->tpac_alloc(mr->mr_stack, mr->mr_log, - NULL, size, self, NULL); + int flags = mr->mr_log; + msg_t *msg; + + /* Capture rebuilds the payload via msg_iovec(), which needs the + * header wire image that only MSG_DO_EXTRACT_COPY preserves. */ + if (mr->mr_capt_sock) { + flags |= MSG_DO_EXTRACT_COPY; + } + + msg = mr->mr_tpac->tpac_alloc(mr->mr_stack, flags, + NULL, size, self, NULL); if (msg) { su_addrinfo_t *mai = msg_addrinfo(msg); su_addrinfo_t const *tai = self->tp_addrinfo; @@ -3056,6 +3070,8 @@ static void tport_parse(tport_t *self, int complete, su_time_t now) if (self->tp_rlogged != msg) self->tp_rlogged = NULL; + if (self->tp_rcaptured != msg) + self->tp_rcaptured = NULL; self->tp_msg = msg; } @@ -3115,6 +3131,26 @@ void tport_deliver(tport_t *self, self->tp_rlogged = msg; } + /* Capture needs the wire image MSG_FLG_EXTRACT_COPY preserves; messages + * allocated before capture was enabled lack it, so skip them. */ + if (!error && self->tp_master->mr_capt_sock && msg != self->tp_rcaptured + && msg_get_flags(msg, MSG_FLG_EXTRACT_COPY)) { + msg_iovec_t iov[TPORT_CAPT_IOVMAX]; + size_t i, iovlen = msg_iovec(msg, iov, TPORT_CAPT_IOVMAX); + size_t bytes = 0; + + for (i = 0; i < iovlen && i < TPORT_CAPT_IOVMAX; i++) { + bytes += iov[i].mv_len; + } + + if (bytes > 0) { + tport_capt_msg(self, msg, bytes, iov, + iovlen < TPORT_CAPT_IOVMAX ? iovlen : TPORT_CAPT_IOVMAX, + "recv"); + } + self->tp_rcaptured = msg; + } + SU_DEBUG_7(("%s(%p): %smsg %p ("MOD_ZU" bytes)" " from " TPN_FORMAT " next=%p\n", __func__, (void *)self, error ? "bad " : "", diff --git a/libsofia-sip-ua/tport/tport_internal.h b/libsofia-sip-ua/tport/tport_internal.h index e77d175d9..b24430c0f 100644 --- a/libsofia-sip-ua/tport/tport_internal.h +++ b/libsofia-sip-ua/tport/tport_internal.h @@ -212,6 +212,7 @@ struct tport_s { msg_t *tp_msg; /**< Message being received */ msg_t const *tp_rlogged; /**< Last logged when receiving */ + msg_t const *tp_rcaptured; /**< Last HEP-captured when receiving */ su_time_t tp_rtime; /**< Last time received data */ unsigned short tp_ping; /**< Whitespace ping being received */ diff --git a/libsofia-sip-ua/tport/tport_type_sctp.c b/libsofia-sip-ua/tport/tport_type_sctp.c index fba193c95..470178fdf 100644 --- a/libsofia-sip-ua/tport/tport_type_sctp.c +++ b/libsofia-sip-ua/tport/tport_type_sctp.c @@ -260,9 +260,6 @@ int tport_recv_sctp(tport_t *self) if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, N, iovec, veclen, "recv", "from"); - if (self->tp_master->mr_capt_sock) - tport_capt_msg(self, msg, N, iovec, veclen, "recv"); - msg_recv_commit(msg, N, 0); /* Mark buffer as used */ return 2; diff --git a/libsofia-sip-ua/tport/tport_type_tcp.c b/libsofia-sip-ua/tport/tport_type_tcp.c index db3a76ac6..d4af27c02 100644 --- a/libsofia-sip-ua/tport/tport_type_tcp.c +++ b/libsofia-sip-ua/tport/tport_type_tcp.c @@ -353,10 +353,6 @@ int tport_recv_stream(tport_t *self) /* Write the received data to the message dump file */ if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); - - if (self->tp_master->mr_capt_sock) - tport_capt_msg(self, msg, n, iovec, veclen, "recv"); - /* Mark buffer as used */ msg_recv_commit(msg, n, n == 0); diff --git a/libsofia-sip-ua/tport/tport_type_tls.c b/libsofia-sip-ua/tport/tport_type_tls.c index 2418e87cb..2f3643a44 100644 --- a/libsofia-sip-ua/tport/tport_type_tls.c +++ b/libsofia-sip-ua/tport/tport_type_tls.c @@ -468,9 +468,6 @@ int tport_tls_recv(tport_t *self) if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); - if (self->tp_master->mr_capt_sock) - tport_capt_msg(self, msg, n, iovec, veclen, "recv"); - /* Mark buffer as used */ msg_recv_commit(msg, N, 0); diff --git a/libsofia-sip-ua/tport/tport_type_udp.c b/libsofia-sip-ua/tport/tport_type_udp.c index 5a1715b3e..8d0f2de71 100644 --- a/libsofia-sip-ua/tport/tport_type_udp.c +++ b/libsofia-sip-ua/tport/tport_type_udp.c @@ -362,9 +362,6 @@ int tport_recv_dgram(tport_t *self) if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); - - if (self->tp_master->mr_capt_sock) - tport_capt_msg(self, msg, n, iovec, veclen, "recv"); *sample = *((uint8_t *)iovec[0].mv_base); diff --git a/libsofia-sip-ua/tport/tport_type_ws.c b/libsofia-sip-ua/tport/tport_type_ws.c index a62ec2287..0d6906632 100644 --- a/libsofia-sip-ua/tport/tport_type_ws.c +++ b/libsofia-sip-ua/tport/tport_type_ws.c @@ -253,9 +253,6 @@ int tport_recv_stream_ws(tport_t *self) if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); - if (self->tp_master->mr_capt_sock) - tport_capt_msg(self, msg, n, iovec, veclen, "recv"); - /* Mark buffer as used */ msg_recv_commit(msg, N, 0);