fix(ristsender): enable --rtp-sequence and --rtp-timestamp extraction

The RTP seq/timestamp extraction in input_udp_recv was disabled since
be32351 (2020) with a "TODO: Figure out why this does not work" comment.

The root cause was a buffer offset bug: recvfrom writes the UDP payload
at recv_buf + ipheader_bytes, but the extraction code read recv_buf[2..7]
— the reserved IP-header prefix area — returning garbage.
This commit is contained in:
Sergio Ammirata
2026-05-23 15:35:57 -04:00
parent 88467c0e4e
commit aa141517a3
4 changed files with 39 additions and 17 deletions
+5
View File
@@ -41,6 +41,11 @@ Bug Fixes:
refused to start the SRP/AES code paths in those environments
rather than silently downgrade. Fixes #210.
Tools:
- ristsender now preserves incoming RTP sequence numbers and
timestamps when the --rtp-sequence and --rtp-timestamp options
are used. Previously these options had no effect.
Hardening / follow-ups to 0.2.15:
- EAP-SRP authentication retry exhaustion did not drop the failed
+3
View File
@@ -64,6 +64,9 @@ test('Main profile receive client mode, sender server mode packet loss 25%', tes
test('Main profile encryption receive server mode, sender client mode', test_send_receive, args: ['1', 'rist://@127.0.0.1:6001?secret=12345678&aes-type=128', 'rist://127.0.0.1:6001?secret=12345678&aes-type=128', '0'],suite: ['main', 'unicast', 'server', 'encryption'])
test('Main profile encryption receive client mode, sender server mode ', test_send_receive, args: ['1', 'rist://127.0.0.1:6002?secret=12345678&aes-type=128', 'rist://@127.0.0.1:6002?secret=12345678&aes-type=128', '0'],suite: ['main', 'unicast', 'client', 'encryption'])
test('Main profile encryption receive client mode, sender server mode AES256 ', test_send_receive, args: ['1', 'rist://127.0.0.1:6007?secret=12345678&aes-type=256', 'rist://@127.0.0.1:6007?secret=12345678&aes-type=256', '0'],suite: ['main', 'unicast', 'client', 'encryption'])
#Caller-controlled seq (RIST_DATA_FLAGS_USE_SEQ) passthrough
test('Main profile USE_SEQ passthrough', test_send_receive, args: ['1', 'rist://@127.0.0.1:6020?rtt-max=10&rtt-min=1', 'rist://127.0.0.1:6020?rtt-max=10&rtt-min=1', '0', '0', '1'], suite: ['main', 'unicast', 'use_seq'])
test('Main profile USE_SEQ passthrough 10% loss', test_send_receive, args: ['1', 'rist://@127.0.0.1:6021?rtt-max=10&rtt-min=1', 'rist://127.0.0.1:6021?rtt-max=10&rtt-min=1', '10', '0', '1'], suite: ['main', 'unicast', 'use_seq'])
#Encryption tests where 1 side has enabled encryption these should fail
test('Main profile encryption receive server mode unencrypted, sender client mode', test_send_receive, args: ['1', 'rist://@127.0.0.1:6003', 'rist://127.0.0.1:6003?secret=12345678&aes-type=128', '0'], should_fail: true)
test('Main profile encryption receive server mode, sender client mode unencrypted', test_send_receive, args: ['1', 'rist://@127.0.0.1:6004?secret=12345678&aes-type=128', 'rist://127.0.0.1:6004', '0'], should_fail: true)
+20 -3
View File
@@ -8,6 +8,7 @@
#include "librist/librist.h"
#include "rist-private.h"
#include <stdatomic.h>
#include <inttypes.h>
#include "mpegts.h"
#include "endian-shim.h"
@@ -17,6 +18,8 @@
atomic_ulong failed;
atomic_ulong stop;
int use_seq = 0;
#define USE_SEQ_START 1000
struct rist_logging_settings *logging_settings_sender = NULL;
struct rist_logging_settings *logging_settings_receiver = NULL;
@@ -143,10 +146,15 @@ static PTHREAD_START_FUNC(send_data, arg) {
else {
hdr->flags1 = htobe16(0x1111);
}
sprintf(&buffer[offset+sizeof(*hdr)+1], "DEADBEAF TEST PACKET #%i-%i", send_counter, ts);
int pkt_id = use_seq ? (send_counter + USE_SEQ_START) : send_counter;
sprintf(&buffer[offset+sizeof(*hdr)+1], "DEADBEAF TEST PACKET #%i-%i", pkt_id, ts);
}
data.payload = &buffer;
data.payload_len = 188 * random_num;
if (use_seq) {
data.flags = RIST_DATA_FLAGS_USE_SEQ;
data.seq = (uint64_t)(send_counter + USE_SEQ_START);
}
int ret = rist_sender_data_write(rist_sender, &data);
if (ret < 0) {
fprintf(stderr, "Failed to send test packet with error code %d!\n", ret);
@@ -179,7 +187,7 @@ static PTHREAD_START_FUNC(send_data, arg) {
}
int main(int argc, char *argv[]) {
if (argc != 5 && argc != 6) {
if (argc < 5 || argc > 7) {
return 99;
}
int profile = atoi(argv[1]);
@@ -189,8 +197,10 @@ int main(int argc, char *argv[]) {
int npd = 0;
int ret = 0;
if (argc == 6)
if (argc >= 6)
npd = atoi(argv[5]);
if (argc >= 7)
use_seq = atoi(argv[6]);
struct rist_ctx *receiver_ctx = NULL;
struct rist_ctx *sender_ctx = NULL;
@@ -249,6 +259,13 @@ int main(int argc, char *argv[]) {
if (!got_first) {
receive_count = (int)b->seq;
got_first = true;
if (use_seq && (int)b->seq < USE_SEQ_START) {
fprintf(stderr, "USE_SEQ: first seq %"PRIu64" < expected start %d, "
"sender-supplied seq was not preserved\n",
b->seq, USE_SEQ_START);
atomic_store(&failed, 1);
atomic_store(&stop, 1);
}
}
// Check entire mpegts structure
int tsindex = (int)(b->payload_len / 188);
+11 -14
View File
@@ -193,16 +193,14 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n"
" --statsinterval 1000 \\\n"
" --verbose-level 6 \n";
/*
static uint64_t risttools_convertRTPtoNTP(uint32_t i_rtp)
{
uint64_t i_ntp;
int32_t clock = 90000;
i_ntp = (uint64_t)i_rtp << 32;
i_ntp /= clock;
int32_t clock = 90000;
i_ntp = (uint64_t)i_rtp << 32;
i_ntp /= clock;
return i_ntp;
}
*/
#if HAVE_SRP_SUPPORT
char *srpfile = NULL;
@@ -243,20 +241,19 @@ static void input_udp_recv(struct evsocket_ctx *evctx, int fd, short revents, vo
// If we wanted to be more accurate, we could use the kernel nic capture timestamp (linux)
data_block.ts_ntp = 0;
data_block.flags = 0;
uint8_t *rtp_hdr = recv_buf + ipheader_bytes;
if (callback_object->udp_config->rtp_timestamp && recv_bufsize > 12)
{
// Extract timestamp from rtp header
//uint32_t rtp_time = (recv_buf[4] << 24) | (recv_buf[5] << 16) | (recv_buf[6] << 8) | recv_buf[7];
// Convert to NTP (assumes 90Khz)
//data_block.ts_ntp = risttools_convertRTPtoNTP(rtp_time);
// TODO: Figure out why this does not work (commenting out for now)
uint32_t rtp_time = ((uint32_t)rtp_hdr[4] << 24) |
((uint32_t)rtp_hdr[5] << 16) |
((uint32_t)rtp_hdr[6] << 8) |
(uint32_t)rtp_hdr[7];
data_block.ts_ntp = risttools_convertRTPtoNTP(rtp_time);
}
if (callback_object->udp_config->rtp_sequence && recv_bufsize > 12)
{
// Extract sequence number from rtp header
//data_block.seq = (uint64_t)((recv_buf[2] << 8) | recv_buf[3]);
//data_block.flags = RIST_DATA_FLAGS_USE_SEQ;
// TODO: Figure out why this does not work (commenting out for now)
data_block.seq = (uint64_t)(((uint16_t)rtp_hdr[2] << 8) | rtp_hdr[3]);
data_block.flags = RIST_DATA_FLAGS_USE_SEQ;
}
if (callback_object->udp_config->version == 1 && callback_object->udp_config->multiplex_mode == LIBRIST_MULTIPLEX_MODE_IPV4) {
data_block.virt_src_port = UINT16_MAX;