From 55d280becc3f3633e12efba2df4f28dc3dbe4e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 20 Jan 2023 10:37:08 +0100 Subject: [PATCH 001/231] SRT --- configure.ac | 3 + examples/Makefile.am | 10 +- examples/rist_rx.c | 443 +++----- examples/rist_tx.c | 469 ++++---- include/Makefile.am | 2 +- include/upipe-srt/Makefile.am | 5 + include/upipe-srt/upipe_srt_handshake.h | 92 ++ include/upipe-srt/upipe_srt_receiver.h | 51 + include/upipe-srt/upipe_srt_sender.h | 51 + lib/Makefile.am | 3 +- lib/upipe-modules/Makefile.am | 5 + lib/upipe-srt/Makefile.am | 18 + lib/upipe-srt/libupipe_srt.pc.in | 11 + lib/upipe-srt/upipe_srt_handshake.c | 1345 +++++++++++++++++++++++ lib/upipe-srt/upipe_srt_receiver.c | 1147 +++++++++++++++++++ lib/upipe-srt/upipe_srt_sender.c | 748 +++++++++++++ 16 files changed, 3843 insertions(+), 560 deletions(-) create mode 100644 include/upipe-srt/Makefile.am create mode 100644 include/upipe-srt/upipe_srt_handshake.h create mode 100644 include/upipe-srt/upipe_srt_receiver.h create mode 100644 include/upipe-srt/upipe_srt_sender.h create mode 100644 lib/upipe-srt/Makefile.am create mode 100644 lib/upipe-srt/libupipe_srt.pc.in create mode 100644 lib/upipe-srt/upipe_srt_handshake.c create mode 100644 lib/upipe-srt/upipe_srt_receiver.c create mode 100644 lib/upipe-srt/upipe_srt_sender.c diff --git a/configure.ac b/configure.ac index 4c1d5fa67..cd29f4cfe 100644 --- a/configure.ac +++ b/configure.ac @@ -270,6 +270,7 @@ AC_CONFIG_FILES([Makefile include/upipe-dvbcsa/Makefile include/upipe-ebur128/Makefile include/upipe-bearssl/Makefile + include/upipe-srt/Makefile lib/Makefile lib/upipe/Makefile lib/upipe/libupipe.pc @@ -337,6 +338,8 @@ AC_CONFIG_FILES([Makefile lib/upipe-ebur128/libupipe_ebur128.pc lib/upipe-bearssl/Makefile lib/upipe-bearssl/libupipe_bearssl.pc + lib/upipe-srt/Makefile + lib/upipe-srt/libupipe_srt.pc x86/Makefile x86/config.asm tests/Makefile diff --git a/examples/Makefile.am b/examples/Makefile.am index 4262b6c83..0f82687d0 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -19,13 +19,15 @@ UPIPEOSX_LIBS = $(top_builddir)/lib/upipe-osx/libupipe_osx.la UPIPEDVBCSA_LIBS = $(top_builddir)/lib/upipe-dvbcsa/libupipe_dvbcsa.la UPIPEDVB_LIBS = $(top_builddir)/lib/upipe-dvb/libupipe_dvb.la UPIPEBEARSSL_LIBS = $(top_builddir)/lib/upipe-bearssl/libupipe_bearssl.la +UPIPESRT_LIBS = $(top_builddir)/lib/upipe-srt/libupipe_srt.la noinst_PROGRAMS = fec_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPETS_LIBS) -rist_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) +rist_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) +rist_rx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) rist_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) -rist_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) +rist_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) udpmulticat_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) multicatudp_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEPTHREAD_LIBS) -lpthread hls2rtp_LDADD= $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFRAMERS_LIBS) $(UPIPETS_LIBS) $(UPIPEHLS_LIBS) $(UPIPEPTHREAD_LIBS) -lpthread @@ -63,6 +65,10 @@ frame_LDADD = $(LDADD) $(UPIPEMODULES_LIBS) $(UPUMPEV_LIBS) $(UPIPEFRAMERS_LIBS) if HAVE_GCRYPT ts_encrypt_CFLAGS += $(GCRYPT_CFLAGS) ts_encrypt_LDADD += $(GCRYPT_LIBS) +rist_rx_CFLAGS += $(GCRYPT_CFLAGS) +rist_rx_LDADD += $(GCRYPT_LIBS) +rist_tx_CFLAGS += $(GCRYPT_CFLAGS) +rist_tx_LDADD += $(GCRYPT_LIBS) endif if HAVE_EV diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 65520f552..296114a1b 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -24,6 +24,8 @@ * */ +#include + #undef NDEBUG #include "upipe/uprobe.h" #include "upipe/uprobe_stdio.h" @@ -47,19 +49,17 @@ #include "upipe/uuri.h" #include "upipe/ustring.h" #include "upipe/upipe.h" -#include "upipe-modules/upipe_dup.h" #include "upipe-modules/upipe_udp_source.h" #include "upipe-modules/upipe_udp_sink.h" -#include "upipe-modules/upipe_probe_uref.h" -#include "upipe-filters/upipe_rtp_feedback.h" - -#include -#include -#include -#include -#include +#include "upipe-srt/upipe_srt_handshake.h" +#include "upipe-srt/upipe_srt_receiver.h" + #include +#ifdef UPIPE_HAVE_GCRYPT_H +#include +#endif + #define UDICT_POOL_DEPTH 10 #define UREF_POOL_DEPTH 10 #define UBUF_POOL_DEPTH 10 @@ -72,219 +72,189 @@ static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; static struct upipe_mgr *udp_sink_mgr; static struct upump_mgr *upump_mgr; -static struct upipe *upipe_rtpfb; -static struct upipe *upipe_rtpfb_sub; static struct upipe *upipe_udpsrc; -static struct upipe *upipe_udpsrc_rtcp; -static struct upipe *upipe_dup; +static struct upipe *upipe_udp_sink; +static struct upipe *upipe_srth_sub; +static struct upipe *upipe_srtr_sub; -struct rtcp_sink { - struct upipe *dup_sub; - struct sockaddr_storage addr; - socklen_t addr_len; - struct upump *timeout; -}; +static struct uprobe uprobe_udp; +static struct uprobe uprobe_srt; +static struct uprobe *logger; -static struct rtcp_sink rtcp_sink[2]; +static char *dirpath; +static char *srcpath; +static char *password; -static int udp_fd = -1; +static bool restart; -static void usage(const char *argv0) { - fprintf(stdout, "Usage: %s [-d] ", argv0); - fprintf(stdout, " -d: more verbose\n"); - fprintf(stdout, " -q: more quiet\n"); - exit(EXIT_FAILURE); +static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) +{ + uint16_t port = 0; + switch(s->sa_family) { + case AF_INET: { + struct sockaddr_in *in = (struct sockaddr_in *)s; + inet_ntop(AF_INET, &in->sin_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in->sin_port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + inet_ntop(AF_INET6, &in6->sin6_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in6->sin6_port); + break; + } + default: + uri[0] = '\0'; + } + + size_t uri_len = strlen(uri); + sprintf(&uri[uri_len], ":%hu", port); } -static void gather_stats(struct upipe *upipe, struct uref *uref) +static int start(void) { - uint64_t cr_sys = 0; - if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) { - upipe_err(upipe, "Couldn't read cr_sys in probe_uref"); - } + bool listener = srcpath && *srcpath == '@'; + struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); + upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); + upipe_mgr_release(upipe_udpsrc_mgr); + + struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); + struct upipe *upipe_srth = upipe_void_alloc_output(upipe_udpsrc, + upipe_srt_handshake_mgr, &uprobe_srt); + assert(upipe_srth); + upipe_set_option(upipe_srth, "listener", listener ? "1" : "0"); + upipe_srt_handshake_set_password(upipe_srth, password); + upipe_mgr_release(upipe_srt_handshake_mgr); + + upipe_srth_sub = upipe_void_alloc_sub(upipe_srth, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srth_sub")); + assert(upipe_srth_sub); + upipe_udp_sink = upipe_void_alloc_output(upipe_srth_sub, + udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, + "udpsink")); + upipe_release(upipe_udp_sink); - static uint64_t last_print; - if (unlikely(last_print == 0)) - last_print = cr_sys; + struct upipe_mgr *upipe_srt_receiver_mgr = upipe_srt_receiver_mgr_alloc(); + struct upipe *upipe_srtr = upipe_void_chain_output(upipe_srth, + upipe_srt_receiver_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr")); + assert(upipe_srtr); + upipe_mgr_release(upipe_srt_receiver_mgr); + + upipe_srtr_sub = upipe_void_alloc_sub(upipe_srtr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr_sub")); + assert(upipe_srtr_sub); + upipe_set_output(upipe_srtr_sub, upipe_udp_sink); + + int udp_fd; + /* receive SRT */ + if (listener) { + if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) + return EXIT_FAILURE; + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc, &udp_fd)); + + } else { + if (!ubase_check(upipe_set_uri(upipe_udp_sink, srcpath))) + return EXIT_FAILURE; + + ubase_assert(upipe_udpsink_get_fd(upipe_udp_sink, &udp_fd)); + ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc, dup(udp_fd))); + } - if ((cr_sys - last_print) < 3 * UCLOCK_FREQ) - return; + struct sockaddr_storage ad; + socklen_t peer_len = sizeof(ad); + struct sockaddr *peer = (struct sockaddr*) &ad; - last_print = cr_sys; + if (!getsockname(udp_fd, peer, &peer_len)) { + char uri[INET6_ADDRSTRLEN+6]; + addr_to_str(peer, uri); + upipe_warn_va(upipe_srth, "Local %s", uri); // XXX: INADDR_ANY when listening + upipe_srt_handshake_set_peer(upipe_srth, peer, peer_len); + } - unsigned expected_seqnum, last_output_seqnum; - size_t buffers, nacks, repairs, loss, dups; - if (unlikely(!ubase_check(upipe_rtpfb_get_stats(upipe_rtpfb, - &expected_seqnum, &last_output_seqnum, - &buffers, &nacks, &repairs, &loss, &dups - )))) - upipe_err_va(upipe, "Couldn't get stats from rtpfb"); + upipe_attach_uclock(upipe_udpsrc); + struct upipe *upipe_udp_sink_data = upipe_void_chain_output(upipe_srtr, + udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, + "udpsink data")); + upipe_set_uri(upipe_udp_sink_data, dirpath); + upipe_release(upipe_udp_sink_data); - unsigned nack_overflow = (repairs && repairs < nacks) ? (nacks - repairs ) * 100 / repairs : 0; - upipe_notice_va(upipe, "%5u (%3zu) %5u\t%zu repairs %zu NACKS (%u%% too much)\tlost %zu\tduplicates %zu", - last_output_seqnum, buffers, expected_seqnum, repairs, nacks, nack_overflow, loss, dups); + return 0; } -static void sink_timeout(struct upump *upump) +static void stop(struct upump *upump) { - struct rtcp_sink *sink = upump_get_opaque(upump, struct rtcp_sink *); upump_stop(upump); upump_free(upump); - upipe_err_va(sink->dup_sub, "timeout"); - sink->timeout = NULL; - upipe_release(sink->dup_sub); - sink->dup_sub = NULL; -} + upipe_release(upipe_srth_sub); + upipe_release(upipe_srtr_sub); + upipe_release(upipe_udpsrc); -static struct rtcp_sink *last_peer; + if (restart) { + restart = false; + start(); + } +} -/** definition of our uprobe */ -static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, +static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { - const char *uri; - switch (event) { - case UPROBE_UDPSRC_NEW_PEER: { - int sig = va_arg(args, int); - if (sig != UPIPE_UDPSRC_SIGNATURE) - return uprobe_throw_next(uprobe, upipe, event, args); - - const struct sockaddr *s = va_arg(args, struct sockaddr*); - const struct sockaddr_in *in = (const struct sockaddr_in*) s; - socklen_t addr_len = sizeof(*in); - const socklen_t *len = va_arg(args, socklen_t *); - - if (s->sa_family != AF_INET) { - upipe_err_va(upipe, "New UDP remote, unknown addr family %d", - s->sa_family); - return UBASE_ERR_NONE; - } - - if (*len < addr_len) { - upipe_err_va(upipe, "Too small AF_INET address"); - return UBASE_ERR_NONE; - } - - upipe_dbg_va(upipe, "Got new remote: %s:%hu ", - inet_ntoa(in->sin_addr), ntohs(in->sin_port)); - - const size_t n = sizeof(rtcp_sink) / sizeof(*rtcp_sink); - struct rtcp_sink *sink = NULL; - ssize_t avail = -1; /* index of the free remote */ - for (size_t i = 0; i < n; i++) { - if (!rtcp_sink[i].dup_sub) { - if (!sink) { - avail = i; - sink = &rtcp_sink[i]; - } - continue; - } - - if (memcmp(&rtcp_sink[i].addr, in, addr_len)) - continue; - - upipe_dbg_va(upipe, "Remote already existing"); - sink = &rtcp_sink[i]; - upump_stop(sink->timeout); - break; - } - - if (!sink) { - upipe_err_va(upipe, "Too many RTCP remotes already"); - return UBASE_ERR_NONE; - } - - if (last_peer) /* restart the timeout for the previous peer we got */ - upump_restart(last_peer->timeout); - - /* keep the timer for this remote stopped for now, - * this could be the only one we have */ - last_peer = sink; + if (event == UPROBE_SOURCE_END) { + restart = true; + struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, 0, 0); + upump_start(u); + return UBASE_ERR_NONE; + } - if (sink->dup_sub) - return UBASE_ERR_NONE; + return uprobe_throw_next(uprobe, upipe, event, args); +} - sink->dup_sub = upipe_void_alloc_sub(upipe_dup, - uprobe_pfx_alloc_va(uprobe_use(uprobe), loglevel, - "dup %zu", avail)); - assert(sink->dup_sub); +static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + if (event == UPROBE_SOURCE_END) { + /* This control can not fail, and will trigger restart of upump */ + const char *uri; + upipe_get_uri(upipe, &uri); + return UBASE_ERR_NONE; + } - struct upipe *rtcp_sink = upipe_void_alloc_output(sink->dup_sub, - udp_sink_mgr, uprobe_pfx_alloc_va(uprobe_use(uprobe), loglevel, - "udpsink rtpfb %zu", avail)); - ubase_assert(upipe_udpsink_set_fd(rtcp_sink, dup(udp_fd))); - upipe_release(rtcp_sink); + if (event != UPROBE_UDPSRC_NEW_PEER) + return uprobe_throw_next(uprobe, upipe, event, args); - sink->addr_len = addr_len; - memcpy(&sink->addr, in, addr_len); + int sig = va_arg(args, int); + if (sig != UPIPE_UDPSRC_SIGNATURE) + return uprobe_throw_next(uprobe, upipe, event, args); - ubase_assert(upipe_udpsink_set_peer(rtcp_sink, - (const struct sockaddr*)&sink->addr, addr_len)); + const struct sockaddr *s = va_arg(args, struct sockaddr*); + const socklen_t *len = va_arg(args, socklen_t *); + char uri[INET6_ADDRSTRLEN+6]; - sink->timeout = upump_alloc_timer(upump_mgr, sink_timeout, - sink, NULL, 3 * UCLOCK_FREQ, 3 * UCLOCK_FREQ); + addr_to_str(s, uri); + upipe_warn_va(upipe, "Remote %s", uri); - return UBASE_ERR_NONE; - } - case UPROBE_SOURCE_END: - /* This control can not fail, and will trigger restart of upump */ - upipe_get_uri(upipe, &uri); - return UBASE_ERR_NONE; - default: - return uprobe_throw_next(uprobe, upipe, event, args); - } -} + int udp_fd; + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc, &udp_fd)); + ubase_assert(upipe_udpsink_set_fd(upipe_udp_sink, dup(udp_fd))); + ubase_assert(upipe_udpsink_set_peer(upipe_udp_sink, s, *len)); -/** definition of our uprobe */ -static int catch(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) -{ - switch (event) { - default: - break; - case UPROBE_SOURCE_END: - if (upipe->mgr->signature == UPIPE_DUP_OUTPUT_SIGNATURE) { - const size_t n = sizeof(rtcp_sink) / sizeof(*rtcp_sink); - for (size_t i = 0; i < n; i++) { - struct rtcp_sink *sink = &rtcp_sink[i]; - if (sink->dup_sub == upipe) { - upump_stop(sink->timeout); - sink->dup_sub = NULL; - } - } - } - upipe_release(upipe); - break; - case UPROBE_PROBE_UREF: { - int sig = va_arg(args, int); - if (sig != UPIPE_PROBE_UREF_SIGNATURE) - return UBASE_ERR_INVALID; - struct uref *uref = va_arg(args, struct uref *); - va_arg(args, struct upump **); - gather_stats(upipe, uref); - break; - } - } return UBASE_ERR_NONE; } -static void stop(struct upump *upump) -{ - upump_stop(upump); - upump_free(upump); - - upipe_release(upipe_udpsrc_rtcp); - upipe_release(upipe_udpsrc); +static void usage(const char *argv0) { + fprintf(stdout, "Usage: %s [-d] [-k password] ", argv0); + fprintf(stdout, " -d: more verbose\n"); + fprintf(stdout, " -q: more quiet\n"); + fprintf(stdout, " -k encryption password\n"); + exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { - char *dirpath, *latency, *srcpath; int opt; /* parse options */ - while ((opt = getopt(argc, argv, "qd")) != -1) { + while ((opt = getopt(argc, argv, "qdk:")) != -1) { switch (opt) { case 'd': loglevel--; @@ -292,16 +262,23 @@ int main(int argc, char *argv[]) case 'q': loglevel++; break; + case 'k': + password = optarg; + break; default: usage(argv[0]); } } - if (argc - optind < 3) { + if (argc - optind < 2) { usage(argv[0]); } srcpath = argv[optind++]; dirpath = argv[optind++]; - latency = argv[optind++]; + +#ifdef UPIPE_HAVE_GCRYPT_H + gcry_check_version(NULL); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +#endif /* setup environment */ @@ -312,9 +289,7 @@ int main(int argc, char *argv[]) 0); upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); - struct uprobe uprobe; - uprobe_init(&uprobe, catch, NULL); - struct uprobe *logger = uprobe_stdio_alloc(&uprobe, stdout, loglevel); + logger = uprobe_stdio_alloc(NULL, stdout, loglevel); assert(logger != NULL); struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); assert(uprobe_dejitter != NULL); @@ -336,89 +311,12 @@ int main(int argc, char *argv[]) logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); - /* rtp source */ - struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); - upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "udp source")); - - /* rtcp source */ - struct uprobe uprobe_udp; - uprobe_init(&uprobe_udp, catch_udp, uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "udp rtcp source")); - upipe_udpsrc_rtcp = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); - upipe_mgr_release(upipe_udpsrc_mgr); - - struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); - struct upipe *upipe_probe_uref = upipe_void_alloc_output(upipe_udpsrc, - upipe_probe_uref_mgr, uprobe_use(logger)); - assert(upipe_probe_uref); - upipe_mgr_release(upipe_probe_uref_mgr); - upipe_release(upipe_probe_uref); - - struct upipe_mgr *upipe_rtpfb_mgr = upipe_rtpfb_mgr_alloc(); - upipe_rtpfb = upipe_void_alloc_output(upipe_probe_uref, - upipe_rtpfb_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtpfb")); - upipe_mgr_release(upipe_rtpfb_mgr); - - upipe_rtpfb_sub = upipe_void_alloc_output_sub(upipe_udpsrc_rtcp, upipe_rtpfb, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtpfb_sub")); - assert(upipe_rtpfb_sub); - - upipe_rtpfb_output_set_name(upipe_rtpfb_sub, "Upipe"); - - struct upipe_mgr *dup_mgr = upipe_dup_mgr_alloc(); - upipe_dup = upipe_void_chain_output(upipe_rtpfb_sub, dup_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "dup rtpfb_sub")); - assert(upipe_dup); - upipe_release(upipe_dup); - upipe_mgr_release(dup_mgr); - - if (!ubase_check(upipe_set_option(upipe_rtpfb, "latency", latency))) { - return EXIT_FAILURE; - } - - /* receive RTP */ - if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { - return EXIT_FAILURE; - } - - struct ustring u = ustring_from_str(srcpath); - struct uuri_authority authority = uuri_parse_authority(&u); - struct ustring settings = uuri_parse_path(&u); - - char port_str[6]; - snprintf(port_str, sizeof(port_str), "%.*s", (int)authority.port.len, - authority.port.at); - int port = atoi(port_str); - - if (port & 1) { - fprintf(stderr, "RTP port should be even\n"); - return EXIT_FAILURE; - } + uprobe_init(&uprobe_udp, catch_udp, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source")); + uprobe_init(&uprobe_srt, catch_srt, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srth")); - char uri[128]; - snprintf(uri, sizeof(uri), "%.*s@%.*s:%u%.*s", - (int)authority.userinfo.len, authority.userinfo.at, - (int)authority.host.len, authority.host.at, port + 1, - (int)settings.len, settings.at); - - if (!ubase_check(upipe_set_uri(upipe_udpsrc_rtcp, uri))) { - return EXIT_FAILURE; - } - - upipe_attach_uclock(upipe_udpsrc); - upipe_attach_uclock(upipe_udpsrc_rtcp); - - ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_rtcp, &udp_fd)); - assert(udp_fd != -1); - - struct upipe *upipe_udp_sink = upipe_void_chain_output(upipe_rtpfb, - udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, - "udpsink")); - upipe_set_uri(upipe_udp_sink, dirpath); - - upipe_release(upipe_udp_sink); + int ret = start(); + if (ret) + return ret; if (0) { struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, @@ -431,17 +329,10 @@ int main(int argc, char *argv[]) /* should never be here for the moment. todo: sighandler. * release everything */ - uprobe_clean(&uprobe); + uprobe_clean(&uprobe_srt); uprobe_clean(&uprobe_udp); uprobe_release(logger); - const size_t n = sizeof(rtcp_sink) / sizeof(*rtcp_sink); - for (size_t i = 0; i < n; i++) { - struct rtcp_sink *sink = &rtcp_sink[i]; - if (sink->timeout) - upump_free(sink->timeout); - } - upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); udict_mgr_release(udict_mgr); diff --git a/examples/rist_tx.c b/examples/rist_tx.c index af0ed000d..2d01b6dd1 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -46,238 +46,246 @@ #include "upipe/uref_clock.h" #include "upipe/uref_std.h" #include "upipe/upump.h" +#include "upipe/upipe_dump.h" #include "upump-ev/upump_ev.h" #include "upipe/uuri.h" #include "upipe/ustring.h" #include "upipe/upipe.h" -#include "upipe-modules/upipe_dup.h" -#include "upipe-modules/upipe_rtcp.h" #include "upipe-modules/upipe_udp_source.h" #include "upipe-modules/upipe_udp_sink.h" -#include "upipe-modules/upipe_probe_uref.h" -#include "upipe-filters/upipe_rtcp_fb_receiver.h" -#include -#include -#include +#include "upipe-srt/upipe_srt_sender.h" +#include "upipe-srt/upipe_srt_handshake.h" + #include -#include +#include -#include -#include -#include -#include +#ifdef UPIPE_HAVE_GCRYPT_H +#include +#endif #define UDICT_POOL_DEPTH 10 #define UREF_POOL_DEPTH 10 #define UBUF_POOL_DEPTH 10 #define UPUMP_POOL 10 #define UPUMP_BLOCKER_POOL 10 -#define READ_SIZE 4096 static void usage(const char *argv0) { fprintf(stdout, "Usage: %s [-d] \n", argv0); fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); + fprintf(stdout, " -k encryption password\n"); exit(EXIT_FAILURE); } static struct upipe *upipe_udpsink; -static struct upipe *upipe_udpsink_rtcp; -static struct upipe *upipe_udpsrc_sub; - -static uint64_t last_sr_ntp; -static uint64_t last_sr_cr; +static struct upipe *upipe_udpsrc_srt; +static struct upipe *upipe_udpsrc; +static struct upipe *upipe_srt_handshake_sub; +static struct upipe *upipe_srt_sender; +static struct upipe *upipe_srt_sender_sub; +static struct upump_mgr *upump_mgr; static struct uref_mgr *uref_mgr; +static char *srcpath; +static char *dirpath; +static char *latency; +static char *password; + +static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; + +static struct uprobe uprobe_udp_srt; +static struct uprobe *logger; + +static bool restart; + +static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) +{ + uint16_t port = 0; + switch(s->sa_family) { + case AF_INET: { + struct sockaddr_in *in = (struct sockaddr_in *)s; + inet_ntop(AF_INET, &in->sin_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in->sin_port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + inet_ntop(AF_INET6, &in6->sin6_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in6->sin6_port); + break; + } + default: + uri[0] = '\0'; + } + + size_t uri_len = strlen(uri); + sprintf(&uri[uri_len], ":%hu", port); +} + +static void stop(struct upump *upump); + /** definition of our uprobe */ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { - const char *uri; - switch (event) { case UPROBE_SOURCE_END: - upipe_warn(upipe, "Remote end not listening, can't receive RTCP"); - /* This control can not fail, and will trigger restart of upump */ - upipe_get_uri(upipe, &uri); - return UBASE_ERR_NONE; - case UPROBE_UDPSRC_NEW_PEER: - return UBASE_ERR_NONE; - default: + upipe_warn(upipe, "Remote end not listening, can't receive SRT"); + restart = true; + struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, + NULL, UCLOCK_FREQ, 0); + upump_start(u); return uprobe_throw_next(uprobe, upipe, event, args); - } -} - -static void parse_rtcp(struct upipe *upipe, const uint8_t *rtp, int s, - uint64_t cr_sys, struct ubuf_mgr *ubuf_mgr) -{ - while (s > 0) { - if (s < 4 || !rtp_check_hdr(rtp)) { - upipe_warn_va(upipe, "Received invalid RTP packet"); + case UPROBE_UDPSRC_NEW_PEER: { + int udp_fd; + int sig = va_arg(args, int); + if (sig != UPIPE_UDPSRC_SIGNATURE) break; - } - size_t len = 4 + 4 * rtcp_get_length(rtp); - if (len > s) { - break; - } + const struct sockaddr *s = va_arg(args, struct sockaddr*); + const socklen_t *len = va_arg(args, socklen_t *); - switch (rtcp_get_pt(rtp)) { - case RTCP_PT_SR: - if (s < RTCP_SR_SIZE) - break; - uint32_t ntp_msw = rtcp_sr_get_ntp_time_msw(rtp); - uint32_t ntp_lsw = rtcp_sr_get_ntp_time_lsw(rtp); - if (cr_sys != UINT64_MAX) - last_sr_cr = cr_sys; - last_sr_ntp = ((uint64_t)ntp_msw << 32) | ntp_lsw; - upipe_verbose_va(upipe, "RTCP SR, CR %"PRIu64" NTP %"PRIu64, last_sr_cr, - last_sr_ntp); - break; - case RTCP_PT_RR: - if (s < RTCP_RR_SIZE) - break; - if (rtcp_get_rc(rtp) < 1) - break; + char uri[INET6_ADDRSTRLEN+6]; + addr_to_str(s, uri); + upipe_warn_va(upipe, "Remote %s", uri); - uint32_t delay = rtcp_rr_get_delay_since_last_sr(rtp); - uint32_t last_sr = rtcp_rr_get_last_sr(rtp); - if (last_sr != ((last_sr_ntp >> 16) & 0xffffffff)) - break; + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_srt, &udp_fd)); + ubase_assert(upipe_udpsink_set_fd(upipe_udpsink, dup(udp_fd))); - if (cr_sys != UINT64_MAX) { - cr_sys -= last_sr_cr; - cr_sys -= delay * UCLOCK_FREQ / 65536; - upipe_verbose_va(upipe, "RTCP RR: RTT %f", (float) cr_sys / UCLOCK_FREQ); - } - break; - case RTCP_PT_XR: - if (s < RTCP_XR_HEADER_SIZE + RTCP_XR_RRTP_SIZE) - break; + ubase_assert(upipe_udpsink_set_peer(upipe_udpsink, s, *len)); - uint8_t ssrc[4]; - rtcp_xr_get_ssrc_sender(rtp, ssrc); - const uint8_t *rtp_xr = &rtp[RTCP_XR_HEADER_SIZE]; + return UBASE_ERR_NONE; + } + } + return uprobe_throw_next(uprobe, upipe, event, args); +} - if (rtcp_xr_get_bt(rtp_xr) != RTCP_XR_RRTP_BT) - break; - if ((rtcp_xr_get_length(rtp_xr) + 1) * 4 != RTCP_XR_RRTP_SIZE) - break; +static int start(void) +{ + bool listener = dirpath && *dirpath == '@'; - uint64_t ntp = rtcp_xr_rrtp_get_ntp(rtp_xr); + /* rtp source */ + struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); + upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source data")); - struct uref *xr = uref_alloc(uref_mgr); - if (!xr) - break; + if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { + return EXIT_FAILURE; + } + upipe_attach_uclock(upipe_udpsrc); - if (cr_sys != UINT64_MAX) - uref_clock_set_cr_sys(xr, cr_sys); + /* send through srt sender */ + struct upipe_mgr *upipe_srt_sender_mgr = upipe_srt_sender_mgr_alloc(); + upipe_srt_sender = upipe_void_alloc_output(upipe_udpsrc, upipe_srt_sender_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt sender")); + upipe_mgr_release(upipe_srt_sender_mgr); - const size_t xr_len = RTCP_XR_HEADER_SIZE + RTCP_XR_DLRR_SIZE; - struct ubuf *ubuf = ubuf_block_alloc(ubuf_mgr, xr_len); - if (!ubuf) { - uref_free(xr); - break; - } + if (!ubase_check(upipe_set_option(upipe_srt_sender, "latency", latency))) + return EXIT_FAILURE; - uref_attach_ubuf(xr, ubuf); + uprobe_init(&uprobe_udp_srt, catch_udp, uprobe_use(logger)); + upipe_udpsrc_srt = upipe_void_alloc(upipe_udpsrc_mgr, + uprobe_pfx_alloc(&uprobe_udp_srt, loglevel, "udp source srt")); + upipe_attach_uclock(upipe_udpsrc_srt); - uint8_t *buf_xr; - int block_size = 0; - uref_block_write(xr, 0, &block_size, &buf_xr); + struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); + struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt handshake")); + upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); + upipe_srt_handshake_set_password(upipe_srt_handshake, password); - rtcp_set_rtp_version(buf_xr); - rtcp_set_pt(buf_xr, RTCP_PT_XR); - rtcp_set_length(buf_xr, xr_len / 4 - 1); + upipe_mgr_release(upipe_srt_handshake_mgr); - static const uint8_t pi_ssrc[4] = { 0, 0, 0, 0 }; - rtcp_xr_set_ssrc_sender(buf_xr, pi_ssrc); + upipe_mgr_release(upipe_udpsrc_mgr); - buf_xr += RTCP_XR_HEADER_SIZE; - rtcp_xr_set_bt(buf_xr, RTCP_XR_DLRR_BT); - rtcp_xr_dlrr_set_reserved(buf_xr); - rtcp_xr_set_length(buf_xr, RTCP_XR_DLRR_SIZE / 4 - 1); - rtcp_xr_dlrr_set_ssrc_receiver(buf_xr, ssrc); + upipe_srt_handshake_sub = upipe_void_alloc_sub(upipe_srt_handshake, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt handshake sub")); + assert(upipe_srt_handshake_sub); - ntp >>= 16; - rtcp_xr_dlrr_set_lrr(buf_xr, (uint32_t)ntp); + upipe_srt_sender_sub = upipe_void_chain_output_sub(upipe_srt_handshake, + upipe_srt_sender, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt sender sub")); + assert(upipe_srt_sender_sub); + upipe_release(upipe_srt_sender_sub); - rtcp_xr_dlrr_set_dlrr(buf_xr, 0); // delay = 0, we answer immediately + /* send to udp */ + struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); + upipe_udpsink = upipe_void_chain_output(upipe_srt_sender, upipe_udpsink_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp sink")); + upipe_release(upipe_udpsink); - uref_block_unmap(xr, 0); + upipe_set_output(upipe_srt_handshake_sub, upipe_udpsink); - upipe_notice_va(upipe, "sending XR"); - upipe_input(upipe_udpsink_rtcp, xr, NULL); - break; - default: - break; + int udp_fd = -1; + if (listener) { + if (!ubase_check(upipe_set_uri(upipe_udpsrc_srt, dirpath))) { + return EXIT_FAILURE; + } + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_srt, &udp_fd)); + } else { + if (!ubase_check(upipe_set_uri(upipe_udpsink, dirpath))) { + return EXIT_FAILURE; } - s -= len; - rtp += len; + ubase_assert(upipe_udpsink_get_fd(upipe_udpsink, &udp_fd)); + int flags = fcntl(udp_fd, F_GETFL); + flags |= O_NONBLOCK; + if (fcntl(udp_fd, F_SETFL, flags) < 0) + upipe_err(upipe_udpsink, "Could not set flags");; + ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc_srt, udp_fd)); } -} - -/** definition of our uprobe */ -static int catch(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) -{ - struct uref *uref = NULL; - - switch (event) { - case UPROBE_SOURCE_END: - upipe_release(upipe); - break; - case UPROBE_PROBE_UREF: { - int sig = va_arg(args, int); - if (sig != UPIPE_PROBE_UREF_SIGNATURE) - return UBASE_ERR_INVALID; - uref = va_arg(args, struct uref *); - va_arg(args, struct upump **); - va_arg(args, bool *); + struct sockaddr_storage ad; + socklen_t peer_len = sizeof(ad); + struct sockaddr *peer = (struct sockaddr*) &ad; - const uint8_t *buf; - int s = -1; - if (!ubase_check(uref_block_read(uref, 0, &s, &buf))) - return UBASE_ERR_INVALID; + if (!getsockname(udp_fd, peer, &peer_len)) { + char uri[INET6_ADDRSTRLEN+6]; + addr_to_str(peer, uri); + upipe_warn_va(upipe_srt_handshake, "Local %s", uri); // XXX: INADDR_ANY when listening + upipe_srt_handshake_set_peer(upipe_srt_handshake, peer, peer_len); + } - uint64_t cr_sys; - if (!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys))) - cr_sys = UINT64_MAX; + return 0; +} - parse_rtcp(upipe, buf, s, cr_sys, uref->ubuf->mgr); +static void stop(struct upump *upump) +{ + if (upump) { + upump_stop(upump); + upump_free(upump); + } - uref_block_unmap(uref, 0); + upipe_release(upipe_udpsrc_srt); + upipe_release(upipe_udpsrc); + upipe_release(upipe_srt_handshake_sub); - break; - } - default: - return uprobe_throw_next(uprobe, upipe, event, args); + if (restart) { + restart = false; + start(); } - return UBASE_ERR_NONE; } -static void stop(struct upump *upump) +static void sig_cb(struct upump *upump) { - struct upipe *udpsrc = upump_get_opaque(upump, struct upipe*); - upump_stop(upump); - upump_free(upump); + static int done = false; - upipe_release(upipe_udpsrc_sub); - upipe_release(udpsrc); + if (done) + abort(); + done = true; + + stop(NULL); } + int main(int argc, char *argv[]) { - char *srcpath, *dirpath, *latency; int opt; - enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; /* parse options */ - while ((opt = getopt(argc, argv, "qd")) != -1) { + while ((opt = getopt(argc, argv, "qdk:")) != -1) { switch (opt) { case 'q': loglevel++; @@ -285,6 +293,10 @@ int main(int argc, char *argv[]) case 'd': loglevel--; break; + break; + case 'k': + password = optarg; + break; default: usage(argv[0]); } @@ -296,6 +308,11 @@ int main(int argc, char *argv[]) dirpath = argv[optind++]; latency = argv[optind++]; +#ifdef UPIPE_HAVE_GCRYPT_H + gcry_check_version(NULL); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +#endif + /* setup environment */ struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); @@ -303,12 +320,10 @@ int main(int argc, char *argv[]) umem_mgr, -1, -1); uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, 0); - struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, + upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); struct uclock *uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); - struct uprobe uprobe; - uprobe_init(&uprobe, catch, NULL); - struct uprobe *logger = uprobe_stdio_alloc(&uprobe, stdout, loglevel); + logger = uprobe_stdio_alloc(NULL, stdout, loglevel); assert(logger != NULL); struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); assert(uprobe_dejitter != NULL); @@ -325,138 +340,32 @@ int main(int argc, char *argv[]) logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); - /* rtp source */ - struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); - struct upipe *upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source")); - - if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { - return EXIT_FAILURE; - } - upipe_attach_uclock(upipe_udpsrc); - - /* send through rtcp fb receiver */ - struct upipe_mgr *upipe_rtcpfb_mgr = upipe_rtcpfb_mgr_alloc(); - struct upipe *upipe_rtcpfb = upipe_void_alloc_output(upipe_udpsrc, upipe_rtcpfb_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtcp fb")); - upipe_mgr_release(upipe_rtcpfb_mgr); - - if (!ubase_check(upipe_set_option(upipe_rtcpfb, "latency", latency))) - return EXIT_FAILURE; - - struct uprobe uprobe_udp_rtcp; - uprobe_init(&uprobe_udp_rtcp, catch_udp, uprobe_use(logger)); - upipe_udpsrc_sub = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc(&uprobe_udp_rtcp, loglevel, "udp source rtcp")); - upipe_attach_uclock(upipe_udpsrc_sub); - - upipe_mgr_release(upipe_udpsrc_mgr); - - /* catch RTCP XR/NACK messages before they're output to rtcp_fb */ - struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); - struct upipe *upipe_probe_uref = upipe_void_alloc_output(upipe_udpsrc_sub, - upipe_probe_uref_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "probe")); - assert(upipe_probe_uref); - upipe_mgr_release(upipe_probe_uref_mgr); - - struct upipe *upipe_rtcp_sub = upipe_void_chain_output_sub(upipe_probe_uref, - upipe_rtcpfb, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtcp fb sub")); - assert(upipe_rtcp_sub); - upipe_release(upipe_rtcp_sub); - - struct upipe_mgr *dup_mgr = upipe_dup_mgr_alloc(); - struct upipe *dup = upipe_void_chain_output(upipe_rtcpfb, dup_mgr, - uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "dup")); - upipe_mgr_release(dup_mgr); - - upipe_rtcpfb = upipe_void_alloc_sub(dup, - uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "dup 1")); - - struct upipe *rtcp_dup = upipe_void_alloc_sub(dup, - uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "dup 2")); - - upipe_release(dup); - - struct upipe_mgr *rtcp_mgr = upipe_rtcp_mgr_alloc(); - struct upipe *rtcp = upipe_void_alloc_output(rtcp_dup, rtcp_mgr, - uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "rtcp")); - upipe_mgr_release(rtcp_mgr); - - /* catch RTCP SR messages before they're output */ - upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); - rtcp = upipe_void_chain_output(rtcp, - upipe_probe_uref_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "probe2")); - assert(rtcp); - upipe_mgr_release(upipe_probe_uref_mgr); - - /* send to udp */ - struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); - upipe_udpsink = upipe_void_alloc_output(upipe_rtcpfb, upipe_udpsink_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp sink")); - upipe_release(upipe_udpsink); - - if (!ubase_check(upipe_set_uri(upipe_udpsink, dirpath))) { - return EXIT_FAILURE; - } - - /* send RTCP to udp */ - upipe_udpsink_rtcp = upipe_void_chain_output(rtcp, upipe_udpsink_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp sink rtcp")); - upipe_mgr_release(upipe_udpsink_mgr); - upipe_release(upipe_udpsink_rtcp); - - struct ustring u = ustring_from_str(dirpath); - struct uuri_authority authority = uuri_parse_authority(&u); - struct ustring settings = uuri_parse_path(&u); - - char port_str[6]; - snprintf(port_str, sizeof(port_str), "%.*s", (int)authority.port.len, - authority.port.at); - int port = atoi(port_str); - - if (port & 1) { - fprintf(stderr, "RTP port should be even\n"); - return EXIT_FAILURE; - } - - char uri[128]; - snprintf(uri, sizeof(uri), "%.*s%s%.*s:%u%.*s", - (int)authority.userinfo.len, authority.userinfo.at, - ustring_is_empty(authority.userinfo) ? "" : "@", - (int)authority.host.len, authority.host.at, port + 1, - (int)settings.len, settings.at); - - if (!ubase_check(upipe_set_uri(upipe_udpsink_rtcp, uri))) { - return EXIT_FAILURE; - } - - int udp_fd = -1; - ubase_assert(upipe_udpsink_get_fd(upipe_udpsink_rtcp, &udp_fd)); - int flags = fcntl(udp_fd, F_GETFL); - flags |= O_NONBLOCK; - if (fcntl(udp_fd, F_SETFL, flags) < 0) - upipe_err(upipe_udpsink, "Could not set flags");; - ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc_sub, udp_fd)); + int ret = start(); + if (ret) + return ret; if (0) { + upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, NULL, UCLOCK_FREQ, 0); upump_start(u); } + struct upump *sigint_pump = + upump_alloc_signal(upump_mgr, sig_cb, + (void *)SIGINT, NULL, SIGINT); + upump_set_status(sigint_pump, false); + upump_start(sigint_pump); + /* fire loop ! */ upump_mgr_run(upump_mgr, NULL); + upump_free(sigint_pump); + /* should never be here for the moment. todo: sighandler. * release everything */ uprobe_release(logger); - uprobe_clean(&uprobe); - uprobe_clean(&uprobe_udp_rtcp); + uprobe_clean(&uprobe_udp_srt); upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); diff --git a/include/Makefile.am b/include/Makefile.am index f9e993d02..72ce21d80 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -105,5 +105,5 @@ SUBDIRS += upipe-bearssl endif if HAVE_SRT -SUBDIRS += upump-srt +SUBDIRS += upump-srt upipe-srt endif diff --git a/include/upipe-srt/Makefile.am b/include/upipe-srt/Makefile.am new file mode 100644 index 000000000..8e1861f9e --- /dev/null +++ b/include/upipe-srt/Makefile.am @@ -0,0 +1,5 @@ +myincludedir = $(includedir)/upipe-srt +myinclude_HEADERS = \ + upipe_srt_handshake.h \ + upipe_srt_sender.h \ + upipe_srt_receiver.h diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h new file mode 100644 index 000000000..876d75a15 --- /dev/null +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2023 Open Broadcast Systems Ltd + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module for SRT handshakes + */ + +#ifndef _UPIPE_MODULES_UPIPE_SRT_HANDSHAKE_H_ +/** @hidden */ +#define _UPIPE_MODULES_UPIPE_SRT_HANDSHAKE_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "upipe/upipe.h" +#include +#include + +#define UPIPE_SRT_HANDSHAKE_SIGNATURE UBASE_FOURCC('s','r','t','h') +#define UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE UBASE_FOURCC('s','r','h','o') + +/** @This extends upipe_command with specific commands for srt handshake. */ +enum upipe_srt_handshake_command { + UPIPE_SRT_HANDSHAKE_SENTINEL = UPIPE_CONTROL_LOCAL, + + /** set our peer address (const struct sockaddr *, socklen_t) **/ + UPIPE_SRT_HANDSHAKE_SET_PEER, + + /** set the encryption password (const char *) */ + UPIPE_SRT_HANDSHAKE_SET_PASSWORD, +}; + +/** @This sets the peer address + * + * @param upipe description structure of the pipe + * @param addr our address + * @param addrlen the size of addr + * @return false in case of error + */ +static inline int upipe_srt_handshake_set_peer(struct upipe *upipe, + const struct sockaddr *addr, socklen_t addrlen) +{ + return upipe_control(upipe, UPIPE_SRT_HANDSHAKE_SET_PEER, UPIPE_SRT_HANDSHAKE_SIGNATURE, + addr, addrlen); +} + +/** @This sets the encryption key + * + * @param upipe description structure of the pipe + * @param even key + * @param odd key + * @return false in case of error + */ +static inline int upipe_srt_handshake_set_password(struct upipe *upipe, + const char *password) +{ + return upipe_control(upipe, UPIPE_SRT_HANDSHAKE_SET_PASSWORD, UPIPE_SRT_HANDSHAKE_SIGNATURE, + password); +} + +/** @This returns the management structure for all srt handshakes sources. + * + * @return pointer to manager + */ +struct upipe_mgr *upipe_srt_handshake_mgr_alloc(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/upipe-srt/upipe_srt_receiver.h b/include/upipe-srt/upipe_srt_receiver.h new file mode 100644 index 000000000..ea16d6042 --- /dev/null +++ b/include/upipe-srt/upipe_srt_receiver.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 Open Broadcast Systems Ltd + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module for SRT handshakes + */ + +#ifndef _UPIPE_MODULES_UPIPE_SRT_RECEIVER_H_ +/** @hidden */ +#define _UPIPE_MODULES_UPIPE_SRT_RECEIVER_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "upipe/upipe.h" + +#define UPIPE_SRT_RECEIVER_SIGNATURE UBASE_FOURCC('s','r','t','r') +#define UPIPE_SRT_RECEIVER_OUTPUT_SIGNATURE UBASE_FOURCC('s','r','r','o') + +/** @This returns the management structure for all srt receiver sources. + * + * @return pointer to manager + */ +struct upipe_mgr *upipe_srt_receiver_mgr_alloc(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/upipe-srt/upipe_srt_sender.h b/include/upipe-srt/upipe_srt_sender.h new file mode 100644 index 000000000..29465a811 --- /dev/null +++ b/include/upipe-srt/upipe_srt_sender.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 Open Broadcast Systems Ltd + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module sending SRT + */ + +#ifndef _UPIPE_FILTERS_UPIPE_SRT_SENDER_H_ +/** @hidden */ +#define _UPIPE_FILTERS_UPIPE_SRT_SENDER_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "upipe/upipe.h" + +#define UPIPE_SRT_SENDER_SIGNATURE UBASE_FOURCC('s','r','t','s') +#define UPIPE_SRT_SENDER_INPUT_SIGNATURE UBASE_FOURCC('s','r','s','i') + +/** @This returns the management structure for srt_sender pipes. + * + * @return pointer to manager + */ +struct upipe_mgr *upipe_srt_sender_mgr_alloc(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/Makefile.am b/lib/Makefile.am index 0cc1dfb8d..6eb3b4eca 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,7 +2,8 @@ SUBDIRS = \ upipe \ upipe-modules \ upipe-filters \ - upipe-dveo + upipe-dveo \ + upipe-srt if HAVE_QTWEBKIT SUBDIRS += upipe-qt diff --git a/lib/upipe-modules/Makefile.am b/lib/upipe-modules/Makefile.am index 86d95e8fa..46a01a3dd 100644 --- a/lib/upipe-modules/Makefile.am +++ b/lib/upipe-modules/Makefile.am @@ -110,6 +110,11 @@ endif libupipe_modules_la_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include libupipe_modules_la_LIBADD = -lm $(top_builddir)/lib/upipe/libupipe.la +if HAVE_GCRYPT +libupipe_modules_la_CPPFLAGS += $(GCRYPT_CFLAGS) +libupipe_modules_la_LIBADD += $(GCRYPT_LIBS) +endif + libupipe_modules_la_LDFLAGS = -no-undefined pkgconfigdir = $(libdir)/pkgconfig diff --git a/lib/upipe-srt/Makefile.am b/lib/upipe-srt/Makefile.am new file mode 100644 index 000000000..2c2d653c8 --- /dev/null +++ b/lib/upipe-srt/Makefile.am @@ -0,0 +1,18 @@ +lib_LTLIBRARIES = libupipe_srt.la + +libupipe_srt_la_SOURCES = upipe_srt_handshake.c \ + upipe_srt_sender.c \ + upipe_srt_receiver.c + +libupipe_srt_la_CPPFLAGS = -I$(top_builddir) -I$(top_builddir)/include -I$(top_srcdir)/include +libupipe_srt_la_CFLAGS = $(AM_CFLAGS) $(SRT_FLAGS) $(BITSTREAM_CFLAGS) +libupipe_srt_la_LIBADD = $(top_builddir)/lib/upipe/libupipe.la $(SRT_LIBS) +libupipe_srt_la_LDFLAGS = -no-undefined + +if HAVE_GCRYPT +libupipe_srt_la_CPPFLAGS += $(GCRYPT_CFLAGS) +libupipe_srt_la_LIBADD += $(GCRYPT_LIBS) +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libupipe_srt.pc diff --git a/lib/upipe-srt/libupipe_srt.pc.in b/lib/upipe-srt/libupipe_srt.pc.in new file mode 100644 index 000000000..acc884a6b --- /dev/null +++ b/lib/upipe-srt/libupipe_srt.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +Name: libupipe_srt +Description: Upipe multimedia framework, libsrt interface module +Version: @VERSION@ +Requires: libupipe +Requires.private: libgcrypt +Libs: -L${libdir} -lupipe_srt +Cflags: -I${includedir} diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c new file mode 100644 index 000000000..6b32a110e --- /dev/null +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -0,0 +1,1345 @@ +/* + * Copyright (C) 2023 Open Broadcast Systems Ltd + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module for SRT handshakes + */ + +#include "upipe/config.h" +#include "upipe/ubase.h" +#include "upipe/uclock.h" +#include "upipe/uref.h" +#include "upipe/uref_block.h" +#include "upipe/uref_block_flow.h" +#include "upipe/uref_pic.h" // XXX +#include "upipe/uref_clock.h" +#include "upipe/uref_attr.h" +#include "upipe/upipe.h" +#include "upipe/upipe_helper_upipe.h" +#include "upipe/upipe_helper_subpipe.h" +#include "upipe/upipe_helper_urefcount.h" +#include "upipe/upipe_helper_urefcount_real.h" +#include "upipe/upipe_helper_void.h" +#include "upipe/upipe_helper_uref_mgr.h" +#include "upipe/upipe_helper_ubuf_mgr.h" +#include "upipe/upipe_helper_output.h" +#include "upipe/upipe_helper_upump_mgr.h" +#include "upipe/upipe_helper_upump.h" +#include "upipe/upipe_helper_uclock.h" + +#include "upipe-srt/upipe_srt_handshake.h" + +#include + +#include +#include + +#include + +/** @hidden */ +static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_format); + +/** @internal @This is the private context of a SRT handshake pipe. */ +struct upipe_srt_handshake { + /** real refcount management structure */ + struct urefcount urefcount_real; + /** refcount management structure exported to the public structure */ + struct urefcount urefcount; + + struct upipe_mgr sub_mgr; + /** list of output subpipes */ + struct uchain outputs; + + struct upump_mgr *upump_mgr; + struct upump *upump_timer; + struct uclock *uclock; + struct urequest uclock_request; + + + /** uref manager */ + struct uref_mgr *uref_mgr; + /** uref manager request */ + struct urequest uref_mgr_request; + + /** ubuf manager */ + struct ubuf_mgr *ubuf_mgr; + /** flow format packet */ + struct uref *flow_format; + /** ubuf manager request */ + struct urequest ubuf_mgr_request; + + /** pipe acting as output */ + struct upipe *output; + /** flow definition packet */ + struct uref *flow_def; + /** output state */ + enum upipe_helper_output_state output_state; + /** list of output requests */ + struct uchain request_list; + + uint32_t syn_cookie; + uint32_t socket_id; /* ours */ + uint32_t remote_socket_id; /* theirs */ + uint32_t isn; + uint32_t mtu; + uint32_t mfw; + + + uint16_t receiver_tsbpd_delay; + uint16_t sender_tsbpd_delay; + uint32_t flags; + uint16_t major; + uint8_t minor, patch; + + uint8_t salt[16]; + uint8_t sek[2][32]; + uint8_t sek_len; + + char *password; + + struct sockaddr_storage addr; + uint64_t establish_time; + + bool expect_conclusion; + + bool listener; + + uint8_t *stream_id; + size_t stream_id_len; + + uint64_t last_hs_sent; + + struct upipe *control; + + /** public upipe structure */ + struct upipe upipe; +}; + +UPIPE_HELPER_UPIPE(upipe_srt_handshake, upipe, UPIPE_SRT_HANDSHAKE_SIGNATURE) +UPIPE_HELPER_UREFCOUNT(upipe_srt_handshake, urefcount, upipe_srt_handshake_no_input) +UPIPE_HELPER_UREFCOUNT_REAL(upipe_srt_handshake, urefcount_real, upipe_srt_handshake_free); + +UPIPE_HELPER_VOID(upipe_srt_handshake) + +UPIPE_HELPER_OUTPUT(upipe_srt_handshake, output, flow_def, output_state, request_list) +UPIPE_HELPER_UPUMP_MGR(upipe_srt_handshake, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timer, upump_mgr) +UPIPE_HELPER_UCLOCK(upipe_srt_handshake, uclock, uclock_request, NULL, upipe_throw_provide_request, NULL) + +UPIPE_HELPER_UREF_MGR(upipe_srt_handshake, uref_mgr, uref_mgr_request, + upipe_srt_handshake_check, + upipe_srt_handshake_register_output_request, + upipe_srt_handshake_unregister_output_request) +UPIPE_HELPER_UBUF_MGR(upipe_srt_handshake, ubuf_mgr, flow_format, ubuf_mgr_request, + upipe_srt_handshake_check, + upipe_srt_handshake_register_output_request, + upipe_srt_handshake_unregister_output_request) + +/** @internal @This is the private context of a SRT handshake output pipe. */ +struct upipe_srt_handshake_output { + /** refcount management structure */ + struct urefcount urefcount; + /** structure for double-linked lists */ + struct uchain uchain; + + /** uref manager */ + struct uref_mgr *uref_mgr; + /** uref manager request */ + struct urequest uref_mgr_request; + + /** ubuf manager */ + struct ubuf_mgr *ubuf_mgr; + /** flow format packet */ + struct uref *flow_format; + /** ubuf manager request */ + struct urequest ubuf_mgr_request; + + /** pipe acting as output */ + struct upipe *output; + /** flow definition packet */ + struct uref *flow_def; + /** output state */ + enum upipe_helper_output_state output_state; + /** list of output requests */ + struct uchain request_list; + + /** public upipe structure */ + struct upipe upipe; +}; + +static int upipe_srt_handshake_output_check(struct upipe *upipe, struct uref *flow_format); +UPIPE_HELPER_UPIPE(upipe_srt_handshake_output, upipe, UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE) +UPIPE_HELPER_VOID(upipe_srt_handshake_output); +UPIPE_HELPER_UREFCOUNT(upipe_srt_handshake_output, urefcount, upipe_srt_handshake_output_free) +UPIPE_HELPER_OUTPUT(upipe_srt_handshake_output, output, flow_def, output_state, request_list) +UPIPE_HELPER_UREF_MGR(upipe_srt_handshake_output, uref_mgr, uref_mgr_request, + upipe_srt_handshake_output_check, + upipe_srt_handshake_output_register_output_request, + upipe_srt_handshake_output_unregister_output_request) +UPIPE_HELPER_UBUF_MGR(upipe_srt_handshake_output, ubuf_mgr, flow_format, ubuf_mgr_request, + upipe_srt_handshake_output_check, + upipe_srt_handshake_output_register_output_request, + upipe_srt_handshake_output_unregister_output_request) +UPIPE_HELPER_SUBPIPE(upipe_srt_handshake, upipe_srt_handshake_output, output, sub_mgr, outputs, + uchain) + +static int upipe_srt_handshake_output_check(struct upipe *upipe, struct uref *flow_format) +{ + struct upipe_srt_handshake_output *upipe_srt_handshake_output = upipe_srt_handshake_output_from_upipe(upipe); + if (flow_format) + upipe_srt_handshake_output_store_flow_def(upipe, flow_format); + + if (upipe_srt_handshake_output->uref_mgr == NULL) { + upipe_srt_handshake_output_require_uref_mgr(upipe); + return UBASE_ERR_NONE; + } + + if (upipe_srt_handshake_output->ubuf_mgr == NULL) { + struct uref *flow_format = + uref_block_flow_alloc_def(upipe_srt_handshake_output->uref_mgr, NULL); + if (unlikely(flow_format == NULL)) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return UBASE_ERR_ALLOC; + } + upipe_srt_handshake_output_require_ubuf_mgr(upipe, flow_format); + return UBASE_ERR_NONE; + } + + return UBASE_ERR_NONE; +} + +/** @This is called when there is no external reference to the pipe anymore. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_handshake_no_input(struct upipe *upipe) +{ + upipe_srt_handshake_throw_sub_outputs(upipe, UPROBE_SOURCE_END); + upipe_srt_handshake_release_urefcount_real(upipe); +} +/** @internal @This allocates an output subpipe of a dup pipe. + * + * @param mgr common management structure + * @param uprobe structure used to raise events + * @param signature signature of the pipe allocator + * @param args optional arguments + * @return pointer to upipe or NULL in case of allocation error + */ +static struct upipe *upipe_srt_handshake_output_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + if (mgr->signature != UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE) + return NULL; + + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_sub_mgr(mgr); + if (upipe_srt_handshake->control) + return NULL; + + struct upipe *upipe = upipe_srt_handshake_output_alloc_void(mgr, uprobe, signature, args); + if (unlikely(upipe == NULL)) + return NULL; + +// struct upipe_srt_handshake_output *upipe_srt_handshake_output = upipe_srt_handshake_output_from_upipe(upipe); + + upipe_srt_handshake->control = upipe; + + upipe_srt_handshake_output_init_urefcount(upipe); + upipe_srt_handshake_output_init_output(upipe); + upipe_srt_handshake_output_init_sub(upipe); + upipe_srt_handshake_output_init_ubuf_mgr(upipe); + upipe_srt_handshake_output_init_uref_mgr(upipe); + + upipe_throw_ready(upipe); + + upipe_srt_handshake_output_require_uref_mgr(upipe); + + return upipe; +} + +static void upipe_srt_handshake_output_shutdown(struct upipe *upipe) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_sub_mgr(upipe->mgr); + + uint64_t now = uclock_now(upipe_srt_handshake->uclock); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + + struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE); + if (!uref) + return; + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_SHUTDOWN); + srt_set_control_packet_subtype(out, 0); + + uref_block_unmap(uref, 0); + upipe_srt_handshake_output_output(upipe, uref, + &upipe_srt_handshake->upump_timer); +} + + +/** @This frees a upipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_handshake_output_free(struct upipe *upipe) +{ + upipe_srt_handshake_output_shutdown(upipe); + upipe_throw_dead(upipe); + + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_sub_mgr(upipe->mgr); + upipe_srt_handshake->control = NULL; + upipe_srt_handshake_output_clean_output(upipe); + upipe_srt_handshake_output_clean_sub(upipe); + upipe_srt_handshake_output_clean_urefcount(upipe); + upipe_srt_handshake_output_clean_ubuf_mgr(upipe); + upipe_srt_handshake_output_clean_uref_mgr(upipe); + upipe_srt_handshake_output_free_void(upipe); +} + +static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_size, uint32_t timestamp, uint8_t **cif) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + int size = SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE + ext_size; + + struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, size); + if (!uref) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return NULL; + } + + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return NULL; + } + + memset(out, 0, output_size); + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_HANDSHAKE); + srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, 0); + + + uint8_t *out_cif = (uint8_t*)srt_get_control_packet_cif(out); + *cif = out_cif; + + srt_set_handshake_syn_cookie(out_cif, upipe_srt_handshake->syn_cookie); + srt_set_handshake_mtu(out_cif, upipe_srt_handshake->mtu); + srt_set_handshake_mfw(out_cif, upipe_srt_handshake->mfw); + srt_set_handshake_socket_id(out_cif, upipe_srt_handshake->socket_id); + srt_set_handshake_isn(out_cif, upipe_srt_handshake->isn); + + srt_set_handshake_ip(out_cif, (const struct sockaddr*)&upipe_srt_handshake->addr); + + srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION); + srt_set_handshake_encryption(out_cif, SRT_HANDSHAKE_CIPHER_NONE); + + return uref; +} + +static void upipe_srt_handshake_timer(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + uint64_t now = uclock_now(upipe_srt_handshake->uclock); + + if (now - upipe_srt_handshake->last_hs_sent < UCLOCK_FREQ / 10) { + return; + } + + //send HS + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, 0, &out_cif); + if (!uref) + return; + + upipe_srt_handshake->establish_time = now; + + srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); // XXX + srt_set_handshake_extension(out_cif, SRT_HANDSHAKE_EXT_KMREQ); // draft-sharabayko-srt-01#section-4.3.1.1 * Extension Field: 2 + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); + + uref_block_unmap(uref, 0); + + /* control goes through subpipe */ + upipe_srt_handshake_output_output(upipe_srt_handshake->control, uref, + &upipe_srt_handshake->upump_timer); + upipe_srt_handshake->last_hs_sent = now; +} + +/** @internal @This sets the input flow definition. + * + * @param upipe description structure of the pipe + * @param flow_def flow definition packet + * @return an error code + */ +static int upipe_srt_handshake_output_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + if (flow_def == NULL) + return UBASE_ERR_INVALID; + UBASE_RETURN(uref_flow_match_def(flow_def, "block.")) + + if (upipe_srt_handshake->control) { + struct uref *flow_def_dup = uref_dup(flow_def); + if (unlikely(flow_def_dup == NULL)) + return UBASE_ERR_ALLOC; + upipe_srt_handshake_output_store_flow_def(upipe_srt_handshake->control, flow_def_dup); + } + + return UBASE_ERR_NONE; +} + +/** @internal @This processes control commands on an output subpipe of a dup + * pipe. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int _upipe_srt_handshake_output_control(struct upipe *upipe, + int command, va_list args) +{ + UBASE_HANDLED_RETURN(upipe_srt_handshake_output_control_super(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_srt_handshake_output_control_output(upipe, command, args)); + switch (command) { + case UPIPE_SET_FLOW_DEF: { + struct uref *flow_def = va_arg(args, struct uref *); + return upipe_srt_handshake_output_set_flow_def(upipe, flow_def); + } + default: + return UBASE_ERR_UNHANDLED; + } +} +static int upipe_srt_handshake_output_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_RETURN(_upipe_srt_handshake_output_control(upipe, command, args)) + return upipe_srt_handshake_output_check(upipe, NULL); +} + +/** @internal @This initializes the output manager for a srt set pipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_handshake_init_sub_mgr(struct upipe *upipe) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + struct upipe_mgr *sub_mgr = &upipe_srt_handshake->sub_mgr; + sub_mgr->refcount = upipe_srt_handshake_to_urefcount_real(upipe_srt_handshake); + sub_mgr->signature = UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE; + sub_mgr->upipe_alloc = upipe_srt_handshake_output_alloc; + sub_mgr->upipe_input = NULL; + sub_mgr->upipe_control = upipe_srt_handshake_output_control; +} + + +/** @internal @This allocates a SRT handshake pipe. + * + * @param mgr common management structure + * @param uprobe structure used to raise events + * @param signature signature of the pipe allocator + * @param args optional arguments + * @return pointer to upipe or NULL in case of allocation error + */ +static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + struct upipe *upipe = upipe_srt_handshake_alloc_void(mgr, uprobe, signature, args); + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + +#ifdef UPIPE_HAVE_GCRYPT_H + if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { + uprobe_err(uprobe, upipe, "Application did not initialize libgcrypt, see " + "https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html"); + upipe_srt_handshake_free_void(upipe); + return NULL; + } +#endif + + upipe_srt_handshake_init_urefcount(upipe); + upipe_srt_handshake_init_urefcount_real(upipe); + upipe_srt_handshake_init_sub_outputs(upipe); + upipe_srt_handshake_init_sub_mgr(upipe); + + upipe_srt_handshake_init_uref_mgr(upipe); + upipe_srt_handshake_init_ubuf_mgr(upipe); + upipe_srt_handshake_init_output(upipe); + + upipe_srt_handshake_init_upump_mgr(upipe); + upipe_srt_handshake_init_upump_timer(upipe); + upipe_srt_handshake_init_uclock(upipe); + upipe_srt_handshake_require_uclock(upipe); + + srand48((long)&uprobe); // FIXME + upipe_srt_handshake->isn = 0; + upipe_srt_handshake->remote_socket_id = 0; // will be set with remote first packet + upipe_srt_handshake->mtu = 1500; + upipe_srt_handshake->mfw = 8192; + upipe_srt_handshake->addr.ss_family = 0; + + upipe_srt_handshake->listener = true; + upipe_srt_handshake->last_hs_sent = 0; + + upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake->control = NULL; + + upipe_srt_handshake->stream_id = NULL; + upipe_srt_handshake->stream_id_len = 0; + + upipe_srt_handshake->receiver_tsbpd_delay = 0; + upipe_srt_handshake->sender_tsbpd_delay = 0; + upipe_srt_handshake->flags = 0; + upipe_srt_handshake->major = 0; + upipe_srt_handshake->minor = 0; + upipe_srt_handshake->patch = 0; + + upipe_srt_handshake->sek_len = 0; + upipe_srt_handshake->password = NULL; + + upipe_throw_ready(upipe); + return upipe; +} + + +/** @internal @This checks if the pump may be allocated. + * + * @param upipe description structure of the pipe + * @param flow_format amended flow format + * @return an error code + */ +static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_format) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + upipe_srt_handshake_check_upump_mgr(upipe); + + if (flow_format != NULL) { + upipe_srt_handshake_store_flow_def(upipe, flow_format); + } + + if (upipe_srt_handshake->uref_mgr == NULL) { + upipe_srt_handshake_require_uref_mgr(upipe); + return UBASE_ERR_NONE; + } + + if (upipe_srt_handshake->ubuf_mgr == NULL) { + struct uref *flow_format = + uref_block_flow_alloc_def(upipe_srt_handshake->uref_mgr, NULL); + if (unlikely(flow_format == NULL)) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return UBASE_ERR_ALLOC; + } + upipe_srt_handshake_require_ubuf_mgr(upipe, flow_format); + return UBASE_ERR_NONE; + } + + if (upipe_srt_handshake->upump_mgr && !upipe_srt_handshake->upump_timer && !upipe_srt_handshake->listener) { + upipe_srt_handshake->socket_id = mrand48(); + upipe_srt_handshake->syn_cookie = 0; + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timer, + upipe, upipe->refcount, + UCLOCK_FREQ/300, UCLOCK_FREQ/300); + upump_start(upump); + upipe_srt_handshake_set_upump_timer(upipe, upump); + } + + return UBASE_ERR_NONE; +} + +/** @internal @This sets the input flow definition. + * + * @param upipe description structure of the pipe + * @param flow_def flow definition packet + * @return an error code + */ +static int upipe_srt_handshake_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + if (flow_def == NULL) + return UBASE_ERR_INVALID; + + const char *def; + UBASE_RETURN(uref_flow_get_def(flow_def, &def)) + + if (ubase_ncmp(def, "block.")) { + upipe_err_va(upipe, "Unknown def %s", def); + return UBASE_ERR_INVALID; + } + + flow_def = uref_dup(flow_def); + if (!flow_def) + return UBASE_ERR_ALLOC; + + upipe_srt_handshake_store_flow_def(upipe, flow_def); + /* force sending flow definition immediately */ + upipe_srt_handshake_output(upipe, NULL, NULL); + + return UBASE_ERR_NONE; +} + +static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *option, + const char *value) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + if (!option || !value) + return UBASE_ERR_INVALID; + + if (!strcmp(option, "listener")) { + upipe_srt_handshake->listener = strcmp(value, "0"); + return UBASE_ERR_NONE; + } + + if (!strcmp(option, "stream_id")) { + free(upipe_srt_handshake->stream_id); + upipe_srt_handshake->stream_id = NULL; + + size_t stream_id_len = (strlen(value) + 3) & ~3; // round up to 4 bytes + uint8_t *stream_id = malloc(stream_id_len); + if (!stream_id) { + return UBASE_ERR_ALLOC; + } + + strncpy(stream_id, value, stream_id_len); + + for (size_t i = 0; i < stream_id_len; i += 4) { + uint8_t tmp = stream_id[i+0]; + stream_id[i+0] = stream_id[i+3]; + stream_id[i+3] = tmp; + tmp = stream_id[i+2]; + stream_id[i+2] = stream_id[i+1]; + stream_id[i+1] = tmp; + } + + upipe_srt_handshake->stream_id = stream_id; + upipe_srt_handshake->stream_id_len = stream_id_len; + return UBASE_ERR_NONE; + } + + upipe_err_va(upipe, "Unknown option %s", option); + return UBASE_ERR_INVALID; +} + +/** @internal @This processes control commands on a SRT handshake pipe. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int _upipe_srt_handshake_control(struct upipe *upipe, + int command, va_list args) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + UBASE_HANDLED_RETURN(upipe_srt_handshake_control_output(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_srt_handshake_control_outputs(upipe, command, args)); + + switch (command) { + case UPIPE_ATTACH_UPUMP_MGR: + upipe_srt_handshake_set_upump_timer(upipe, NULL); + return upipe_srt_handshake_attach_upump_mgr(upipe); + + case UPIPE_SET_FLOW_DEF: { + struct uref *flow = va_arg(args, struct uref *); + return upipe_srt_handshake_set_flow_def(upipe, flow); + } + + case UPIPE_SET_OPTION: { + const char *option = va_arg(args, const char *); + const char *value = va_arg(args, const char *); + return upipe_srt_handshake_set_option(upipe, option, value); + } + + case UPIPE_SRT_HANDSHAKE_SET_PEER: { + UBASE_SIGNATURE_CHECK(args, UPIPE_SRT_HANDSHAKE_SIGNATURE) + const struct sockaddr *s = va_arg(args, const struct sockaddr *); + socklen_t addrlen = va_arg(args, socklen_t); + if (addrlen > sizeof(upipe_srt_handshake->addr)) + addrlen = sizeof(upipe_srt_handshake->addr); + memcpy(&upipe_srt_handshake->addr, s, addrlen); + return UBASE_ERR_NONE; + } + + case UPIPE_SRT_HANDSHAKE_SET_PASSWORD: { + UBASE_SIGNATURE_CHECK(args, UPIPE_SRT_HANDSHAKE_SIGNATURE) + const char *password = va_arg(args, const char*); + free(upipe_srt_handshake->password); + upipe_srt_handshake->password = password ? strdup(password) : NULL; + return UBASE_ERR_NONE; + } + + default: + return UBASE_ERR_UNHANDLED; + } +} + +/** @internal @This processes control commands on a SRT handshake pipe, and + * checks the status of the pipe afterwards. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int upipe_srt_handshake_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_RETURN(_upipe_srt_handshake_control(upipe, command, args)); + + return upipe_srt_handshake_check(upipe, NULL); +} + +static const char ctrl_type[][10] = +{ + [SRT_CONTROL_TYPE_HANDSHAKE] = "handshake", + [SRT_CONTROL_TYPE_KEEPALIVE] = "keepalive", + [SRT_CONTROL_TYPE_ACK] = "ack", + [SRT_CONTROL_TYPE_NAK] = "nak", + [SRT_CONTROL_TYPE_SHUTDOWN] = "shutdown", + [SRT_CONTROL_TYPE_ACKACK] = "ackack", + [SRT_CONTROL_TYPE_DROPREQ] = "dropreq", + [SRT_CONTROL_TYPE_PEERERROR] = "peererror", +}; + +static const char *get_ctrl_type(uint16_t type) +{ + if (type == SRT_CONTROL_TYPE_USER) + return "user"; + if (type >= (sizeof(ctrl_type) / sizeof(*ctrl_type))) + return "?"; + return ctrl_type[type]; +} + +static void upipe_srt_handshake_finalize(struct upipe *upipe) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + upipe_srt_handshake->expect_conclusion = false; + + struct uref *flow_def; + if (ubase_check(upipe_srt_handshake_get_flow_def(upipe, &flow_def))) { + flow_def = uref_dup(flow_def); + if (flow_def) { + uref_flow_set_id(flow_def, upipe_srt_handshake->remote_socket_id); + struct udict_opaque opaque; + opaque.v = upipe_srt_handshake->salt; + opaque.size = 16; + if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) + upipe_err(upipe, "damn"); + + opaque.v = upipe_srt_handshake->sek[0]; + opaque.size = upipe_srt_handshake->sek_len; + if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) + upipe_err(upipe, "damn"); + + // TODO: odd key + + uref_pic_set_number(flow_def, upipe_srt_handshake->isn); + upipe_srt_handshake_store_flow_def(upipe, flow_def); + /* force sending flow definition immediately */ + upipe_srt_handshake_output(upipe, NULL, NULL); + } + } +} + +static void upipe_srt_handshake_parse_hsreq(struct upipe *upipe, const uint8_t *ext) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + srt_get_handshake_extension_srt_version(ext, &upipe_srt_handshake->major, &upipe_srt_handshake->minor, &upipe_srt_handshake->patch); + upipe_dbg_va(upipe, "SRT lib version %u.%u.%u", upipe_srt_handshake->major, upipe_srt_handshake->minor, upipe_srt_handshake->patch); + + uint32_t flags = srt_get_handshake_extension_srt_flags(ext); + upipe_dbg_va(upipe, "%s%s%s%s%s%s%s%s", + (flags & SRT_HANDSHAKE_EXT_FLAG_TSBPDSND) ? "TSBPDSND " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV) ? "TSBPDRCV " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_CRYPT) ? "CRYPT " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP) ? "TLPKTDROP " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK) ? "PERIODICNAK " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_REXMITFLG) ? "REXMITFLG " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_STREAM) ? "STREAM " : "", + (flags & SRT_HANDSHAKE_EXT_FLAG_PACKET_FILTER) ? "PACKET_FILTER " : ""); + upipe_srt_handshake->flags = flags; + + upipe_srt_handshake->receiver_tsbpd_delay = srt_get_handshake_extension_receiver_tsbpd_delay(ext); + upipe_srt_handshake->sender_tsbpd_delay = srt_get_handshake_extension_sender_tsbpd_delay(ext); + upipe_dbg_va(upipe, "tsbpd delays: receiver %u, sender %u", + upipe_srt_handshake->receiver_tsbpd_delay, upipe_srt_handshake->sender_tsbpd_delay); +} + +static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, uint8_t *kk, const uint8_t **wrap, uint8_t *wrap_len) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + if (!upipe_srt_handshake->password) { + upipe_err(upipe, "Password not set"); + return false; + } + +#ifdef UPIPE_HAVE_GCRYPT_H + + *kk = srt_km_get_kk(ext); + uint8_t cipher = srt_km_get_cipher(ext); + if (cipher != SRT_KMREQ_CIPHER_AES) { + upipe_err_va(upipe, "Unsupported cipher %u", cipher); + return false; + } + + uint8_t klen = 4 * srt_km_get_klen(ext); + + memcpy(upipe_srt_handshake->salt, srt_km_get_salt(ext), 16); + + *wrap = srt_km_get_wrap((uint8_t*)ext); + + uint8_t kek[32]; + + gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, + strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, + &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); + if (err) { + upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); + return false; + } + + *wrap_len = ((*kk == 3) ? 2 : 1) * klen + 8; + + uint8_t osek[32]; + + gcry_cipher_hd_t aes; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + return false; + } + + err = gcry_cipher_setkey(aes, kek, klen); + if (err) { + upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); + goto key_error; + } + + err = gcry_cipher_decrypt(aes, osek, 16, *wrap, *wrap_len); + if (err) { + upipe_err_va(upipe, "Couldn't decrypt session key (0x%x)", err); + goto key_error; + } + + gcry_cipher_close(aes); + + upipe_srt_handshake->sek_len = klen; + memcpy(upipe_srt_handshake->sek[0], osek, klen); + + return true; + +key_error: + gcry_cipher_close(aes); + upipe_srt_handshake->sek_len = 0; + upipe_err(upipe, "Couldn't recover encryption key"); + + return false; +#else + upipe_err(upipe, "Encryption not built in"); + return false; +#endif +} + +static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + + uint8_t *out_cif; + const uint8_t *cif = srt_get_control_packet_cif(buf); + if (!srt_check_handshake(cif, size - SRT_HEADER_SIZE)) { + upipe_err(upipe, "Malformed handshake"); + return NULL; + } + + uint32_t version = srt_get_handshake_version(cif); + uint16_t encryption = srt_get_handshake_encryption(cif); + uint16_t extension = srt_get_handshake_extension(cif); + uint32_t hs_type = srt_get_handshake_type(cif); + uint32_t syn_cookie = srt_get_handshake_syn_cookie(cif); + uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); + + if (!upipe_srt_handshake->listener) { + if (upipe_srt_handshake->expect_conclusion) { + upipe_srt_handshake_set_upump_timer(upipe, NULL); + // check + upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); + + upipe_srt_handshake_finalize(upipe); + return NULL; + } + + /* */ + if (version != SRT_HANDSHAKE_VERSION || dst_socket_id != upipe_srt_handshake->socket_id + || hs_type != SRT_HANDSHAKE_TYPE_INDUCTION + ) { + upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", + dst_socket_id, upipe_srt_handshake->socket_id); + return NULL; + } + + upipe_srt_handshake->mtu = srt_get_handshake_mtu(cif); + upipe_srt_handshake->mfw = srt_get_handshake_mfw(cif); + upipe_srt_handshake->isn = srt_get_handshake_isn(cif); + + upipe_dbg_va(upipe, "mtu %u mfw %u isn %u", upipe_srt_handshake->mtu, upipe_srt_handshake->mfw, upipe_srt_handshake->isn); + upipe_verbose_va(upipe, "cookie %08x", syn_cookie); + + upipe_srt_handshake->syn_cookie = syn_cookie; + const size_t ext_size = SRT_HANDSHAKE_HSREQ_SIZE; + size_t size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; + + if (upipe_srt_handshake->password) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + (8+128/8); + extension |= SRT_HANDSHAKE_EXT_KMREQ; + } + if (upipe_srt_handshake->stream_id) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; + extension |= SRT_HANDSHAKE_EXT_CONFIG; + } + + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + if (!uref) + return NULL; + + uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); + + srt_set_handshake_extension(out_cif, extension); + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSREQ); + srt_set_handshake_extension_len(out_ext, ext_size / 4); + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + srt_set_handshake_extension_srt_version(out_ext, 2, 2, 2); // made up version + uint32_t flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK + | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; + srt_set_handshake_extension_srt_flags(out_ext, flags); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, 120); // made up delays + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, 120); + size -= ext_size; + out_ext += ext_size; + + if (upipe_srt_handshake->stream_id) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); + srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); + size -= upipe_srt_handshake->stream_id_len; + out_ext += upipe_srt_handshake->stream_id_len; + } + +#ifdef UPIPE_HAVE_GCRYPT_H + if (upipe_srt_handshake->password) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMREQ); + srt_set_handshake_extension_len(out_ext, (size - SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) / 4); + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + + // XXX: move to bitstream? + // TODO : salt + uint8_t kk = 1; + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + + // TODO wrap + uint8_t wrap[8+128/8] = {0}; + uint8_t klen = 128/8; + + size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; + + gcry_randomize(upipe_srt_handshake->sek[0], klen, GCRY_STRONG_RANDOM); + gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); + + upipe_srt_handshake->sek_len = klen; + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + + uint8_t kek[32]; + gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, + strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, + &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); + if (err) { + upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); + return false; + } + + gcry_cipher_hd_t aes; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + return false; + } + + err = gcry_cipher_setkey(aes, kek, klen); + if (err) { + gcry_cipher_close(aes); + upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); + return false; + } + + err = gcry_cipher_encrypt(aes, wrap, wrap_len, upipe_srt_handshake->sek[0], klen); + if (err) { + gcry_cipher_close(aes); + upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); + return false; + } + + gcry_cipher_close(aes); + + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + } +#endif + + upipe_srt_handshake->expect_conclusion = true; + + uref_block_unmap(uref, 0); + return uref; + } + + if (!upipe_srt_handshake->expect_conclusion) { + if (version != SRT_HANDSHAKE_VERSION_MIN || encryption != SRT_HANDSHAKE_CIPHER_NONE + || extension != SRT_HANDSHAKE_EXT_KMREQ + || hs_type != SRT_HANDSHAKE_TYPE_INDUCTION || + syn_cookie != 0 || dst_socket_id != 0) { + upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", syn_cookie, dst_socket_id); + return NULL; + } + + upipe_srt_handshake->establish_time = now; + timestamp = 0; + upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); + upipe_srt_handshake->socket_id = mrand48(); + upipe_srt_handshake->syn_cookie = mrand48(); + + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + if (!uref) + return NULL; + + srt_set_handshake_extension(out_cif, SRT_MAGIC_CODE); + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); + + upipe_srt_handshake->expect_conclusion = true; + + uref_block_unmap(uref, 0); + return uref; + } else { + if (version != SRT_HANDSHAKE_VERSION + || hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION + || syn_cookie != upipe_srt_handshake->syn_cookie + || dst_socket_id != 0) { + upipe_err(upipe, "Malformed conclusion handshake"); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } + + /* At least HSREQ is expected */ + size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; + if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { + upipe_err(upipe, "Malformed conclusion handshake (size)"); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } + + upipe_srt_handshake->isn = srt_get_handshake_isn(cif); + + uint8_t *ext = srt_get_handshake_extension_buf((uint8_t*)cif); + + uint8_t kk = 0; + const uint8_t *wrap; + uint8_t wrap_len = 0; + + while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { + uint16_t ext_type = srt_get_handshake_extension_type(ext); + uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); + + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + if (ext_len > size) { + upipe_err_va(upipe, "Malformed extension: %u > %u", ext_len, size); + break; + } + + if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSREQ) { + if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) + upipe_srt_handshake_parse_hsreq(upipe, ext); + else + upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, + SRT_HANDSHAKE_HSREQ_SIZE); + } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { + if (!srt_check_km(ext, ext_len) || !upipe_srt_handshake_parse_kmreq(upipe, ext, &kk, &wrap, &wrap_len)) + upipe_err(upipe, "Malformed KMREQ"); + } + + ext += ext_len; + size -= ext_len; + } + + extension = SRT_HANDSHAKE_EXT_HSREQ; + size = SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; + if (wrap_len) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; + extension |= SRT_HANDSHAKE_EXT_KMREQ; + } + if (upipe_srt_handshake->stream_id) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; + extension |= SRT_HANDSHAKE_EXT_CONFIG; + } + + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + if (!uref) + return NULL; + + srt_set_handshake_extension(out_cif, extension); + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); + + ext = srt_get_handshake_extension_buf((uint8_t*)cif); + uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); + + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSRSP); + srt_set_handshake_extension_len(out_ext, SRT_HANDSHAKE_HSREQ_SIZE / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, + upipe_srt_handshake->minor, upipe_srt_handshake->patch); + srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + + out_ext += SRT_HANDSHAKE_HSREQ_SIZE; + + if (upipe_srt_handshake->stream_id) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); + srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); + out_ext += upipe_srt_handshake->stream_id_len; + } + + if (wrap_len) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMRSP); + srt_set_handshake_extension_len(out_ext, (SRT_KMREQ_COMMON_SIZE + wrap_len) / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + // XXX: move to bitstream? + + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + } + + upipe_srt_handshake_finalize(upipe); + + uref_block_unmap(uref, 0); + return uref; + } +} + +static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + + struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + if (!uref) + return NULL; + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_ACKACK); + srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, srt_get_control_packet_type_specific(buf)); + + uref_block_unmap(uref, 0); + return uref; + // should go to sender +} + +static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const uint8_t *buf, int size, bool *handled) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + uint16_t type = srt_get_control_packet_type(buf); + uint64_t now = uclock_now(upipe_srt_handshake->uclock); + + upipe_verbose_va(upipe, "control pkt %s", get_ctrl_type(type)); + *handled = true; + + if (type == SRT_CONTROL_TYPE_HANDSHAKE) { + return upipe_srt_handshake_handle_hs(upipe, buf, size, now); + } else if (type == SRT_CONTROL_TYPE_KEEPALIVE) { + } else if (type == SRT_CONTROL_TYPE_ACK) { + return upipe_srt_handshake_handle_ack(upipe, buf, size, now); + } else if (type == SRT_CONTROL_TYPE_NAK) { + *handled = false; + } else if (type == SRT_CONTROL_TYPE_ACKACK) { + *handled = false; // send to next pipe for RTT estimation + } else if (type == SRT_CONTROL_TYPE_SHUTDOWN) { + upipe_err_va(upipe, "shutdown requested"); + upipe_throw_source_end(upipe); + } else { + *handled = false; + } + + return NULL; +} + +static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, + struct upump **upump_p) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + size_t total_size; + ubase_assert(uref_block_size(uref, &total_size)); + + const uint8_t *buf; + int size = total_size; + + ubase_assert(uref_block_read(uref, 0, &size, &buf)); + assert(size == total_size); + + if (size < SRT_HEADER_SIZE) { + upipe_err_va(upipe, "Packet too small (%d)", size); + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + return; + } + + uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); + if (dst_socket_id && dst_socket_id != upipe_srt_handshake->socket_id) { + upipe_err_va(upipe, "0x%08x != 0x%08x", dst_socket_id, + upipe_srt_handshake->socket_id); + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + return; + } + + if (srt_get_packet_control(buf)) { + bool handled = false; + struct uref *reply = upipe_srt_handshake_input_control(upipe, buf, size, &handled); + ubase_assert(uref_block_unmap(uref, 0)); + if (!handled && !reply) { + upipe_srt_handshake_output(upipe, uref, upump_p); + } else { + uref_free(uref); + if (reply) { + upipe_srt_handshake_output_output(upipe_srt_handshake->control, reply, upump_p); + } + } + } else { + ubase_assert(uref_block_unmap(uref, 0)); + /* let data packets pass through */ + upipe_srt_handshake_output(upipe, uref, upump_p); + } +} + +/** @This frees a upipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_handshake_free(struct upipe *upipe) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + upipe_throw_dead(upipe); + + free(upipe_srt_handshake->password); + free(upipe_srt_handshake->stream_id); + + upipe_srt_handshake_clean_output(upipe); + upipe_srt_handshake_clean_upump_timer(upipe); + upipe_srt_handshake_clean_upump_mgr(upipe); + upipe_srt_handshake_clean_uclock(upipe); + upipe_srt_handshake_clean_ubuf_mgr(upipe); + upipe_srt_handshake_clean_uref_mgr(upipe); + upipe_srt_handshake_clean_urefcount(upipe); + upipe_srt_handshake_clean_urefcount_real(upipe); + upipe_srt_handshake_clean_sub_outputs(upipe); + upipe_srt_handshake_free_void(upipe); +} + +/** module manager static descriptor */ +static struct upipe_mgr upipe_srt_handshake_mgr = { + .refcount = NULL, + .signature = UPIPE_SRT_HANDSHAKE_SIGNATURE, + + .upipe_alloc = upipe_srt_handshake_alloc, + .upipe_input = upipe_srt_handshake_input, + .upipe_control = upipe_srt_handshake_control, + + .upipe_mgr_control = NULL +}; + +/** @This returns the management structure for all SRT handshake sources + * + * @return pointer to manager + */ +struct upipe_mgr *upipe_srt_handshake_mgr_alloc(void) +{ + return &upipe_srt_handshake_mgr; +} diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c new file mode 100644 index 000000000..aa45a070e --- /dev/null +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -0,0 +1,1147 @@ +/* + * Copyright (C) 2023 Open Broadcast Systems Ltd + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module for SRT receivers + */ + +#include "upipe/config.h" +#include "upipe/ubase.h" +#include "upipe/uclock.h" +#include "upipe/uref.h" +#include "upipe/uref_block.h" +#include "upipe/uref_block_flow.h" +#include "upipe/uref_clock.h" +#include "upipe/upipe.h" +#include "upipe/upipe_helper_upipe.h" +#include "upipe/upipe_helper_subpipe.h" +#include "upipe/upipe_helper_urefcount.h" +#include "upipe/upipe_helper_urefcount_real.h" +#include "upipe/upipe_helper_void.h" +#include "upipe/upipe_helper_uref_mgr.h" +#include "upipe/upipe_helper_ubuf_mgr.h" +#include "upipe/upipe_helper_output.h" +#include "upipe/upipe_helper_upump_mgr.h" +#include "upipe/upipe_helper_upump.h" +#include "upipe/upipe_helper_uclock.h" + +#include "upipe-srt/upipe_srt_receiver.h" + +#include + +#include +#include + +#include + +/** @hidden */ +static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_format); + +/** @internal @This is the private context of a SRT receiver pipe. */ +struct upipe_srt_receiver { + /** real refcount management structure */ + struct urefcount urefcount_real; + /** refcount management structure exported to the public structure */ + struct urefcount urefcount; + + struct upipe_mgr sub_mgr; + /** list of output subpipes */ + struct uchain outputs; + + struct upump_mgr *upump_mgr; + struct upump *upump_timer; + struct upump *upump_timer_lost; + struct uclock *uclock; + struct urequest uclock_request; + + + /** uref manager */ + struct uref_mgr *uref_mgr; + /** uref manager request */ + struct urequest uref_mgr_request; + + /** ubuf manager */ + struct ubuf_mgr *ubuf_mgr; + /** flow format packet */ + struct uref *flow_format; + /** ubuf manager request */ + struct urequest ubuf_mgr_request; + + /** pipe acting as output */ + struct upipe *output; + /** flow definition packet */ + struct uref *flow_def; + /** output state */ + enum upipe_helper_output_state output_state; + /** list of output requests */ + struct uchain request_list; + + uint32_t socket_id; + + struct upipe *control; + + struct uchain queue; + /** expected sequence number */ + uint64_t expected_seqnum; + + /** last seq output */ + uint64_t last_output_seqnum; + + uint64_t last_ack; + + uint32_t ack_num; + + /* stats */ + size_t buffered; + size_t nacks; + size_t repaired; + size_t loss; + size_t dups; + + /** buffer latency */ + uint64_t latency; + /** last time a NACK was sent */ + uint64_t last_nack[65536]; + + uint64_t rtt; + + uint8_t salt[16]; + uint8_t sek[2][32]; + uint8_t sek_len; + + /** public upipe structure */ + struct upipe upipe; +}; + +UPIPE_HELPER_UPIPE(upipe_srt_receiver, upipe, UPIPE_SRT_RECEIVER_SIGNATURE) +UPIPE_HELPER_UREFCOUNT(upipe_srt_receiver, urefcount, upipe_srt_receiver_no_input) +UPIPE_HELPER_UREFCOUNT_REAL(upipe_srt_receiver, urefcount_real, upipe_srt_receiver_free); + +UPIPE_HELPER_VOID(upipe_srt_receiver) + +UPIPE_HELPER_OUTPUT(upipe_srt_receiver, output, flow_def, output_state, request_list) +UPIPE_HELPER_UPUMP_MGR(upipe_srt_receiver, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_receiver, upump_timer, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_receiver, upump_timer_lost, upump_mgr) +UPIPE_HELPER_UCLOCK(upipe_srt_receiver, uclock, uclock_request, NULL, upipe_throw_provide_request, NULL) + +UPIPE_HELPER_UREF_MGR(upipe_srt_receiver, uref_mgr, uref_mgr_request, + upipe_srt_receiver_check, + upipe_srt_receiver_register_output_request, + upipe_srt_receiver_unregister_output_request) +UPIPE_HELPER_UBUF_MGR(upipe_srt_receiver, ubuf_mgr, flow_format, ubuf_mgr_request, + upipe_srt_receiver_check, + upipe_srt_receiver_register_output_request, + upipe_srt_receiver_unregister_output_request) + +/** @internal @This is the private context of a SRT receiver output pipe. */ +struct upipe_srt_receiver_output { + /** refcount management structure */ + struct urefcount urefcount; + /** structure for double-linked lists */ + struct uchain uchain; + + /** uref manager */ + struct uref_mgr *uref_mgr; + /** uref manager request */ + struct urequest uref_mgr_request; + + /** ubuf manager */ + struct ubuf_mgr *ubuf_mgr; + /** flow format packet */ + struct uref *flow_format; + /** ubuf manager request */ + struct urequest ubuf_mgr_request; + + /** pipe acting as output */ + struct upipe *output; + /** flow definition packet */ + struct uref *flow_def; + /** output state */ + enum upipe_helper_output_state output_state; + /** list of output requests */ + struct uchain request_list; + + /** public upipe structure */ + struct upipe upipe; +}; + +static int upipe_srt_receiver_output_check(struct upipe *upipe, struct uref *flow_format); +UPIPE_HELPER_UPIPE(upipe_srt_receiver_output, upipe, UPIPE_SRT_RECEIVER_OUTPUT_SIGNATURE) +UPIPE_HELPER_VOID(upipe_srt_receiver_output); +UPIPE_HELPER_UREFCOUNT(upipe_srt_receiver_output, urefcount, upipe_srt_receiver_output_free) +UPIPE_HELPER_OUTPUT(upipe_srt_receiver_output, output, flow_def, output_state, request_list) +UPIPE_HELPER_UREF_MGR(upipe_srt_receiver_output, uref_mgr, uref_mgr_request, + upipe_srt_receiver_output_check, + upipe_srt_receiver_output_register_output_request, + upipe_srt_receiver_output_unregister_output_request) +UPIPE_HELPER_UBUF_MGR(upipe_srt_receiver_output, ubuf_mgr, flow_format, ubuf_mgr_request, + upipe_srt_receiver_output_check, + upipe_srt_receiver_output_register_output_request, + upipe_srt_receiver_output_unregister_output_request) +UPIPE_HELPER_SUBPIPE(upipe_srt_receiver, upipe_srt_receiver_output, output, sub_mgr, outputs, + uchain) + +static int upipe_srt_receiver_output_check(struct upipe *upipe, struct uref *flow_format) +{ + struct upipe_srt_receiver_output *upipe_srt_receiver_output = upipe_srt_receiver_output_from_upipe(upipe); + if (flow_format) + upipe_srt_receiver_output_store_flow_def(upipe, flow_format); + + if (upipe_srt_receiver_output->uref_mgr == NULL) { + upipe_srt_receiver_output_require_uref_mgr(upipe); + return UBASE_ERR_NONE; + } + + if (upipe_srt_receiver_output->ubuf_mgr == NULL) { + struct uref *flow_format = + uref_block_flow_alloc_def(upipe_srt_receiver_output->uref_mgr, NULL); + if (unlikely(flow_format == NULL)) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return UBASE_ERR_ALLOC; + } + upipe_srt_receiver_output_require_ubuf_mgr(upipe, flow_format); + return UBASE_ERR_NONE; + } + + return UBASE_ERR_NONE; +} + +/** @This is called when there is no external reference to the pipe anymore. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_receiver_no_input(struct upipe *upipe) +{ + upipe_srt_receiver_throw_sub_outputs(upipe, UPROBE_SOURCE_END); + upipe_srt_receiver_release_urefcount_real(upipe); +} +/** @internal @This allocates an output subpipe of a dup pipe. + * + * @param mgr common management structure + * @param uprobe structure used to raise events + * @param signature signature of the pipe allocator + * @param args optional arguments + * @return pointer to upipe or NULL in case of allocation error + */ +static struct upipe *upipe_srt_receiver_output_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + if (mgr->signature != UPIPE_SRT_RECEIVER_OUTPUT_SIGNATURE) + return NULL; + + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_sub_mgr(mgr); + if (upipe_srt_receiver->control) + return NULL; + + struct upipe *upipe = upipe_srt_receiver_output_alloc_void(mgr, uprobe, signature, args); + if (unlikely(upipe == NULL)) + return NULL; + + upipe_srt_receiver->control = upipe; + + upipe_srt_receiver_output_init_urefcount(upipe); + upipe_srt_receiver_output_init_output(upipe); + upipe_srt_receiver_output_init_sub(upipe); + upipe_srt_receiver_output_init_ubuf_mgr(upipe); + upipe_srt_receiver_output_init_uref_mgr(upipe); + + upipe_throw_ready(upipe); + + upipe_srt_receiver_output_require_uref_mgr(upipe); + + return upipe; +} + + +/** @This frees a upipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_receiver_output_free(struct upipe *upipe) +{ + //struct upipe_srt_receiver_output *upipe_srt_receiver_output = upipe_srt_receiver_output_from_upipe(upipe); + upipe_throw_dead(upipe); + + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_sub_mgr(upipe->mgr); + upipe_srt_receiver_set_upump_timer_lost(&upipe_srt_receiver->upipe, NULL); + upipe_srt_receiver->control = NULL; + upipe_srt_receiver_output_clean_output(upipe); + upipe_srt_receiver_output_clean_sub(upipe); + upipe_srt_receiver_output_clean_urefcount(upipe); + upipe_srt_receiver_output_clean_ubuf_mgr(upipe); + upipe_srt_receiver_output_clean_uref_mgr(upipe); + upipe_srt_receiver_output_free_void(upipe); +} + +static uint64_t _upipe_srt_receiver_get_rtt(struct upipe *upipe) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + /* VSF TR-06 doesn't give a mean to retrieve RTT, but defaults to 7 + * retransmissions requests per packet. + * XXX: make it configurable ? */ + + uint64_t rtt = upipe_srt_receiver->rtt; + if (!rtt) + rtt = upipe_srt_receiver->latency / 7; + return rtt; +} + + +/** @internal @This periodic timer checks for missing seqnums. + */ +static void upipe_srt_receiver_timer_lost(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + if (upipe_srt_receiver->buffered == 0) + return; + + uint64_t expected_seq = UINT64_MAX; + + uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + + uint64_t now = uclock_now(upipe_srt_receiver->uclock); + + /* space out NACKs a bit more than RTT. XXX: tune me */ + uint64_t next_nack = now - rtt * 12 / 10; + + /* TODO: do not look at the last pkts/s * rtt + * It it too late to send a NACK for these + * XXX: use cr_sys, because pkts/s also accounts for + * the retransmitted packets */ + + struct uchain *uchain; + int holes = 0; + + uint64_t last_received = UINT64_MAX; + + + int s = 1472; /* 1500 - IP - UDP */ + struct uref *pkt = NULL; + uint8_t *cif = NULL; + + ulist_foreach(&upipe_srt_receiver->queue, uchain) { + struct uref *uref = uref_from_uchain(uchain); + uint64_t seqnum = 0; + uref_attr_get_priv(uref, &seqnum); + + if (likely(expected_seq != UINT64_MAX) && seqnum != expected_seq) { + /* hole found */ + upipe_verbose_va(upipe, "Found hole from %"PRIu64" (incl) to %"PRIu64" (excl)", + expected_seq, seqnum); + if (last_received == UINT64_MAX) + last_received = expected_seq - 1; + + for (uint32_t seq = expected_seq; seq != seqnum; seq++) { + /* if packet was lost, we should have detected it already */ + if (upipe_srt_receiver->last_nack[seq & 0xffff] == 0) { + upipe_err_va(upipe, "packet %u missing but was not marked as lost!", seq); + continue; + } + + /* if we sent a NACK not too long ago, do not repeat it */ + /* since NACKs are sent in a batch, break loop if the first packet is too early */ + if (upipe_srt_receiver->last_nack[seq & 0xffff] > next_nack) { + if (0) upipe_err_va(upipe, "Cancelling NACK due to RTT (seq %u diff %"PRId64"", + seq, next_nack - upipe_srt_receiver->last_nack[seq & 0xffff] + ); + goto next; + } + } + + /* update NACK request time */ + for (uint32_t seq = expected_seq; seq != seqnum; seq++) { + upipe_srt_receiver->last_nack[seq & 0xffff] = now; + } + + if (!pkt) { + pkt = uref_block_alloc(upipe_srt_receiver->uref_mgr, upipe_srt_receiver->ubuf_mgr, s); + if (unlikely(!pkt)) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return; + } + + uint8_t *buf; + uref_block_write(pkt, 0, &s, &buf); + memset(buf, 0, s); + + s -= SRT_HEADER_SIZE; + + srt_set_packet_control(buf, true); + srt_set_packet_timestamp(buf, now / 27); + srt_set_packet_dst_socket_id(buf, upipe_srt_receiver->socket_id); + srt_set_control_packet_type(buf, SRT_CONTROL_TYPE_NAK); + srt_set_control_packet_subtype(buf, 0); + cif = (uint8_t*)srt_get_control_packet_cif(buf); + } + + // TODO : if full, transmit and realloc next one + if (seqnum - expected_seq > 1) { + if (s < 8) { + upipe_warn_va(upipe, "NAK FULL"); + break; + } + cif[0] = ((expected_seq >> 24) & 0x7f) | 0x80; + cif[1] = (expected_seq >> 16) & 0xff; + cif[2] = (expected_seq >> 8) & 0xff; + cif[3] = (expected_seq ) & 0xff; + cif[4] = ((seqnum - 1) >> 24) & 0x7f; + cif[5] = ((seqnum - 1) >> 16) & 0xff; + cif[6] = ((seqnum - 1) >> 8) & 0xff; + cif[7] = ((seqnum - 1) ) & 0xff; + s -= 8; + cif += 8; + } else { + cif[0] = (expected_seq >> 24) & 0x7f; + cif[1] = (expected_seq >> 16) & 0xff; + cif[2] = (expected_seq >> 8) & 0xff; + cif[3] = (expected_seq ) & 0xff; + s -= 4; + cif += 4; + if (s < 4) { + upipe_warn_va(upipe, "NAK FULL"); + break; + } + } + + holes++; + } + +next: + expected_seq = (seqnum + 1) & UINT32_MAX; + } + + // A Full ACK control packet is sent every 10 ms and has all the fields of Figure 13. + if (upipe_srt_receiver->last_ack == UINT64_MAX || (now - upipe_srt_receiver->last_ack > UCLOCK_FREQ / 100)) { + struct uref *uref = uref_block_alloc(upipe_srt_receiver->uref_mgr, + upipe_srt_receiver->ubuf_mgr, SRT_HEADER_SIZE + SRT_ACK_CIF_SIZE_3); + // + if (uref) { + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } else { + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, now / 27); + srt_set_packet_dst_socket_id(out, upipe_srt_receiver->socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_ACK); + srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, upipe_srt_receiver->ack_num++); + uint8_t *out_cif = (uint8_t*)srt_get_control_packet_cif(out); + + uint64_t last_seq = 0; + uref_attr_get_priv(uref_from_uchain(upipe_srt_receiver->queue.prev), &last_seq); + if (last_received != UINT64_MAX) + last_seq = last_received; + srt_set_ack_last_ack_seq(out_cif, last_seq); + srt_set_ack_rtt(out_cif, 1000); + srt_set_ack_rtt_variance(out_cif, 100); + srt_set_ack_avail_bufsize(out_cif, 100); + srt_set_ack_packets_receiving_rate(out_cif, 100); + srt_set_ack_estimated_link_capacity(out_cif, 1000); + srt_set_ack_receiving_rate(out_cif, 100000); + + uref_block_unmap(uref, 0); + upipe_srt_receiver->last_ack = now; + assert(upipe_srt_receiver->control); + upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, NULL); + } + } + } + + if (holes) { /* debug stats */ + static uint64_t old; + if (likely(old != 0)) + upipe_verbose_va(upipe, "%d holes after %"PRIu64" ms", + holes, 1000 * (now - old) / UCLOCK_FREQ); + old = now; + + upipe_srt_receiver->nacks += holes; // XXX + + uref_block_unmap(pkt, 0); + + // XXX : date NACK packet? + //uref_clock_set_date_sys(pkt, /* cr */ 0, UREF_DATE_CR); + + uref_block_resize(pkt, 0, 1472 - s); + + upipe_srt_receiver_output_output(upipe_srt_receiver->control, pkt, NULL); + } +} + +/** @internal @This periodic timer remove seqnums from the buffer. + */ +static void upipe_srt_receiver_timer(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + uint64_t now = uclock_now(upipe_srt_receiver->uclock); + + struct uchain *uchain, *uchain_tmp; + ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { + struct uref *uref = uref_from_uchain(uchain); + uint64_t seqnum = 0; + if (!ubase_check(uref_attr_get_priv(uref, &seqnum))) { + upipe_err_va(upipe, "Could not read seqnum from uref"); + } + + uint64_t cr_sys = 0; + if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) + upipe_warn_va(upipe, "Couldn't read cr_sys in %s()", __func__); + + if (now - cr_sys <= upipe_srt_receiver->latency) + break; + + upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); + if (likely(upipe_srt_receiver->last_output_seqnum != UINT64_MAX)) { + uint32_t diff = seqnum - upipe_srt_receiver->last_output_seqnum - 1; + if (diff) { + upipe_srt_receiver->loss += diff; + upipe_dbg_va(upipe, "PKT LOSS: %" PRIu64 " -> %"PRIu64" DIFF %u", + upipe_srt_receiver->last_output_seqnum, seqnum, diff); + } + } + + upipe_srt_receiver->last_output_seqnum = seqnum; + + ulist_delete(uchain); + upipe_srt_receiver_output(upipe, uref, NULL); // XXX: use timer upump ? + + static uint64_t old; + if (now - old > UCLOCK_FREQ) { + upipe_dbg_va(upipe, "level %zu , %zu nacks (repaired %zu, lost %zu, dups %zu)", + upipe_srt_receiver->buffered, upipe_srt_receiver->nacks, + upipe_srt_receiver->repaired, upipe_srt_receiver->loss, + upipe_srt_receiver->dups); + old = now; + } + + if (--upipe_srt_receiver->buffered == 0) { + upipe_warn_va(upipe, "Exhausted buffer"); + upipe_srt_receiver->expected_seqnum = UINT64_MAX; + upipe_srt_receiver->last_output_seqnum = UINT64_MAX; + } + } +} + +static void upipe_srt_receiver_restart_timer(struct upipe *upipe) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + + upipe_srt_receiver_set_upump_timer_lost(upipe, NULL); + if (upipe_srt_receiver->upump_mgr) { + struct upump *upump= + upump_alloc_timer(upipe_srt_receiver->upump_mgr, + upipe_srt_receiver_timer_lost, + upipe, upipe->refcount, + 0, rtt / 10); + upump_start(upump); + upipe_srt_receiver_set_upump_timer_lost(upipe, upump); + } +} + +/** @internal @This sets the input flow definition. + * + * @param upipe description structure of the pipe + * @param flow_def flow definition packet + * @return an error code + */ +static int upipe_srt_receiver_output_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + if (flow_def == NULL) + return UBASE_ERR_INVALID; + UBASE_RETURN(uref_flow_match_def(flow_def, "block.")) + + if (upipe_srt_receiver->control) { + struct uref *flow_def_dup = uref_dup(flow_def); + if (unlikely(flow_def_dup == NULL)) + return UBASE_ERR_ALLOC; + upipe_srt_receiver_output_store_flow_def(upipe_srt_receiver->control, flow_def_dup); + } + + return UBASE_ERR_NONE; +} + +/** @internal @This processes control commands on an output subpipe of a dup + * pipe. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int _upipe_srt_receiver_output_control(struct upipe *upipe, + int command, va_list args) +{ + UBASE_HANDLED_RETURN(upipe_srt_receiver_output_control_super(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_srt_receiver_output_control_output(upipe, command, args)); + switch (command) { + case UPIPE_SET_FLOW_DEF: { + struct uref *flow_def = va_arg(args, struct uref *); + return upipe_srt_receiver_output_set_flow_def(upipe, flow_def); + } + default: + return UBASE_ERR_UNHANDLED; + } +} +static int upipe_srt_receiver_output_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_RETURN(_upipe_srt_receiver_output_control(upipe, command, args)) + return upipe_srt_receiver_output_check(upipe, NULL); +} + +/** @internal @This initializes the output manager for a srt set pipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_receiver_init_sub_mgr(struct upipe *upipe) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + struct upipe_mgr *sub_mgr = &upipe_srt_receiver->sub_mgr; + sub_mgr->refcount = upipe_srt_receiver_to_urefcount_real(upipe_srt_receiver); + sub_mgr->signature = UPIPE_SRT_RECEIVER_OUTPUT_SIGNATURE; + sub_mgr->upipe_alloc = upipe_srt_receiver_output_alloc; + sub_mgr->upipe_input = NULL; + sub_mgr->upipe_control = upipe_srt_receiver_output_control; +} + + +/** @internal @This allocates a SRT receiver pipe. + * + * @param mgr common management structure + * @param uprobe structure used to raise events + * @param signature signature of the pipe allocator + * @param args optional arguments + * @return pointer to upipe or NULL in case of allocation error + */ +static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + struct upipe *upipe = upipe_srt_receiver_alloc_void(mgr, uprobe, signature, args); + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + +#ifdef UPIPE_HAVE_GCRYPT_H + if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { + uprobe_err(uprobe, upipe, "Application did not initialize libgcrypt, see " + "https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html"); + upipe_srt_receiver_free_void(upipe); + return NULL; + } +#endif + + upipe_srt_receiver_init_urefcount(upipe); + upipe_srt_receiver_init_urefcount_real(upipe); + upipe_srt_receiver_init_sub_outputs(upipe); + upipe_srt_receiver_init_sub_mgr(upipe); + + upipe_srt_receiver_init_uref_mgr(upipe); + upipe_srt_receiver_init_ubuf_mgr(upipe); + upipe_srt_receiver_init_output(upipe); + + upipe_srt_receiver_init_upump_mgr(upipe); + upipe_srt_receiver_init_upump_timer(upipe); + upipe_srt_receiver_init_upump_timer_lost(upipe); + upipe_srt_receiver_init_uclock(upipe); + upipe_srt_receiver_require_uclock(upipe); + + // FIXME + upipe_srt_receiver->socket_id = 0; + upipe_srt_receiver->control = NULL; + + ulist_init(&upipe_srt_receiver->queue); + memset(upipe_srt_receiver->last_nack, 0, sizeof(upipe_srt_receiver->last_nack)); + upipe_srt_receiver->rtt = 0; + upipe_srt_receiver->expected_seqnum = UINT64_MAX; + + upipe_srt_receiver->last_output_seqnum = UINT64_MAX; + upipe_srt_receiver->last_ack = UINT64_MAX; + upipe_srt_receiver->ack_num = 0; + upipe_srt_receiver->buffered = 0; + upipe_srt_receiver->nacks = 0; + upipe_srt_receiver->repaired = 0; + upipe_srt_receiver->loss = 0; + upipe_srt_receiver->dups = 0; + + upipe_srt_receiver->latency = UCLOCK_FREQ; + + upipe_srt_receiver->sek_len = 0; + + upipe_throw_ready(upipe); + return upipe; +} + + +/** @internal @This checks if the pump may be allocated. + * + * @param upipe description structure of the pipe + * @param flow_format amended flow format + * @return an error code + */ +static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_format) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + upipe_srt_receiver_check_upump_mgr(upipe); + + if (flow_format != NULL) { + uint64_t latency; + if (!ubase_check(uref_clock_get_latency(flow_format, &latency))) + latency = 0; + uref_clock_set_latency(flow_format, latency + upipe_srt_receiver->latency); + + upipe_srt_receiver_store_flow_def(upipe, flow_format); + } + + if (upipe_srt_receiver->flow_def == NULL) + return UBASE_ERR_NONE; + + if (upipe_srt_receiver->uref_mgr == NULL) { + upipe_srt_receiver_require_uref_mgr(upipe); + return UBASE_ERR_NONE; + } + + if (upipe_srt_receiver->ubuf_mgr == NULL) { + struct uref *flow_format = + uref_block_flow_alloc_def(upipe_srt_receiver->uref_mgr, NULL); + if (unlikely(flow_format == NULL)) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return UBASE_ERR_ALLOC; + } + upipe_srt_receiver_require_ubuf_mgr(upipe, flow_format); + return UBASE_ERR_NONE; + } + + if (upipe_srt_receiver->upump_mgr && !upipe_srt_receiver->upump_timer) { + struct upump *upump = + upump_alloc_timer(upipe_srt_receiver->upump_mgr, + upipe_srt_receiver_timer, + upipe, upipe->refcount, + UCLOCK_FREQ/300, UCLOCK_FREQ/300); + upump_start(upump); + upipe_srt_receiver_set_upump_timer(upipe, upump); + + /* every 10ms, check for lost packets + * interval is reduced each time we get the current RTT from sender */ + upipe_srt_receiver_restart_timer(upipe); + } + + return UBASE_ERR_NONE; +} + +/** @internal @This sets the input flow definition. + * + * @param upipe description structure of the pipe + * @param flow_def flow definition packet + * @return an error code + */ +static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + /* empty buffer */ + upipe_warn(upipe, "Emptying buffer"); + upipe_srt_receiver->expected_seqnum = UINT64_MAX; + upipe_srt_receiver->last_output_seqnum = UINT64_MAX; + struct uchain *uchain, *uchain_tmp; + ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { + ulist_delete(uchain); + } + + if (flow_def == NULL) + return UBASE_ERR_INVALID; + + const char *def; + UBASE_RETURN(uref_flow_get_def(flow_def, &def)) + + if (ubase_ncmp(def, "block.")) { + upipe_err_va(upipe, "Unknown def %s", def); + return UBASE_ERR_INVALID; + } + + uint64_t id; + if (ubase_check(uref_flow_get_id(flow_def, &id))) + upipe_srt_receiver->socket_id = id; + + struct udict_opaque opaque; + if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) { + if (opaque.size > 16) + opaque.size = 16; + memcpy(upipe_srt_receiver->salt, opaque.v, opaque.size); + } + +#ifdef UPIPE_HAVE_GCRYPT_H + if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) { + if (opaque.size > sizeof(upipe_srt_receiver->sek[0])) + opaque.size = sizeof(upipe_srt_receiver->sek[0]); + upipe_srt_receiver->sek_len = opaque.size; + memcpy(upipe_srt_receiver->sek[0], opaque.v, opaque.size); + } +#endif + + flow_def = uref_dup(flow_def); + if (!flow_def) + return UBASE_ERR_ALLOC; + + upipe_srt_receiver_store_flow_def(upipe, flow_def); + + return UBASE_ERR_NONE; +} + +/** @internal @This processes control commands on a SRT receiver pipe. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int _upipe_srt_receiver_control(struct upipe *upipe, + int command, va_list args) +{ + UBASE_HANDLED_RETURN(upipe_srt_receiver_control_output(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_srt_receiver_control_outputs(upipe, command, args)); + + switch (command) { + case UPIPE_ATTACH_UPUMP_MGR: + upipe_srt_receiver_set_upump_timer(upipe, NULL); + upipe_srt_receiver_set_upump_timer_lost(upipe, NULL); + return upipe_srt_receiver_attach_upump_mgr(upipe); + + case UPIPE_SET_FLOW_DEF: { + struct uref *flow = va_arg(args, struct uref *); + return upipe_srt_receiver_set_flow_def(upipe, flow); + } + case UPIPE_SET_OPTION: { + const char *k = va_arg(args, const char *); + const char *v = va_arg(args, const char *); + if (strcmp(k, "latency")) + return UBASE_ERR_INVALID; + + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + upipe_srt_receiver->latency = atoi(v) * UCLOCK_FREQ / 1000; + upipe_dbg_va(upipe, "Set latency to %s msecs", v); + return UBASE_ERR_NONE; + } + default: + return UBASE_ERR_UNHANDLED; + } +} + +/** @internal @This processes control commands on a SRT receiver pipe, and + * checks the status of the pipe afterwards. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int upipe_srt_receiver_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_RETURN(_upipe_srt_receiver_control(upipe, command, args)); + + return upipe_srt_receiver_check(upipe, NULL); +} + +/* returns true if uref was inserted in the queue */ +static bool upipe_srt_receiver_insert_inner(struct upipe *upipe, struct uref *uref, + const uint32_t seqnum, struct uref *next) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + uint64_t next_seqnum = 0; + uref_attr_get_priv(next, &next_seqnum); + + uint32_t diff = seqnum - next_seqnum; + if (!diff) { + upipe_verbose_va(upipe, "dropping duplicate %u", seqnum); + upipe_srt_receiver->dups++; + uref_free(uref); + return true; + } + + /* browse the list until we find a seqnum bigger than ours */ + if (diff < 0x8000000) // seqnum > next_seqnum + return false; + + /* if there's no previous packet we're too late */ + struct uchain *uchain = uref_to_uchain(next); + if (unlikely(ulist_is_first(&upipe_srt_receiver->queue, uchain))) { + upipe_dbg_va(upipe, + "LATE packet drop: Expected %" PRIu64 ", got %u, didn't insert after %"PRIu64, + upipe_srt_receiver->expected_seqnum, seqnum, next_seqnum); + uref_free(uref); + return true; + } + + /* Read previous packet seq & cr_sys */ + uint64_t prev_seqnum = 0, cr_sys = 0; + + struct uref *prev = uref_from_uchain(uchain->prev); + uref_attr_get_priv(prev, &prev_seqnum); + + /* overwrite this uref' cr_sys with previous one's + * so it get scheduled at the right time */ + if (ubase_check(uref_clock_get_cr_sys(prev, &cr_sys))) + uref_clock_set_cr_sys(uref, cr_sys); + else + upipe_err_va(upipe, "Couldn't read cr_sys in %s() - %zu buffered", + __func__, upipe_srt_receiver->buffered); + + upipe_srt_receiver->buffered++; + ulist_insert(uchain->prev, uchain, uref_to_uchain(uref)); + upipe_srt_receiver->repaired++; + upipe_srt_receiver->last_nack[seqnum & 0xffff] = 0; + + upipe_verbose_va(upipe, "Repaired %"PRIu64" > %u > %"PRIu64" -diff %d", + prev_seqnum, seqnum, next_seqnum, -diff); + + return true; +} + +static bool upipe_srt_receiver_insert(struct upipe *upipe, struct uref *uref, const uint32_t seqnum) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + struct uchain *uchain, *uchain_tmp; + ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { + struct uref *next = uref_from_uchain(uchain); + if (upipe_srt_receiver_insert_inner(upipe, uref, seqnum, next)) + return true; + } + + /* Could not insert packet */ + return false; +} + +static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, + struct upump **upump_p) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + size_t total_size; + ubase_assert(uref_block_size(uref, &total_size)); + + const uint8_t *buf; + int size = total_size; + + ubase_assert(uref_block_read(uref, 0, &size, &buf)); + assert(size == total_size); + + if (size < SRT_HEADER_SIZE) { + upipe_err_va(upipe, "Packet too small (%d)", size); + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + return; + } + + if (srt_get_packet_control(buf)) { + if (srt_get_control_packet_type(buf) == SRT_CONTROL_TYPE_ACKACK) { + uint32_t ack_num = srt_get_control_packet_type_specific(buf); + (void)ack_num; // TODO: check ack_num ? keep a rotating list of acks ? + uint64_t now = uclock_now(upipe_srt_receiver->uclock); + upipe_srt_receiver->rtt = now - upipe_srt_receiver->last_ack; + } + + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + return; + } + + /* data */ + assert(upipe_srt_receiver->control); + + uint32_t seqnum = srt_get_data_packet_seq(buf); + uint32_t position = srt_get_data_packet_position(buf); + bool order = srt_get_data_packet_order(buf); + uint8_t encryption = srt_get_data_packet_encryption(buf); + bool retransmit = srt_get_data_packet_retransmit(buf); + uint32_t num = srt_get_data_packet_message_number(buf); + uint32_t ts = srt_get_packet_timestamp(buf); + + ubase_assert(uref_block_unmap(uref, 0)); + uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ + total_size -= SRT_HEADER_SIZE; + +// upipe_dbg_va(upipe, "Data seq %u", seqnum); + + (void)order; + (void)num; + (void)retransmit; // stats? + (void)ts; // TODO (µs) + + /* store seqnum in uref */ + uref_attr_set_priv(uref, seqnum); + if (position != 3) { + upipe_err_va(upipe, "PP %d not handled for live streaming", position); + uref_free(uref); + return; + } + + if (encryption != SRT_DATA_ENCRYPTION_CLEAR) { + if (upipe_srt_receiver->sek_len == 0) { + upipe_err(upipe, "Encryption not handled"); + uref_free(uref); + return; +#ifdef UPIPE_HAVE_GCRYPT_H + } else { + const uint8_t *salt = upipe_srt_receiver->salt; + const uint8_t *sek = upipe_srt_receiver->sek[0]; + int key_len = upipe_srt_receiver->sek_len; + + uint8_t iv[16]; + memset(&iv, 0, 16); + iv[10] = (seqnum >> 24) & 0xff; + iv[11] = (seqnum >> 16) & 0xff; + iv[12] = (seqnum >> 8) & 0xff; + iv[13] = seqnum & 0xff; + for (int i = 0; i < 112/8; i++) + iv[i] ^= salt[i]; + + uint8_t *buf; + size = total_size; + + ubase_assert(uref_block_write(uref, 0, &size, &buf)); + assert(size == total_size); + + gcry_cipher_hd_t aes; + gpg_error_t err; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + goto error; + } + + err = gcry_cipher_setkey(aes, sek, key_len); + if (err) { + upipe_err_va(upipe, "Couldn't set session key (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_setctr(aes, iv, 16); + if (err) { + upipe_err_va(upipe, "Couldn't set ctr (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_encrypt(aes, buf, size, NULL, 0); + if (err) { + upipe_err_va(upipe, "Couldn't decrypt packet (0x%x)", err); + goto error_close; + } + +error_close: + gcry_cipher_close(aes); +error: + uref_block_unmap(uref, 0); +#endif + } + } + + /* first packet */ + if (unlikely(upipe_srt_receiver->expected_seqnum == UINT64_MAX)) + upipe_srt_receiver->expected_seqnum = seqnum; + + uint32_t diff = seqnum - upipe_srt_receiver->expected_seqnum; + + if (diff < 0x80000000U) { // seqnum > last seq, insert at the end + /* packet is from the future */ + upipe_srt_receiver->buffered++; + ulist_add(&upipe_srt_receiver->queue, uref_to_uchain(uref)); + upipe_srt_receiver->last_nack[seqnum & 0xffff] = 0; + + if (diff != 0) { + uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + /* wait a bit to send a NACK, in case of reordering */ + uint64_t fake_last_nack = uclock_now(upipe_srt_receiver->uclock) - rtt; + for (uint32_t seq = upipe_srt_receiver->expected_seqnum; seq != seqnum; seq++) + if (upipe_srt_receiver->last_nack[seq & 0xffff] == 0) + upipe_srt_receiver->last_nack[seq & 0xffff] = fake_last_nack; + } + + upipe_srt_receiver->expected_seqnum = seqnum + 1; + return; + } + + /* packet is from the past, reordered or retransmitted */ + if (upipe_srt_receiver_insert(upipe, uref, seqnum)) + return; + + uint64_t first_seq = 0, last_seq = 0; + uref_attr_get_priv(uref_from_uchain(upipe_srt_receiver->queue.next), &first_seq); + uref_attr_get_priv(uref_from_uchain(upipe_srt_receiver->queue.prev), &last_seq); + // XXX : when much too late, it could mean RTP source restart + upipe_err_va(upipe, "LATE packet %u, dropped (buffered %"PRIu64" -> %"PRIu64")", + seqnum, first_seq, last_seq); +} + +/** @This frees a upipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_receiver_free(struct upipe *upipe) +{ + upipe_throw_dead(upipe); + + upipe_srt_receiver_clean_output(upipe); + upipe_srt_receiver_clean_upump_timer(upipe); + upipe_srt_receiver_clean_upump_timer_lost(upipe); + upipe_srt_receiver_clean_upump_mgr(upipe); + upipe_srt_receiver_clean_uclock(upipe); + upipe_srt_receiver_clean_ubuf_mgr(upipe); + upipe_srt_receiver_clean_uref_mgr(upipe); + upipe_srt_receiver_clean_urefcount(upipe); + upipe_srt_receiver_clean_urefcount_real(upipe); + upipe_srt_receiver_clean_sub_outputs(upipe); + upipe_srt_receiver_free_void(upipe); +} + +/** module manager static descriptor */ +static struct upipe_mgr upipe_srt_receiver_mgr = { + .refcount = NULL, + .signature = UPIPE_SRT_RECEIVER_SIGNATURE, + + .upipe_alloc = upipe_srt_receiver_alloc, + .upipe_input = upipe_srt_receiver_input, + .upipe_control = upipe_srt_receiver_control, + + .upipe_mgr_control = NULL +}; + +/** @This returns the management structure for all SRT receiver sources + * + * @return pointer to manager + */ +struct upipe_mgr *upipe_srt_receiver_mgr_alloc(void) +{ + return &upipe_srt_receiver_mgr; +} diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c new file mode 100644 index 000000000..f785bc254 --- /dev/null +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -0,0 +1,748 @@ +/* + * Copyright (C) 2023 Open Broadcast Systems Ltd + * + * Authors: Rafaël Carré + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + */ + +/** @file + * @short Upipe module for SRT senders + */ + +#include "upipe/config.h" +#include "upipe/ubase.h" +#include "upipe/uprobe.h" +#include "upipe/uref.h" +#include "upipe/uclock.h" +#include "upipe/uref_clock.h" +#include "upipe/upipe.h" +#include "upipe/uref_block.h" +#include "upipe/uref_block_flow.h" +#include "upipe/uref_pic.h" // XXX +#include "upipe/uref_flow.h" +#include "upipe/upipe_helper_upipe.h" +#include "upipe/upipe_helper_subpipe.h" +#include "upipe/upipe_helper_urefcount.h" +#include "upipe/upipe_helper_urefcount_real.h" +#include "upipe/upipe_helper_void.h" +#include "upipe/upipe_helper_output.h" +#include "upipe/upipe_helper_uref_mgr.h" +#include "upipe/upipe_helper_ubuf_mgr.h" +#include "upipe/upipe_helper_upump_mgr.h" +#include "upipe/upipe_helper_upump.h" +#include "upipe/upipe_helper_uclock.h" +#include "upipe-srt/upipe_srt_sender.h" + +#include + +#include + +#include + +#define EXPECTED_FLOW_DEF "block." + +/** upipe_srt_sender structure */ +struct upipe_srt_sender { + /** real refcount management structure */ + struct urefcount urefcount_real; + /** refcount management structure exported to the public structure */ + struct urefcount urefcount; + + /** uref manager */ + struct uref_mgr *uref_mgr; + /** uref manager request */ + struct urequest uref_mgr_request; + + /** ubuf mgr structures */ + struct ubuf_mgr *ubuf_mgr; + struct urequest ubuf_mgr_request; + struct uref *flow_format; + + struct upipe_mgr sub_mgr; + + struct upump_mgr *upump_mgr; + struct upump *upump_timer; + struct uclock *uclock; + struct urequest uclock_request; + struct uchain queue; + + /** list of input subpipes */ + struct uchain inputs; + + /** output pipe */ + struct upipe *output; + /** flow definition packet */ + struct uref *flow_def; + /** output state */ + enum upipe_helper_output_state output_state; + /** list of output requests */ + struct uchain request_list; + + uint32_t syn_cookie; + uint32_t socket_id; + uint32_t seqnum; + + uint64_t establish_time; + + /** buffer latency */ + uint64_t latency; + + uint8_t salt[16]; + uint8_t sek[2][32]; + uint8_t sek_len; + + /** public upipe structure */ + struct upipe upipe; +}; + +static int upipe_srt_sender_check(struct upipe *upipe, struct uref *flow_format); + +UPIPE_HELPER_UPIPE(upipe_srt_sender, upipe, UPIPE_SRT_SENDER_SIGNATURE); +UPIPE_HELPER_UREFCOUNT(upipe_srt_sender, urefcount, upipe_srt_sender_no_input); +UPIPE_HELPER_UREFCOUNT_REAL(upipe_srt_sender, urefcount_real, upipe_srt_sender_free); +UPIPE_HELPER_VOID(upipe_srt_sender); +UPIPE_HELPER_OUTPUT(upipe_srt_sender, output, flow_def, output_state, request_list); +UPIPE_HELPER_UREF_MGR(upipe_srt_sender, uref_mgr, uref_mgr_request, + upipe_srt_sender_check, + upipe_srt_sender_register_output_request, + upipe_srt_sender_unregister_output_request) +UPIPE_HELPER_UBUF_MGR(upipe_srt_sender, ubuf_mgr, flow_format, ubuf_mgr_request, + upipe_srt_sender_check, + upipe_srt_sender_register_output_request, + upipe_srt_sender_unregister_output_request) +UPIPE_HELPER_UPUMP_MGR(upipe_srt_sender, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_sender, upump_timer, upump_mgr) +UPIPE_HELPER_UCLOCK(upipe_srt_sender, uclock, uclock_request, + upipe_srt_sender_check, upipe_throw_provide_request, NULL) + +struct upipe_srt_sender_input { + /** refcount management structure */ + struct urefcount urefcount; + /** structure for double-linked lists */ + struct uchain uchain; + /** public upipe structure */ + struct upipe upipe; +}; + +static const char ctrl_type[][10] = +{ + [SRT_CONTROL_TYPE_HANDSHAKE] = "handshake", + [SRT_CONTROL_TYPE_KEEPALIVE] = "keepalive", + [SRT_CONTROL_TYPE_ACK] = "ack", + [SRT_CONTROL_TYPE_NAK] = "nak", + [SRT_CONTROL_TYPE_SHUTDOWN] = "shutdown", + [SRT_CONTROL_TYPE_ACKACK] = "ackack", + [SRT_CONTROL_TYPE_DROPREQ] = "dropreq", + [SRT_CONTROL_TYPE_PEERERROR] = "peererror", +}; + +static const char *get_ctrl_type(uint16_t type) +{ + if (type == SRT_CONTROL_TYPE_USER) + return "user"; + if (type >= (sizeof(ctrl_type) / sizeof(*ctrl_type))) + return "?"; + return ctrl_type[type]; +} + +static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts); + +/** @internal @This handles SRT messages. + * + * @param upipe description structure of the pipe + * @param uref uref structure + * @param upump_p reference to pump that generated the buffer + */ +static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, + struct upump **upump_p) +{ + size_t total_size; + ubase_assert(uref_block_size(uref, &total_size)); + + const uint8_t *buf; + int size = total_size; + + ubase_assert(uref_block_read(uref, 0, &size, &buf)); + assert(size == total_size); + + if (size < SRT_HEADER_SIZE || !srt_get_packet_control(buf)) { + upipe_err_va(upipe, "Invalid SRT control packet (%d)", size); + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + return; + } + + uint16_t type = srt_get_control_packet_type(buf); + //upipe_dbg_va(upipe, "control pkt %s", get_ctrl_type(type)); + + if (type == SRT_CONTROL_TYPE_NAK) { + buf += SRT_HEADER_SIZE; + size -= SRT_HEADER_SIZE; + size_t s = size; + uint32_t seq; + uint32_t packets; + while (srt_get_nak_range(&buf, &s, &seq, &packets)) { + upipe_srt_sender_lost_sub_n(upipe, seq, packets); + } + } + + uref_block_unmap(uref, 0); + uref_free(uref); +} + +UPIPE_HELPER_UPIPE(upipe_srt_sender_input, upipe, UPIPE_SRT_SENDER_INPUT_SIGNATURE) +UPIPE_HELPER_UREFCOUNT(upipe_srt_sender_input, urefcount, upipe_srt_sender_input_free) +UPIPE_HELPER_VOID(upipe_srt_sender_input); +UPIPE_HELPER_SUBPIPE(upipe_srt_sender, upipe_srt_sender_input, output, sub_mgr, inputs, + uchain) + +/** @internal @This retransmits a number of packets */ +static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts) +{ + struct upipe *upipe_super = NULL; + upipe_srt_sender_input_get_super(upipe, &upipe_super); + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); + + struct uchain *uchain; + ulist_foreach(&upipe_srt_sender->queue, uchain) { + struct uref *uref = uref_from_uchain(uchain); + uint64_t uref_seqnum = 0; + uref_attr_get_priv(uref, &uref_seqnum); + + uint32_t diff = uref_seqnum - seq; + if (diff >= pkts) { + /* packet not in range */ + if (diff < 0x80000000) { + /* packet after range */ + return; + } + continue; + } + + upipe_verbose_va(upipe, "Retransmit %" PRIu64, uref_seqnum); + + uint8_t *buf; + int s = 0; + if (ubase_check(uref_block_write(uref, 0, &s, &buf))) { + srt_set_data_packet_retransmit(buf, true); + uref_block_unmap(uref, 0); + } + + upipe_srt_sender_output(upipe_super, uref_dup(uref), NULL); + } +} + +/** @This is called when there is no external reference to the pipe anymore. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_sender_no_input(struct upipe *upipe) +{ + upipe_srt_sender_throw_sub_outputs(upipe, UPROBE_SOURCE_END); + upipe_srt_sender_release_urefcount_real(upipe); +} + +/** @internal @This allocates an output subpipe of a dup pipe. + * + * @param mgr common management structure + * @param uprobe structure used to raise events + * @param signature signature of the pipe allocator + * @param args optional arguments + * @return pointer to upipe or NULL in case of allocation error + */ +static struct upipe *upipe_srt_sender_input_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + struct upipe *upipe = + upipe_srt_sender_input_alloc_void(mgr, uprobe, signature, args); + if (unlikely(upipe == NULL)) + return NULL; + + upipe_srt_sender_input_init_urefcount(upipe); + upipe_srt_sender_input_init_sub(upipe); + + upipe_throw_ready(upipe); + return upipe; +} + +/** @This frees a upipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_sender_input_free(struct upipe *upipe) +{ + upipe_throw_dead(upipe); + + upipe_srt_sender_input_clean_sub(upipe); + upipe_srt_sender_input_clean_urefcount(upipe); + upipe_srt_sender_input_free_void(upipe); +} + +/** @internal this timer removes from the queue packets that are too + * early to be recovered by receiver. + */ +static void upipe_srt_sender_timer(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + + uint64_t now = uclock_now(upipe_srt_sender->uclock); + + struct uchain *uchain, *uchain_tmp; + ulist_delete_foreach(&upipe_srt_sender->queue, uchain, uchain_tmp) { + struct uref *uref = uref_from_uchain(uchain); + + uint64_t seqnum = 0; + uref_attr_get_priv(uref, &seqnum); + + uint64_t cr_sys = 0; + if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) + upipe_warn(upipe, "Couldn't read cr_sys"); + + if (now - cr_sys < upipe_srt_sender->latency * UCLOCK_FREQ / 1000) + return; + + upipe_verbose_va(upipe, "Delete seq %" PRIu64 " after %"PRIu64" clocks", + seqnum, now - cr_sys); + + ulist_delete(uchain); + uref_free(uref); + } +} + +static int upipe_srt_sender_check(struct upipe *upipe, struct uref *flow_format) +{ + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + + if (flow_format != NULL) + upipe_srt_sender_store_flow_def(upipe, flow_format); + + if (upipe_srt_sender->flow_def == NULL) + return UBASE_ERR_NONE; + + if (upipe_srt_sender->uref_mgr == NULL) { + upipe_srt_sender_require_uref_mgr(upipe); + return UBASE_ERR_NONE; + } + + if (upipe_srt_sender->uclock == NULL) { + upipe_srt_sender_require_uclock(upipe); + return UBASE_ERR_NONE; + } + + if (upipe_srt_sender->ubuf_mgr == NULL) { + struct uref *flow_format = + uref_block_flow_alloc_def(upipe_srt_sender->uref_mgr, NULL); + if (unlikely(flow_format == NULL)) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return UBASE_ERR_ALLOC; + } + upipe_srt_sender_require_ubuf_mgr(upipe, flow_format); + return UBASE_ERR_NONE; + } + + upipe_srt_sender_check_upump_mgr(upipe); + if (upipe_srt_sender->upump_mgr == NULL) + return UBASE_ERR_NONE; + + if (upipe_srt_sender->upump_timer == NULL) { + upipe_srt_sender->establish_time = uclock_now(upipe_srt_sender->uclock); // FIXME + struct upump *upump = + upump_alloc_timer(upipe_srt_sender->upump_mgr, + upipe_srt_sender_timer, upipe, upipe->refcount, + UCLOCK_FREQ, UCLOCK_FREQ); + upump_start(upump); + + upipe_srt_sender_set_upump_timer(upipe, upump); + } + + return UBASE_ERR_NONE; +} + +/** @internal */ +static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + struct upipe *upipe_super = NULL; + upipe_srt_sender_input_get_super(upipe, &upipe_super); + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); + + if (flow_def == NULL) + return UBASE_ERR_INVALID; + + uint64_t id; + if (ubase_check(uref_flow_get_id(flow_def, &id))) + upipe_srt_sender->socket_id = id; + + uint64_t isn; + if (ubase_check(uref_pic_get_number(flow_def, &isn))) + upipe_srt_sender->seqnum = isn; + + struct udict_opaque opaque; + if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) { + if (opaque.size > 16) + opaque.size = 16; + memcpy(upipe_srt_sender->salt, opaque.v, opaque.size); + } + +#ifdef UPIPE_HAVE_GCRYPT_H + if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) { + if (opaque.size > sizeof(upipe_srt_sender->sek[0])) + opaque.size = sizeof(upipe_srt_sender->sek[0]); + upipe_srt_sender->sek_len = opaque.size; + memcpy(upipe_srt_sender->sek[0], opaque.v, opaque.size); + } +#endif + + return uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF); +} + +/** @internal @This processes control commands on an output subpipe of a dup + * pipe. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int upipe_srt_sender_input_control(struct upipe *upipe, + int command, va_list args) +{ + UBASE_HANDLED_RETURN( + upipe_srt_sender_input_control_super(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_control_provide_request(upipe, command, args)); + switch (command) { + case UPIPE_SET_FLOW_DEF: { + struct uref *flow_def = va_arg(args, struct uref *); + return upipe_srt_sender_input_set_flow_def(upipe, flow_def); + } + default: + return UBASE_ERR_UNHANDLED; + } +} + +/** @internal @This initializes the output manager for a srt_sender set pipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_srt_sender_init_sub_mgr(struct upipe *upipe) +{ + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + struct upipe_mgr *sub_mgr = &upipe_srt_sender->sub_mgr; + sub_mgr->refcount = upipe_srt_sender_to_urefcount_real(upipe_srt_sender); + sub_mgr->signature = UPIPE_SRT_SENDER_INPUT_SIGNATURE; + sub_mgr->upipe_alloc = upipe_srt_sender_input_alloc; + sub_mgr->upipe_input = upipe_srt_sender_input_sub; + sub_mgr->upipe_control = upipe_srt_sender_input_control; +} + +/** @internal @This allocates a srt_sender pipe. + * + * @param mgr common management structure + * @param uprobe structure used to raise events + * @param signature signature of the pipe allocator + * @param args optional arguments + * @return pointer to upipe or NULL in case of allocation error + */ +static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + struct upipe *upipe = upipe_srt_sender_alloc_void(mgr, uprobe, signature, args); + if (unlikely(upipe == NULL)) + return NULL; + +#ifdef UPIPE_HAVE_GCRYPT_H + if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { + uprobe_err(uprobe, upipe, "Application did not initialize libgcrypt, see " + "https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html"); + upipe_srt_sender_free_void(upipe); + return NULL; + } +#endif + + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + upipe_srt_sender_init_urefcount(upipe); + upipe_srt_sender_init_urefcount_real(upipe); + upipe_srt_sender_init_upump_mgr(upipe); + upipe_srt_sender_init_upump_timer(upipe); + upipe_srt_sender_init_uclock(upipe); + upipe_srt_sender_init_output(upipe); + upipe_srt_sender_init_sub_outputs(upipe); + upipe_srt_sender_init_sub_mgr(upipe); + upipe_srt_sender_init_ubuf_mgr(upipe); + upipe_srt_sender_init_uref_mgr(upipe); + ulist_init(&upipe_srt_sender->queue); + upipe_srt_sender->latency = 1000; /* 1 sec */ + upipe_srt_sender->socket_id = 0; + upipe_srt_sender->seqnum = 0; + upipe_srt_sender->syn_cookie = 1; + + upipe_srt_sender->sek_len = 0; + + upipe_throw_ready(upipe); + return upipe; +} + +/** @internal @This handles data. + * + * @param upipe description structure of the pipe + * @param uref uref structure + * @param upump_p reference to pump that generated the buffer + */ +static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref, + struct upump **upump_p) +{ + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + + upipe_srt_sender_check(upipe, NULL); + + if (!upipe_srt_sender->ubuf_mgr) { + uref_free(uref); + return; + } + + if (upipe_srt_sender->socket_id == 0) { + uref_free(uref); + return; + } + + struct ubuf *insert = ubuf_block_alloc(upipe_srt_sender->ubuf_mgr, SRT_HEADER_SIZE); + if (!insert) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + uref_free(uref); + return; + } + + uint8_t *buf; + int s = -1; + if (unlikely(!ubase_check(ubuf_block_write(insert, 0, &s, &buf)))) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + ubuf_free(insert); + uref_free(uref); + return; + } + + uint64_t now = uclock_now(upipe_srt_sender->uclock); + + uint32_t seqnum = upipe_srt_sender->seqnum++; + memset(buf, 0, SRT_HEADER_SIZE); + srt_set_packet_control(buf, false); + srt_set_packet_timestamp(buf, (now - upipe_srt_sender->establish_time) / 27); + srt_set_packet_dst_socket_id(buf, upipe_srt_sender->socket_id); + srt_set_data_packet_message_number(buf, seqnum); + srt_set_data_packet_seq(buf, seqnum); + srt_set_data_packet_position(buf, SRT_DATA_POSITION_ONLY); + srt_set_data_packet_order(buf, true); + srt_set_data_packet_retransmit(buf, false); + +#ifdef UPIPE_HAVE_GCRYPT_H + if (upipe_srt_sender->sek_len) { + // + uint8_t *data; + int s = -1; + if (ubase_check(uref_block_write(uref, 0, &s, &data))) { + const uint8_t *salt = upipe_srt_sender->salt; + const uint8_t *sek = upipe_srt_sender->sek[0]; + int key_len = upipe_srt_sender->sek_len; + + uint8_t iv[16]; + memset(&iv, 0, 16); + iv[10] = (seqnum >> 24) & 0xff; + iv[11] = (seqnum >> 16) & 0xff; + iv[12] = (seqnum >> 8) & 0xff; + iv[13] = seqnum & 0xff; + for (int i = 0; i < 112/8; i++) + iv[i] ^= salt[i]; + + gcry_cipher_hd_t aes; + gpg_error_t err; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + goto error; + } + + err = gcry_cipher_setkey(aes, sek, key_len); + if (err) { + upipe_err_va(upipe, "Couldn't set session key (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_setctr(aes, iv, 16); + if (err) { + upipe_err_va(upipe, "Couldn't set encryption ctr (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_encrypt(aes, data, s, NULL, 0); + if (err) { + upipe_err_va(upipe, "Couldn't encrypt packet (0x%x)", err); + goto error_close; + } + +error_close: + gcry_cipher_close(aes); +error: + uref_block_unmap(uref, 0); + + if (err) { + upipe_err(upipe, "Dropping packet"); + ubuf_block_unmap(insert, 0); + ubuf_free(insert); + uref_free(uref); + return; + } + } + + // + srt_set_data_packet_encryption(buf, SRT_DATA_ENCRYPTION_EVEN); + } else +#endif + srt_set_data_packet_encryption(buf, SRT_DATA_ENCRYPTION_CLEAR); + + ubuf_block_unmap(insert, 0); + if (!ubase_check(uref_block_insert(uref, 0, insert))) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + ubuf_free(insert); + uref_free(uref); + return; + } + + uref_attr_set_priv(uref, seqnum); + + /* Output packet immediately */ + upipe_srt_sender_output(upipe, uref_dup(uref), upump_p); + + upipe_verbose_va(upipe, "Output & buffer %u", seqnum); + + /* Buffer packet in case retransmission is needed */ + ulist_add(&upipe_srt_sender->queue, uref_to_uchain(uref)); +} + +/** @internal @This sets the input flow definition. + * + * @param upipe description structure of the pipe + * @param flow_def flow definition packet + * @return an error code + */ +static int upipe_srt_sender_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + if (flow_def == NULL) + return UBASE_ERR_INVALID; + UBASE_RETURN(uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF)) + struct uref *flow_def_dup; + if (unlikely((flow_def_dup = uref_dup(flow_def)) == NULL)) + return UBASE_ERR_ALLOC; + upipe_srt_sender_store_flow_def(upipe, flow_def_dup); + + return UBASE_ERR_NONE; +} + +/** @internal @This processes control commands on a srt_sender pipe. + * + * @param upipe description structure of the pipe + * @param command type of command to process + * @param args arguments of the command + * @return an error code + */ +static int _upipe_srt_sender_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_HANDLED_RETURN(upipe_srt_sender_control_output(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_srt_sender_control_outputs(upipe, command, args)); + switch (command) { + case UPIPE_ATTACH_UPUMP_MGR: + upipe_srt_sender_set_upump_timer(upipe, NULL); + return upipe_srt_sender_attach_upump_mgr(upipe); + case UPIPE_ATTACH_UCLOCK: + upipe_srt_sender_set_upump_timer(upipe, NULL); + upipe_srt_sender_require_uclock(upipe); + return UBASE_ERR_NONE; + case UPIPE_SET_FLOW_DEF: { + struct uref *flow_def = va_arg(args, struct uref *); + return upipe_srt_sender_set_flow_def(upipe, flow_def); + } + case UPIPE_SET_OPTION: { + const char *k = va_arg(args, const char *); + const char *v = va_arg(args, const char *); + if (strcmp(k, "latency")) + return UBASE_ERR_INVALID; + + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + upipe_srt_sender->latency = atoi(v) * UCLOCK_FREQ / 1000; + upipe_dbg_va(upipe, "Set latency to %s msecs", v); + return UBASE_ERR_NONE; + } + default: + return UBASE_ERR_UNHANDLED; + } +} + +static int upipe_srt_sender_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_RETURN(_upipe_srt_sender_control(upipe, command, args)) + return upipe_srt_sender_check(upipe, NULL); +} + +/** @internal @This frees all resources allocated. + * + * @param upipe the public structure of the pipe + */ +static void upipe_srt_sender_free(struct upipe *upipe) +{ + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); + + upipe_throw_dead(upipe); + + upipe_srt_sender_clean_output(upipe); + upipe_srt_sender_clean_sub_outputs(upipe); + upipe_srt_sender_clean_urefcount_real(upipe); + upipe_srt_sender_clean_urefcount(upipe); + upipe_srt_sender_clean_ubuf_mgr(upipe); + upipe_srt_sender_clean_uref_mgr(upipe); + upipe_srt_sender_clean_upump_timer(upipe); + upipe_srt_sender_clean_upump_mgr(upipe); + upipe_srt_sender_clean_uclock(upipe); + + struct uchain *uchain, *uchain_tmp; + ulist_delete_foreach(&upipe_srt_sender->queue, uchain, uchain_tmp) { + struct uref *uref = uref_from_uchain(uchain); + ulist_delete(uchain); + uref_free(uref); + } + + upipe_srt_sender_free_void(upipe); +} + +static struct upipe_mgr upipe_srt_sender_mgr = { + .refcount = NULL, + .signature = UPIPE_SRT_SENDER_SIGNATURE, + + .upipe_alloc = upipe_srt_sender_alloc, + .upipe_input = upipe_srt_sender_input, + .upipe_control = upipe_srt_sender_control, + + .upipe_mgr_control = NULL +}; + +/** @This returns the management structure for srt_sender pipes. + * + * @return pointer to manager + */ +struct upipe_mgr *upipe_srt_sender_mgr_alloc(void) +{ + return &upipe_srt_sender_mgr; +} From 73186aa9c66cbbeb8784c86f086c404c0d99a5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 6 Oct 2023 16:25:40 +0200 Subject: [PATCH 002/231] SRT: update comments --- lib/upipe-srt/upipe_srt_handshake.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 6b32a110e..7d683f5a4 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -774,7 +774,7 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) upipe_err(upipe, "damn"); - // TODO: odd key + // TODO: odd key ? uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); @@ -985,7 +985,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); // XXX: move to bitstream? - // TODO : salt uint8_t kk = 1; out_ext[0] = 0x12; // S V PT out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign @@ -994,7 +993,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin out_ext[10] = 2; // SE out_ext[14] = 4; // slen; - // TODO wrap uint8_t wrap[8+128/8] = {0}; uint8_t klen = 128/8; From 53aef17aa0a4a15fc854ff765b973a2084294679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:24:35 +0200 Subject: [PATCH 003/231] srt_sender: properly handle requests for more than one packet --- lib/upipe-srt/upipe_srt_sender.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index f785bc254..931343ace 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -242,6 +242,9 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 } upipe_srt_sender_output(upipe_super, uref_dup(uref), NULL); + if (--pkts == 0) + return; + seq++; } } From 672269c3359dcee154485e5c3202fb35435abb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:28:09 +0200 Subject: [PATCH 004/231] srth: whitespace --- lib/upipe-srt/upipe_srt_handshake.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 7d683f5a4..3468b4194 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -522,7 +522,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->listener = true; upipe_srt_handshake->last_hs_sent = 0; - + upipe_srt_handshake->expect_conclusion = false; upipe_srt_handshake->control = NULL; @@ -1049,7 +1049,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (!upipe_srt_handshake->expect_conclusion) { if (version != SRT_HANDSHAKE_VERSION_MIN || encryption != SRT_HANDSHAKE_CIPHER_NONE - || extension != SRT_HANDSHAKE_EXT_KMREQ + || extension != SRT_HANDSHAKE_EXT_KMREQ || hs_type != SRT_HANDSHAKE_TYPE_INDUCTION || syn_cookie != 0 || dst_socket_id != 0) { upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", syn_cookie, dst_socket_id); @@ -1112,7 +1112,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSREQ) { - if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) + if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) upipe_srt_handshake_parse_hsreq(upipe, ext); else upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, From 392ebbbb057a21d134d04af4a91c0508abc9831a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:28:26 +0200 Subject: [PATCH 005/231] srth: set latency properly --- lib/upipe-srt/upipe_srt_handshake.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 3468b4194..6aa2a4a7e 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -660,6 +660,12 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio return UBASE_ERR_NONE; } + if (!strcmp(option, "latency")) { + upipe_srt_handshake->receiver_tsbpd_delay = atoi(value); + upipe_srt_handshake->sender_tsbpd_delay = atoi(value); + return UBASE_ERR_NONE; + } + upipe_err_va(upipe, "Unknown option %s", option); return UBASE_ERR_INVALID; } @@ -960,8 +966,9 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint32_t flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; srt_set_handshake_extension_srt_flags(out_ext, flags); - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, 120); // made up delays - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, 120); + + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); size -= ext_size; out_ext += ext_size; From 7aae77aa8e0df35960623f91dbc92a8a1b6ec45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:28:59 +0200 Subject: [PATCH 006/231] srth: debug latency values in all cases --- lib/upipe-srt/upipe_srt_handshake.c | 36 ++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 6aa2a4a7e..4b823e8f9 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -912,9 +912,43 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (!upipe_srt_handshake->listener) { if (upipe_srt_handshake->expect_conclusion) { upipe_srt_handshake_set_upump_timer(upipe, NULL); - // check upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); + /* At least HSREQ is expected */ + printf("size %u\n", size); + size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; + if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { + upipe_err_va(upipe, "Malformed conclusion handshake (size %u)", size); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } + + uint8_t *ext = srt_get_handshake_extension_buf((uint8_t*)cif); + + while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { + uint16_t ext_type = srt_get_handshake_extension_type(ext); + uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); + + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + if (ext_len > size) { + upipe_err_va(upipe, "Malformed extension: %u > %u", ext_len, size); + break; + } + + if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSRSP) { + if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) + upipe_srt_handshake_parse_hsreq(upipe, ext); + else + upipe_err_va(upipe, "Malformed HSRSP: %u < %u\n", ext_len, + SRT_HANDSHAKE_HSREQ_SIZE); + } + + ext += ext_len; + size -= ext_len; + } + upipe_srt_handshake_finalize(upipe); return NULL; } From aa6ba207e208bcf68797cb53a3e295815babe162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:29:13 +0200 Subject: [PATCH 007/231] srth: debug dropreq messages --- lib/upipe-srt/upipe_srt_handshake.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 4b823e8f9..4bc020674 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1282,6 +1282,15 @@ static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const } else if (type == SRT_CONTROL_TYPE_SHUTDOWN) { upipe_err_va(upipe, "shutdown requested"); upipe_throw_source_end(upipe); + } else if (type == SRT_CONTROL_TYPE_DROPREQ) { + const uint8_t *cif = srt_get_control_packet_cif(buf); + if (!srt_check_dropreq(cif, size - SRT_HEADER_SIZE)) { + upipe_err_va(upipe, "dropreq pkt invalid"); + } else { + uint32_t first = srt_get_dropreq_first_seq(cif); + uint32_t last = srt_get_dropreq_last_seq(cif); + upipe_dbg_va(upipe, "sender dropped packets from %u to %u", first, last); + } } else { *handled = false; } From 7cacce9ad4d63396f5fce228d22d288c1912de08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:29:58 +0200 Subject: [PATCH 008/231] rist_rx: set latency --- examples/rist_rx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 296114a1b..4e07d9d65 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -84,6 +84,7 @@ static struct uprobe *logger; static char *dirpath; static char *srcpath; static char *password; +static char *latency; static bool restart; @@ -123,6 +124,9 @@ static int start(void) upipe_srt_handshake_mgr, &uprobe_srt); assert(upipe_srth); upipe_set_option(upipe_srth, "listener", listener ? "1" : "0"); + if (!ubase_check(upipe_set_option(upipe_srth, "latency", latency))) + return EXIT_FAILURE; + upipe_srt_handshake_set_password(upipe_srth, password); upipe_mgr_release(upipe_srt_handshake_mgr); @@ -138,6 +142,9 @@ static int start(void) struct upipe *upipe_srtr = upipe_void_chain_output(upipe_srth, upipe_srt_receiver_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr")); assert(upipe_srtr); + if (!ubase_check(upipe_set_option(upipe_srtr, "latency", latency))) + return EXIT_FAILURE; + upipe_mgr_release(upipe_srt_receiver_mgr); upipe_srtr_sub = upipe_void_alloc_sub(upipe_srtr, @@ -242,7 +249,7 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, } static void usage(const char *argv0) { - fprintf(stdout, "Usage: %s [-d] [-k password] ", argv0); + fprintf(stdout, "Usage: %s [-d] [-k password] ", argv0); fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); fprintf(stdout, " -k encryption password\n"); @@ -269,11 +276,12 @@ int main(int argc, char *argv[]) usage(argv[0]); } } - if (argc - optind < 2) { + if (argc - optind < 3) { usage(argv[0]); } srcpath = argv[optind++]; dirpath = argv[optind++]; + latency = argv[optind++]; #ifdef UPIPE_HAVE_GCRYPT_H gcry_check_version(NULL); From 96b4e61d0821cdf966235f3e92a6816024fd9828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:30:10 +0200 Subject: [PATCH 009/231] rist_rx: log timestamps --- examples/rist_rx.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 4e07d9d65..7ff0da9c7 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -53,6 +53,8 @@ #include "upipe-modules/upipe_udp_sink.h" #include "upipe-srt/upipe_srt_handshake.h" #include "upipe-srt/upipe_srt_receiver.h" +#include "upipe/uprobe_helper_uprobe.h" +#include "upipe/uprobe_helper_alloc.h" #include @@ -67,6 +69,90 @@ #define UPUMP_BLOCKER_POOL 10 #define READ_SIZE 4096 + +/* structure */ +struct uprobe_obe_log { + struct urefcount urefcount; + struct uclock *uclock; + struct uprobe uprobe; + uint64_t start; + uatomic_uint32_t loglevel; +}; + +/* helper */ +UPROBE_HELPER_UPROBE(uprobe_obe_log, uprobe) + +/* alloc */ +struct uprobe *uprobe_obe_log_alloc(struct uprobe *next); + +static int uprobe_obe_log_throw(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + if (event != UPROBE_LOG) + return uprobe_throw_next(uprobe, upipe, event, args); + + va_list args_copy; + va_copy(args_copy, args); + struct ulog *ulog = va_arg(args_copy, struct ulog *); + + uint32_t loglevel = uatomic_load(&probe_obe_log->loglevel); + if (loglevel > ulog->level) + return UBASE_ERR_NONE; + + char time_str[22]; + if (probe_obe_log->uclock) { + uint64_t t = uclock_now(probe_obe_log->uclock) - probe_obe_log->start; + snprintf(time_str, sizeof(time_str), "%.2f", (float)t / 27000.); + } else { + snprintf(time_str, sizeof(time_str), "?"); + } + struct ulog_pfx ulog_pfx = { + .tag = time_str, + }; + ulist_add(&ulog->prefixes, ulog_pfx_to_uchain(&ulog_pfx)); + + return uprobe_throw_next(uprobe, upipe, event, args); +} + +static void uprobe_obe_log_set_loglevel(struct uprobe *uprobe, int loglevel) +{ + struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + uatomic_store(&probe_obe_log->loglevel, loglevel); +} + +static void uprobe_obe_log_set_uclock(struct uprobe *uprobe, struct uclock *uclock) +{ + struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + uclock_release(probe_obe_log->uclock); + probe_obe_log->uclock = uclock_use(uclock); + probe_obe_log->start = uclock_now(uclock); +} + +static struct uprobe *uprobe_obe_log_init(struct uprobe_obe_log *probe_obe_log, + struct uprobe *next) +{ + struct uprobe *probe = uprobe_obe_log_to_uprobe(probe_obe_log); + probe_obe_log->uclock = NULL; + probe_obe_log->start = UINT64_MAX; + uatomic_init(&probe_obe_log->loglevel, UPROBE_LOG_DEBUG); + uprobe_init(probe, uprobe_obe_log_throw, next); + return probe; +} + +static void uprobe_obe_log_clean(struct uprobe_obe_log *probe_obe_log) +{ + uprobe_clean(uprobe_obe_log_to_uprobe(probe_obe_log)); + uclock_release(probe_obe_log->uclock); + uatomic_clean(&probe_obe_log->loglevel); +} + +#define ARGS_DECL struct uprobe *next +#define ARGS next +UPROBE_HELPER_ALLOC(uprobe_obe_log); +#undef ARGS +#undef ARGS_DECL + static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; static struct upipe_mgr *udp_sink_mgr; @@ -316,6 +402,11 @@ int main(int argc, char *argv[]) uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + logger = uprobe_obe_log_alloc(logger); + + uprobe_obe_log_set_loglevel(logger, loglevel); + uprobe_obe_log_set_uclock(logger, uclock); + logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); From faddf7f5cfa11b3258aa8d5ee1f90ca01a287a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 11:30:35 +0200 Subject: [PATCH 010/231] srt_receiver: properly detects RTT --- lib/upipe-srt/upipe_srt_receiver.c | 109 ++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index aa45a070e..d9a58e6d3 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -59,6 +59,11 @@ /** @hidden */ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_format); +struct ack_entry { + uint32_t ack_num; + uint64_t timestamp; +}; + /** @internal @This is the private context of a SRT receiver pipe. */ struct upipe_srt_receiver { /** real refcount management structure */ @@ -109,10 +114,6 @@ struct upipe_srt_receiver { /** last seq output */ uint64_t last_output_seqnum; - uint64_t last_ack; - - uint32_t ack_num; - /* stats */ size_t buffered; size_t nacks; @@ -125,6 +126,13 @@ struct upipe_srt_receiver { /** last time a NACK was sent */ uint64_t last_nack[65536]; + uint32_t ack_num; + uint64_t last_ack; + struct ack_entry *acks; + size_t n_acks; + size_t ack_ridx; + size_t ack_widx; + uint64_t rtt; uint8_t salt[16]; @@ -449,12 +457,13 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); } else { + uint32_t ack_num = upipe_srt_receiver->ack_num++; srt_set_packet_control(out, true); srt_set_packet_timestamp(out, now / 27); srt_set_packet_dst_socket_id(out, upipe_srt_receiver->socket_id); srt_set_control_packet_type(out, SRT_CONTROL_TYPE_ACK); srt_set_control_packet_subtype(out, 0); - srt_set_control_packet_type_specific(out, upipe_srt_receiver->ack_num++); + srt_set_control_packet_type_specific(out, ack_num); uint8_t *out_cif = (uint8_t*)srt_get_control_packet_cif(out); uint64_t last_seq = 0; @@ -473,6 +482,11 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) upipe_srt_receiver->last_ack = now; assert(upipe_srt_receiver->control); upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, NULL); + + upipe_srt_receiver->acks[upipe_srt_receiver->ack_widx].ack_num = ack_num; + upipe_srt_receiver->acks[upipe_srt_receiver->ack_widx].timestamp = now; + upipe_srt_receiver->ack_widx++; + upipe_srt_receiver->ack_widx %= upipe_srt_receiver->n_acks; } } } @@ -688,13 +702,19 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->last_output_seqnum = UINT64_MAX; upipe_srt_receiver->last_ack = UINT64_MAX; upipe_srt_receiver->ack_num = 0; + + upipe_srt_receiver->acks = NULL; + upipe_srt_receiver->n_acks = 0; + upipe_srt_receiver->ack_ridx = 0; + upipe_srt_receiver->ack_widx = 0; + upipe_srt_receiver->buffered = 0; upipe_srt_receiver->nacks = 0; upipe_srt_receiver->repaired = 0; upipe_srt_receiver->loss = 0; upipe_srt_receiver->dups = 0; - upipe_srt_receiver->latency = UCLOCK_FREQ; + upipe_srt_receiver->latency = 0; upipe_srt_receiver->sek_len = 0; @@ -715,6 +735,11 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma upipe_srt_receiver_check_upump_mgr(upipe); + if (upipe_srt_receiver->latency == 0) { + upipe_err(upipe, "Latency unset"); + return UBASE_ERR_UNKNOWN; + } + if (flow_format != NULL) { uint64_t latency; if (!ubase_check(uref_clock_get_latency(flow_format, &latency))) @@ -842,6 +867,7 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, struct uref *flow = va_arg(args, struct uref *); return upipe_srt_receiver_set_flow_def(upipe, flow); } + case UPIPE_SET_OPTION: { const char *k = va_arg(args, const char *); const char *v = va_arg(args, const char *); @@ -849,10 +875,22 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, return UBASE_ERR_INVALID; struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); - upipe_srt_receiver->latency = atoi(v) * UCLOCK_FREQ / 1000; - upipe_dbg_va(upipe, "Set latency to %s msecs", v); + if (upipe_srt_receiver->latency) { + upipe_err(upipe, "Latency already set"); + return UBASE_ERR_UNHANDLED; + } + unsigned latency = atoi(v); + upipe_srt_receiver->latency = latency * UCLOCK_FREQ / 1000; + upipe_dbg_va(upipe, "Set latency to %u msecs", latency); + + upipe_srt_receiver->n_acks = (latency + 9) / 10; + upipe_srt_receiver->acks = malloc(sizeof(*upipe_srt_receiver->acks) * upipe_srt_receiver->n_acks); + if (!upipe_srt_receiver->acks) + return UBASE_ERR_ALLOC; + return UBASE_ERR_NONE; } + default: return UBASE_ERR_UNHANDLED; } @@ -943,6 +981,46 @@ static bool upipe_srt_receiver_insert(struct upipe *upipe, struct uref *uref, co return false; } +static uint64_t upipe_srt_receiver_ackack(struct upipe *upipe, uint32_t ack_num, uint64_t ts) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + const size_t n = upipe_srt_receiver->n_acks; + const size_t ridx = upipe_srt_receiver->ack_ridx;; + + //upipe_verbose_va(upipe,"%s(%u), start at %zu", __func__, ack_num, ridx); + + size_t max = (ridx > 0) ? (ridx - 1) : (n - 1); // end of loop + + for (size_t i = ridx; ; i++) { + uint32_t a = upipe_srt_receiver->acks[i].ack_num; + + if (upipe_srt_receiver->acks[i].timestamp == UINT64_MAX) { // already acked + //upipe_verbose_va(upipe, "break at %zu", i); + break; + } + + if (ack_num < a) { // too late + //upipe_verbose_va(upipe, "break2 at %zu", i); + break; + } else if (ack_num == a) { + uint64_t rtt = ts - upipe_srt_receiver->acks[i].timestamp; + //upipe_verbose_va(upipe, "rtt[%d] %" PRId64, a, rtt); + upipe_srt_receiver->acks[i].timestamp = UINT64_MAX; // do not ack twice + upipe_srt_receiver->ack_ridx = (i+1) % n; // advance + return rtt; + } + + i %= n; + if (i == max) + break; + } + + //upipe_verbose_va(upipe, "%d not found", ack_num); + + return 0; +} + static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { @@ -967,9 +1045,18 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, if (srt_get_packet_control(buf)) { if (srt_get_control_packet_type(buf) == SRT_CONTROL_TYPE_ACKACK) { uint32_t ack_num = srt_get_control_packet_type_specific(buf); - (void)ack_num; // TODO: check ack_num ? keep a rotating list of acks ? uint64_t now = uclock_now(upipe_srt_receiver->uclock); - upipe_srt_receiver->rtt = now - upipe_srt_receiver->last_ack; + uint64_t rtt = upipe_srt_receiver_ackack(upipe, ack_num, now); + upipe_verbose_va(upipe, "RTT %.2f", (float) rtt / 27000.); + if (rtt) { + if (upipe_srt_receiver->rtt) { + upipe_srt_receiver->rtt *= 7; + upipe_srt_receiver->rtt += rtt; + upipe_srt_receiver->rtt /= 8; + } else { + upipe_srt_receiver->rtt = rtt; + } + } } ubase_assert(uref_block_unmap(uref, 0)); @@ -992,7 +1079,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ total_size -= SRT_HEADER_SIZE; -// upipe_dbg_va(upipe, "Data seq %u", seqnum); + upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); (void)order; (void)num; From f69522a5eb41b078e85547256014ba9aaa8b313a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 12:00:18 +0200 Subject: [PATCH 011/231] srth: check hs_type for errors --- lib/upipe-srt/upipe_srt_handshake.c | 44 ++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 4bc020674..108625cfa 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -759,6 +759,37 @@ static const char *get_ctrl_type(uint16_t type) return ctrl_type[type]; } +static const char hs_error[][40] = { + [SRT_HANDSHAKE_TYPE_REJ_UNKNOWN - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Unknown reason", + [SRT_HANDSHAKE_TYPE_REJ_SYSTEM - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "System function error", + [SRT_HANDSHAKE_TYPE_REJ_PEER - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Rejected by peer", + [SRT_HANDSHAKE_TYPE_REJ_RESOURCE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Resource allocation problem", + [SRT_HANDSHAKE_TYPE_REJ_ROGUE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incorrect data in handshake", + [SRT_HANDSHAKE_TYPE_REJ_BACKLOG - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "listener's backlog exceeded", + [SRT_HANDSHAKE_TYPE_REJ_IPE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "internal program error", + [SRT_HANDSHAKE_TYPE_REJ_CLOSE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "socket is closing", + [SRT_HANDSHAKE_TYPE_REJ_VERSION - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "peer is older version than agent's min", + [SRT_HANDSHAKE_TYPE_REJ_RDVCOOKIE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "rendezvous cookie collision", + [SRT_HANDSHAKE_TYPE_REJ_BADSECRET - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "wrong password", + [SRT_HANDSHAKE_TYPE_REJ_UNSECURE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "password required or unexpected", + [SRT_HANDSHAKE_TYPE_REJ_MESSAGEAPI - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Stream flag collision", + [SRT_HANDSHAKE_TYPE_REJ_CONGESTION - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible congestion-controller type", + [SRT_HANDSHAKE_TYPE_REJ_FILTER - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible packet filter", + [SRT_HANDSHAKE_TYPE_REJ_GROUP - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible group", +}; + +static const char *get_hs_error(uint32_t hs_type) +{ + if (hs_type < SRT_HANDSHAKE_TYPE_REJ_UNKNOWN) + hs_type = SRT_HANDSHAKE_TYPE_REJ_UNKNOWN; + + hs_type -= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN; + if (hs_type >= (sizeof(hs_error) / sizeof(*hs_error))) + hs_type = 0; + + return hs_error[hs_type]; +} + static void upipe_srt_handshake_finalize(struct upipe *upipe) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -914,8 +945,13 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_srt_handshake_set_upump_timer(upipe, NULL); upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN) { + upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } + /* At least HSREQ is expected */ - printf("size %u\n", size); size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { upipe_err_va(upipe, "Malformed conclusion handshake (size %u)", size); @@ -954,6 +990,12 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } /* */ + + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN) { + upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + return NULL; + } + if (version != SRT_HANDSHAKE_VERSION || dst_socket_id != upipe_srt_handshake->socket_id || hs_type != SRT_HANDSHAKE_TYPE_INDUCTION ) { From de160417a3546f95dd9367b0fb886e0624f0d9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 14:12:45 +0200 Subject: [PATCH 012/231] srth: check hs_type properly --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 108625cfa..55c3ffeb5 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -945,7 +945,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_srt_handshake_set_upump_timer(upipe, NULL); upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); - if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN) { + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); upipe_srt_handshake->expect_conclusion = false; return NULL; @@ -991,7 +991,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin /* */ - if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN) { + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); return NULL; } From a1038ca5d7b102acd85aa8b661fb728eb5bb959f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 14:50:47 +0200 Subject: [PATCH 013/231] srts: remove unused code --- lib/upipe-srt/upipe_srt_sender.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 931343ace..974c8fc63 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -137,27 +137,6 @@ struct upipe_srt_sender_input { struct upipe upipe; }; -static const char ctrl_type[][10] = -{ - [SRT_CONTROL_TYPE_HANDSHAKE] = "handshake", - [SRT_CONTROL_TYPE_KEEPALIVE] = "keepalive", - [SRT_CONTROL_TYPE_ACK] = "ack", - [SRT_CONTROL_TYPE_NAK] = "nak", - [SRT_CONTROL_TYPE_SHUTDOWN] = "shutdown", - [SRT_CONTROL_TYPE_ACKACK] = "ackack", - [SRT_CONTROL_TYPE_DROPREQ] = "dropreq", - [SRT_CONTROL_TYPE_PEERERROR] = "peererror", -}; - -static const char *get_ctrl_type(uint16_t type) -{ - if (type == SRT_CONTROL_TYPE_USER) - return "user"; - if (type >= (sizeof(ctrl_type) / sizeof(*ctrl_type))) - return "?"; - return ctrl_type[type]; -} - static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts); /** @internal @This handles SRT messages. @@ -186,7 +165,6 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, } uint16_t type = srt_get_control_packet_type(buf); - //upipe_dbg_va(upipe, "control pkt %s", get_ctrl_type(type)); if (type == SRT_CONTROL_TYPE_NAK) { buf += SRT_HEADER_SIZE; From 969ec20ae2de33b3accfd98f503f54b7501101c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 14:51:25 +0200 Subject: [PATCH 014/231] ws --- lib/upipe-srt/upipe_srt_sender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 974c8fc63..501b68719 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -453,7 +453,7 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender_free_void(upipe); return NULL; } -#endif +#endif struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe); upipe_srt_sender_init_urefcount(upipe); From 82e29c2363ceb904007059b0f7e72e4c9b05efe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 13 Oct 2023 15:17:29 +0200 Subject: [PATCH 015/231] srts: send dropreq packet --- lib/upipe-srt/upipe_srt_sender.c | 43 +++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 501b68719..35e71082d 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -137,7 +137,7 @@ struct upipe_srt_sender_input { struct upipe upipe; }; -static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts); +static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts, struct upump **upump_p); /** @internal @This handles SRT messages. * @@ -173,7 +173,7 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, uint32_t seq; uint32_t packets; while (srt_get_nak_range(&buf, &s, &seq, &packets)) { - upipe_srt_sender_lost_sub_n(upipe, seq, packets); + upipe_srt_sender_lost_sub_n(upipe, seq, packets, upump_p); } } @@ -188,7 +188,7 @@ UPIPE_HELPER_SUBPIPE(upipe_srt_sender, upipe_srt_sender_input, output, sub_mgr, uchain) /** @internal @This retransmits a number of packets */ -static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts) +static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts, struct upump **upump_p) { struct upipe *upipe_super = NULL; upipe_srt_sender_input_get_super(upipe, &upipe_super); @@ -205,7 +205,7 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 /* packet not in range */ if (diff < 0x80000000) { /* packet after range */ - return; + break; } continue; } @@ -224,6 +224,41 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 return; seq++; } + + /* XXX: Is it needed? */ + + int s = SRT_HEADER_SIZE + SRT_DROPREQ_CIF_SIZE; + struct uref *uref = uref_block_alloc(upipe_srt_sender->uref_mgr, + upipe_srt_sender->ubuf_mgr, s); + if (!uref) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + return; + } + + uint8_t *buf; + s = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &s, &buf)))) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + uref_free(uref); + return; + } + + uint64_t now = uclock_now(upipe_srt_sender->uclock); + + memset(buf, 0, s); + srt_set_packet_control(buf, true); + srt_set_control_packet_type(buf, SRT_CONTROL_TYPE_DROPREQ); + srt_set_control_packet_subtype(buf, 0); // message number + + srt_set_packet_timestamp(buf, (now - upipe_srt_sender->establish_time) / 27); + srt_set_packet_dst_socket_id(buf, upipe_srt_sender->socket_id); + + uint8_t *cif = (uint8_t*)srt_get_control_packet_cif(buf); + srt_set_dropreq_first_seq(cif, seq); + srt_set_dropreq_last_seq(cif, seq + pkts - 1); + + uref_block_unmap(uref, 0); + upipe_srt_sender_output(&upipe_srt_sender->upipe, uref, upump_p); } /** @This is called when there is no external reference to the pipe anymore. From d43584473e98025b1f385f45ed9a839cecdd8cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 26 Oct 2023 15:35:04 +0200 Subject: [PATCH 016/231] srts: use UCLOCK_FREQ for latency --- lib/upipe-srt/upipe_srt_sender.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 35e71082d..8f8412b0c 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -329,7 +329,7 @@ static void upipe_srt_sender_timer(struct upump *upump) if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) upipe_warn(upipe, "Couldn't read cr_sys"); - if (now - cr_sys < upipe_srt_sender->latency * UCLOCK_FREQ / 1000) + if (now - cr_sys < upipe_srt_sender->latency) return; upipe_verbose_va(upipe, "Delete seq %" PRIu64 " after %"PRIu64" clocks", @@ -502,7 +502,7 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender_init_ubuf_mgr(upipe); upipe_srt_sender_init_uref_mgr(upipe); ulist_init(&upipe_srt_sender->queue); - upipe_srt_sender->latency = 1000; /* 1 sec */ + upipe_srt_sender->latency = UCLOCK_FREQ; /* 1 sec */ upipe_srt_sender->socket_id = 0; upipe_srt_sender->seqnum = 0; upipe_srt_sender->syn_cookie = 1; From e67c6bd17c832929f447daead1b04a1c01eebc4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 26 Oct 2023 15:36:24 +0200 Subject: [PATCH 017/231] srtr: clarify variable --- lib/upipe-srt/upipe_srt_receiver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index d9a58e6d3..5ed811928 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -879,11 +879,11 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, upipe_err(upipe, "Latency already set"); return UBASE_ERR_UNHANDLED; } - unsigned latency = atoi(v); - upipe_srt_receiver->latency = latency * UCLOCK_FREQ / 1000; - upipe_dbg_va(upipe, "Set latency to %u msecs", latency); + unsigned latency_ms = atoi(v); + upipe_srt_receiver->latency = latency_ms * UCLOCK_FREQ / 1000; + upipe_dbg_va(upipe, "Set latency to %u msecs", latency_ms); - upipe_srt_receiver->n_acks = (latency + 9) / 10; + upipe_srt_receiver->n_acks = (latency_ms + 9) / 10; upipe_srt_receiver->acks = malloc(sizeof(*upipe_srt_receiver->acks) * upipe_srt_receiver->n_acks); if (!upipe_srt_receiver->acks) return UBASE_ERR_ALLOC; From c579f8612494adbd6b15886bd9e8a11687563f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 26 Oct 2023 15:36:34 +0200 Subject: [PATCH 018/231] srts: sets upump before starting --- lib/upipe-srt/upipe_srt_sender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 8f8412b0c..57062861a 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -381,9 +381,9 @@ static int upipe_srt_sender_check(struct upipe *upipe, struct uref *flow_format) upump_alloc_timer(upipe_srt_sender->upump_mgr, upipe_srt_sender_timer, upipe, upipe->refcount, UCLOCK_FREQ, UCLOCK_FREQ); + upipe_srt_sender_set_upump_timer(upipe, upump); upump_start(upump); - upipe_srt_sender_set_upump_timer(upipe, upump); } return UBASE_ERR_NONE; From 23a1de27bc1c59bd9e1d8d25b9263c8f25f93ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 26 Oct 2023 15:44:34 +0200 Subject: [PATCH 019/231] srth: whitespace --- lib/upipe-srt/upipe_srt_handshake.c | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 55c3ffeb5..501a87097 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -760,22 +760,22 @@ static const char *get_ctrl_type(uint16_t type) } static const char hs_error[][40] = { - [SRT_HANDSHAKE_TYPE_REJ_UNKNOWN - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Unknown reason", - [SRT_HANDSHAKE_TYPE_REJ_SYSTEM - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "System function error", - [SRT_HANDSHAKE_TYPE_REJ_PEER - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Rejected by peer", - [SRT_HANDSHAKE_TYPE_REJ_RESOURCE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Resource allocation problem", - [SRT_HANDSHAKE_TYPE_REJ_ROGUE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incorrect data in handshake", - [SRT_HANDSHAKE_TYPE_REJ_BACKLOG - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "listener's backlog exceeded", - [SRT_HANDSHAKE_TYPE_REJ_IPE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "internal program error", - [SRT_HANDSHAKE_TYPE_REJ_CLOSE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "socket is closing", - [SRT_HANDSHAKE_TYPE_REJ_VERSION - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "peer is older version than agent's min", - [SRT_HANDSHAKE_TYPE_REJ_RDVCOOKIE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "rendezvous cookie collision", - [SRT_HANDSHAKE_TYPE_REJ_BADSECRET - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "wrong password", - [SRT_HANDSHAKE_TYPE_REJ_UNSECURE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "password required or unexpected", - [SRT_HANDSHAKE_TYPE_REJ_MESSAGEAPI - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Stream flag collision", - [SRT_HANDSHAKE_TYPE_REJ_CONGESTION - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible congestion-controller type", - [SRT_HANDSHAKE_TYPE_REJ_FILTER - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible packet filter", - [SRT_HANDSHAKE_TYPE_REJ_GROUP - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible group", + [SRT_HANDSHAKE_TYPE_REJ_UNKNOWN - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Unknown reason", + [SRT_HANDSHAKE_TYPE_REJ_SYSTEM - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "System function error", + [SRT_HANDSHAKE_TYPE_REJ_PEER - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Rejected by peer", + [SRT_HANDSHAKE_TYPE_REJ_RESOURCE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Resource allocation problem", + [SRT_HANDSHAKE_TYPE_REJ_ROGUE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incorrect data in handshake", + [SRT_HANDSHAKE_TYPE_REJ_BACKLOG - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "listener's backlog exceeded", + [SRT_HANDSHAKE_TYPE_REJ_IPE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "internal program error", + [SRT_HANDSHAKE_TYPE_REJ_CLOSE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "socket is closing", + [SRT_HANDSHAKE_TYPE_REJ_VERSION - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "peer is older version than agent's min", + [SRT_HANDSHAKE_TYPE_REJ_RDVCOOKIE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "rendezvous cookie collision", + [SRT_HANDSHAKE_TYPE_REJ_BADSECRET - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "wrong password", + [SRT_HANDSHAKE_TYPE_REJ_UNSECURE - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "password required or unexpected", + [SRT_HANDSHAKE_TYPE_REJ_MESSAGEAPI - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "Stream flag collision", + [SRT_HANDSHAKE_TYPE_REJ_CONGESTION - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible congestion-controller type", + [SRT_HANDSHAKE_TYPE_REJ_FILTER - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible packet filter", + [SRT_HANDSHAKE_TYPE_REJ_GROUP - SRT_HANDSHAKE_TYPE_REJ_UNKNOWN] = "incompatible group", }; static const char *get_hs_error(uint32_t hs_type) From cd43b5a65bbd20946a4bdf4577ce5e740ba382bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 9 Nov 2023 17:02:56 +0100 Subject: [PATCH 020/231] srtr: fix ack fields (rtt, rtt variance, bitrate, packetrate) Use default values from the SRT draft --- lib/upipe-srt/upipe_srt_receiver.c | 56 +++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 5ed811928..031965522 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -126,6 +126,12 @@ struct upipe_srt_receiver { /** last time a NACK was sent */ uint64_t last_nack[65536]; + /** number of packets in the buffer */ + uint64_t packets; + + /** number of bytes in the buffer*/ + uint64_t bytes; + uint32_t ack_num; uint64_t last_ack; struct ack_entry *acks; @@ -134,6 +140,7 @@ struct upipe_srt_receiver { size_t ack_widx; uint64_t rtt; + uint64_t rtt_variance; uint8_t salt[16]; uint8_t sek[2][32]; @@ -471,12 +478,15 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) if (last_received != UINT64_MAX) last_seq = last_received; srt_set_ack_last_ack_seq(out_cif, last_seq); - srt_set_ack_rtt(out_cif, 1000); - srt_set_ack_rtt_variance(out_cif, 100); - srt_set_ack_avail_bufsize(out_cif, 100); - srt_set_ack_packets_receiving_rate(out_cif, 100); - srt_set_ack_estimated_link_capacity(out_cif, 1000); - srt_set_ack_receiving_rate(out_cif, 100000); + srt_set_ack_rtt(out_cif, upipe_srt_receiver->rtt * 1000000 / UCLOCK_FREQ); + srt_set_ack_rtt_variance(out_cif, upipe_srt_receiver->rtt_variance * 1000000 / UCLOCK_FREQ); + uint64_t t = upipe_srt_receiver->latency; + + uint64_t packets_per_sec = upipe_srt_receiver->packets * UCLOCK_FREQ / t; + srt_set_ack_packets_receiving_rate(out_cif, packets_per_sec); + srt_set_ack_avail_bufsize(out_cif, packets_per_sec * upipe_srt_receiver->latency / UCLOCK_FREQ); + srt_set_ack_estimated_link_capacity(out_cif, 10 * packets_per_sec); /* ? */ + srt_set_ack_receiving_rate(out_cif, upipe_srt_receiver->bytes * UCLOCK_FREQ / t); uref_block_unmap(uref, 0); upipe_srt_receiver->last_ack = now; @@ -548,6 +558,11 @@ static void upipe_srt_receiver_timer(struct upump *upump) upipe_srt_receiver->last_output_seqnum = seqnum; ulist_delete(uchain); + upipe_srt_receiver->packets--; + size_t size; + if (unlikely(!ubase_check(uref_block_size(uref, &size)))) + size = 0; + upipe_srt_receiver->bytes -= size; upipe_srt_receiver_output(upipe, uref, NULL); // XXX: use timer upump ? static uint64_t old; @@ -696,7 +711,8 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, ulist_init(&upipe_srt_receiver->queue); memset(upipe_srt_receiver->last_nack, 0, sizeof(upipe_srt_receiver->last_nack)); - upipe_srt_receiver->rtt = 0; + upipe_srt_receiver->rtt = 100 * UCLOCK_FREQ / 1000; + upipe_srt_receiver->rtt_variance = 50 * UCLOCK_FREQ / 1000; upipe_srt_receiver->expected_seqnum = UINT64_MAX; upipe_srt_receiver->last_output_seqnum = UINT64_MAX; @@ -716,6 +732,9 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->latency = 0; + upipe_srt_receiver->packets = 0; + upipe_srt_receiver->bytes = 0; + upipe_srt_receiver->sek_len = 0; upipe_throw_ready(upipe); @@ -1042,20 +1061,28 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, return; } + + uint64_t now = uclock_now(upipe_srt_receiver->uclock); + if (srt_get_packet_control(buf)) { if (srt_get_control_packet_type(buf) == SRT_CONTROL_TYPE_ACKACK) { uint32_t ack_num = srt_get_control_packet_type_specific(buf); - uint64_t now = uclock_now(upipe_srt_receiver->uclock); uint64_t rtt = upipe_srt_receiver_ackack(upipe, ack_num, now); upipe_verbose_va(upipe, "RTT %.2f", (float) rtt / 27000.); if (rtt) { - if (upipe_srt_receiver->rtt) { - upipe_srt_receiver->rtt *= 7; - upipe_srt_receiver->rtt += rtt; - upipe_srt_receiver->rtt /= 8; + uint64_t var = 0; + if (rtt > upipe_srt_receiver->rtt) { + var = rtt - upipe_srt_receiver->rtt; } else { - upipe_srt_receiver->rtt = rtt; + var = upipe_srt_receiver->rtt - rtt; } + upipe_srt_receiver->rtt *= 7; + upipe_srt_receiver->rtt += rtt; + upipe_srt_receiver->rtt /= 8; + + upipe_srt_receiver->rtt_variance *= 3; + upipe_srt_receiver->rtt_variance += var; + upipe_srt_receiver->rtt_variance /= 4; } } @@ -1163,6 +1190,9 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, if (diff < 0x80000000U) { // seqnum > last seq, insert at the end /* packet is from the future */ upipe_srt_receiver->buffered++; + + upipe_srt_receiver->packets++; + upipe_srt_receiver->bytes += total_size + SRT_HEADER_SIZE; ulist_add(&upipe_srt_receiver->queue, uref_to_uchain(uref)); upipe_srt_receiver->last_nack[seqnum & 0xffff] = 0; From 3b2eca6de3b7c1033d74a2e7cdb2b6697399c7f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 10 Nov 2023 13:11:52 +0100 Subject: [PATCH 021/231] srth: longer delay --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 501a87097..f1c5b6ed6 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -384,9 +384,9 @@ static void upipe_srt_handshake_timer(struct upump *upump) uint64_t now = uclock_now(upipe_srt_handshake->uclock); - if (now - upipe_srt_handshake->last_hs_sent < UCLOCK_FREQ / 10) { + /* 250 ms between handshakes, just like libsrt */ + if (now - upipe_srt_handshake->last_hs_sent < UCLOCK_FREQ / 4) return; - } //send HS uint8_t *out_cif; From 3e3e2c5eb05b191ae0b9134975e849a40bec7a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 10 Nov 2023 13:43:25 +0100 Subject: [PATCH 022/231] Fix malformed shutdown packet Here's what libsrt source has to say: // control info field should be none // but "writev" does not allow this m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4); --- lib/upipe-srt/upipe_srt_handshake.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f1c5b6ed6..0627e4491 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -287,7 +287,7 @@ static void upipe_srt_handshake_output_shutdown(struct upipe *upipe) uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE); + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* wtf */); if (!uref) return; uint8_t *out; @@ -302,6 +302,8 @@ static void upipe_srt_handshake_output_shutdown(struct upipe *upipe) srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); srt_set_control_packet_type(out, SRT_CONTROL_TYPE_SHUTDOWN); srt_set_control_packet_subtype(out, 0); + uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); + memset(extra, 0, 4); uref_block_unmap(uref, 0); upipe_srt_handshake_output_output(upipe, uref, From fa6cf28ba671663ccea7de42ee3b9bd49f66398e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 10 Nov 2023 14:37:39 +0100 Subject: [PATCH 023/231] srth: check handshake type in remote reply Ignore reply if type is unexpected (e.g. reply to an earlier message) Reinitialize if not connected after 3s --- lib/upipe-srt/upipe_srt_handshake.c | 74 +++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 0627e4491..f58e725d0 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -74,6 +74,7 @@ struct upipe_srt_handshake { struct upump_mgr *upump_mgr; struct upump *upump_timer; + struct upump *upump_timeout; struct uclock *uclock; struct urequest uclock_request; @@ -146,6 +147,7 @@ UPIPE_HELPER_VOID(upipe_srt_handshake) UPIPE_HELPER_OUTPUT(upipe_srt_handshake, output, flow_def, output_state, request_list) UPIPE_HELPER_UPUMP_MGR(upipe_srt_handshake, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timer, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timeout, upump_mgr) UPIPE_HELPER_UCLOCK(upipe_srt_handshake, uclock, uclock_request, NULL, upipe_throw_provide_request, NULL) UPIPE_HELPER_UREF_MGR(upipe_srt_handshake, uref_mgr, uref_mgr_request, @@ -379,6 +381,16 @@ static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_si return uref; } +static void upipe_srt_handshake_timeout(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + upipe_err(upipe, "Connection timed out"); + + upipe_srt_handshake->expect_conclusion = false; +} + static void upipe_srt_handshake_timer(struct upump *upump) { struct upipe *upipe = upump_get_opaque(upump, struct upipe *); @@ -512,6 +524,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_init_upump_mgr(upipe); upipe_srt_handshake_init_upump_timer(upipe); + upipe_srt_handshake_init_upump_timeout(upipe); upipe_srt_handshake_init_uclock(upipe); upipe_srt_handshake_require_uclock(upipe); @@ -689,6 +702,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, switch (command) { case UPIPE_ATTACH_UPUMP_MGR: upipe_srt_handshake_set_upump_timer(upipe, NULL); + upipe_srt_handshake_set_upump_timeout(upipe, NULL); return upipe_srt_handshake_attach_upump_mgr(upipe); case UPIPE_SET_FLOW_DEF: { @@ -796,6 +810,7 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake_set_upump_timeout(upipe, NULL); struct uref *flow_def; if (ubase_check(upipe_srt_handshake_get_flow_def(upipe, &flow_def))) { @@ -942,17 +957,33 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint32_t syn_cookie = srt_get_handshake_syn_cookie(cif); uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); + if (!upipe_srt_handshake->upump_timeout) { + /* connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_timeout(upipe, upump); + } + if (!upipe_srt_handshake->listener) { - if (upipe_srt_handshake->expect_conclusion) { - upipe_srt_handshake_set_upump_timer(upipe, NULL); - upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { + upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } - if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { - upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); - upipe_srt_handshake->expect_conclusion = false; + if (upipe_srt_handshake->expect_conclusion) { + if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { + upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); return NULL; } + upipe_srt_handshake_set_upump_timer(upipe, NULL); + upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); + /* At least HSREQ is expected */ size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { @@ -993,14 +1024,12 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin /* */ - if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { - upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { + upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); return NULL; } - if (version != SRT_HANDSHAKE_VERSION || dst_socket_id != upipe_srt_handshake->socket_id - || hs_type != SRT_HANDSHAKE_TYPE_INDUCTION - ) { + if (version != SRT_HANDSHAKE_VERSION || dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", dst_socket_id, upipe_srt_handshake->socket_id); return NULL; @@ -1133,9 +1162,13 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } if (!upipe_srt_handshake->expect_conclusion) { - if (version != SRT_HANDSHAKE_VERSION_MIN || encryption != SRT_HANDSHAKE_CIPHER_NONE - || extension != SRT_HANDSHAKE_EXT_KMREQ - || hs_type != SRT_HANDSHAKE_TYPE_INDUCTION || + if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { + upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); + return NULL; + } + + if (version != SRT_HANDSHAKE_VERSION_MIN || encryption != SRT_HANDSHAKE_CIPHER_NONE || + extension != SRT_HANDSHAKE_EXT_KMREQ || syn_cookie != 0 || dst_socket_id != 0) { upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", syn_cookie, dst_socket_id); return NULL; @@ -1159,8 +1192,18 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uref_block_unmap(uref, 0); return uref; } else { + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { + upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } + + if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { + upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); + return NULL; + } + if (version != SRT_HANDSHAKE_VERSION - || hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION || syn_cookie != upipe_srt_handshake->syn_cookie || dst_socket_id != 0) { upipe_err(upipe, "Malformed conclusion handshake"); @@ -1405,6 +1448,7 @@ static void upipe_srt_handshake_free(struct upipe *upipe) upipe_srt_handshake_clean_output(upipe); upipe_srt_handshake_clean_upump_timer(upipe); + upipe_srt_handshake_clean_upump_timeout(upipe); upipe_srt_handshake_clean_upump_mgr(upipe); upipe_srt_handshake_clean_uclock(upipe); upipe_srt_handshake_clean_ubuf_mgr(upipe); From 5147deff4636ded6fdb7b4da3305612927f6489f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 10 Nov 2023 15:02:44 +0100 Subject: [PATCH 024/231] rist_tx: stop on shutdown --- examples/rist_tx.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 2d01b6dd1..488f9b4a3 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -96,6 +96,7 @@ static char *password; static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; static struct uprobe uprobe_udp_srt; +static struct uprobe uprobe_hs; static struct uprobe *logger; static bool restart; @@ -126,6 +127,22 @@ static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) static void stop(struct upump *upump); +/** definition of our uprobe */ +static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + case UPROBE_SOURCE_END: + upipe_warn(upipe, "Remote shutdown"); + restart = true; + struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, + NULL, UCLOCK_FREQ, 0); + upump_start(u); + return uprobe_throw_next(uprobe, upipe, event, args); + } + return uprobe_throw_next(uprobe, upipe, event, args); +} + /** definition of our uprobe */ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) @@ -186,13 +203,14 @@ static int start(void) return EXIT_FAILURE; uprobe_init(&uprobe_udp_srt, catch_udp, uprobe_use(logger)); + uprobe_init(&uprobe_hs, catch_hs, uprobe_use(logger)); upipe_udpsrc_srt = upipe_void_alloc(upipe_udpsrc_mgr, uprobe_pfx_alloc(&uprobe_udp_srt, loglevel, "udp source srt")); upipe_attach_uclock(upipe_udpsrc_srt); struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt handshake")); + uprobe_pfx_alloc(uprobe_use(&uprobe_hs), loglevel, "srt handshake")); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); upipe_srt_handshake_set_password(upipe_srt_handshake, password); @@ -366,6 +384,7 @@ int main(int argc, char *argv[]) * release everything */ uprobe_release(logger); uprobe_clean(&uprobe_udp_srt); + uprobe_clean(&uprobe_hs); upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); From 0c746a00de610ace5f4e544ec6659c8622cde55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 17 Nov 2023 10:04:57 +0100 Subject: [PATCH 025/231] Fix aes-192 and aes-256 --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f58e725d0..b4b404985 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -913,7 +913,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * goto key_error; } - err = gcry_cipher_decrypt(aes, osek, 16, *wrap, *wrap_len); + err = gcry_cipher_decrypt(aes, osek, klen, *wrap, *wrap_len); if (err) { upipe_err_va(upipe, "Couldn't decrypt session key (0x%x)", err); goto key_error; From 44f059f0ec2986157e7b813d21761499b8bfd1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 17 Nov 2023 10:31:13 +0100 Subject: [PATCH 026/231] srth: prepare for different key lengths --- lib/upipe-srt/upipe_srt_handshake.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index b4b404985..48a39e7ce 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -881,6 +881,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * } uint8_t klen = 4 * srt_km_get_klen(ext); + // FIXME: check key length memcpy(upipe_srt_handshake->salt, srt_km_get_salt(ext), 16); @@ -1047,8 +1048,9 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin size_t size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; + uint8_t klen = 128/8; // FIXME: 192 and 256 if (upipe_srt_handshake->password) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + (8+128/8); + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + (8+klen); extension |= SRT_HANDSHAKE_EXT_KMREQ; } if (upipe_srt_handshake->stream_id) { @@ -1107,8 +1109,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin out_ext[10] = 2; // SE out_ext[14] = 4; // slen; - uint8_t wrap[8+128/8] = {0}; - uint8_t klen = 128/8; + uint8_t wrap[8+256/8] = {0}; size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; From 151693f3414d05d27a5a84ccb3c79a3a47b8a94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 24 Nov 2023 09:20:14 +0100 Subject: [PATCH 027/231] rist_tx: debug end of program --- examples/rist_tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 488f9b4a3..323cf14c8 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -380,8 +380,6 @@ int main(int argc, char *argv[]) upump_free(sigint_pump); - /* should never be here for the moment. todo: sighandler. - * release everything */ uprobe_release(logger); uprobe_clean(&uprobe_udp_srt); uprobe_clean(&uprobe_hs); @@ -392,5 +390,7 @@ int main(int argc, char *argv[]) umem_mgr_release(umem_mgr); uclock_release(uclock); + printf("done\n"); + return 0; } From 95f056e3169a06bf5324730929df9c93a4f418de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 24 Nov 2023 10:21:51 +0100 Subject: [PATCH 028/231] rist_tx: debug pipeline number, to differentiate restarts --- examples/rist_tx.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 323cf14c8..e48c797f8 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -181,12 +181,15 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, static int start(void) { + static unsigned z = 0; + z++; + bool listener = dirpath && *dirpath == '@'; /* rtp source */ struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source data")); + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp source data %u", z)); if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { return EXIT_FAILURE; @@ -196,7 +199,7 @@ static int start(void) /* send through srt sender */ struct upipe_mgr *upipe_srt_sender_mgr = upipe_srt_sender_mgr_alloc(); upipe_srt_sender = upipe_void_alloc_output(upipe_udpsrc, upipe_srt_sender_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt sender")); + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender %u", z)); upipe_mgr_release(upipe_srt_sender_mgr); if (!ubase_check(upipe_set_option(upipe_srt_sender, "latency", latency))) @@ -205,12 +208,12 @@ static int start(void) uprobe_init(&uprobe_udp_srt, catch_udp, uprobe_use(logger)); uprobe_init(&uprobe_hs, catch_hs, uprobe_use(logger)); upipe_udpsrc_srt = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc(&uprobe_udp_srt, loglevel, "udp source srt")); + uprobe_pfx_alloc_va(&uprobe_udp_srt, loglevel, "udp source srt %u", z)); upipe_attach_uclock(upipe_udpsrc_srt); struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, - uprobe_pfx_alloc(uprobe_use(&uprobe_hs), loglevel, "srt handshake")); + uprobe_pfx_alloc_va(uprobe_use(&uprobe_hs), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); upipe_srt_handshake_set_password(upipe_srt_handshake, password); @@ -219,19 +222,19 @@ static int start(void) upipe_mgr_release(upipe_udpsrc_mgr); upipe_srt_handshake_sub = upipe_void_alloc_sub(upipe_srt_handshake, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt handshake sub")); + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt handshake sub %u", z)); assert(upipe_srt_handshake_sub); upipe_srt_sender_sub = upipe_void_chain_output_sub(upipe_srt_handshake, upipe_srt_sender, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srt sender sub")); + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender sub %u", z)); assert(upipe_srt_sender_sub); upipe_release(upipe_srt_sender_sub); /* send to udp */ struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); upipe_udpsink = upipe_void_chain_output(upipe_srt_sender, upipe_udpsink_mgr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp sink")); + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp sink %u", z)); upipe_release(upipe_udpsink); upipe_set_output(upipe_srt_handshake_sub, upipe_udpsink); @@ -262,7 +265,7 @@ static int start(void) if (!getsockname(udp_fd, peer, &peer_len)) { char uri[INET6_ADDRSTRLEN+6]; addr_to_str(peer, uri); - upipe_warn_va(upipe_srt_handshake, "Local %s", uri); // XXX: INADDR_ANY when listening + upipe_warn_va(upipe_srt_handshake, "Local %s (%u)", uri, z); // XXX: INADDR_ANY when listening upipe_srt_handshake_set_peer(upipe_srt_handshake, peer, peer_len); } From 5d3c6a7f5ee692f0c1c8b3401a1a0c0b09866a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 24 Nov 2023 11:07:12 +0100 Subject: [PATCH 029/231] rist_tx: reverse restart logic if 2 events are queued immediately, restart won't be reset to true before stop() runs --- examples/rist_tx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index e48c797f8..4b778e47b 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -99,7 +99,7 @@ static struct uprobe uprobe_udp_srt; static struct uprobe uprobe_hs; static struct uprobe *logger; -static bool restart; +static bool restart = true; static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) { @@ -134,7 +134,6 @@ static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, switch (event) { case UPROBE_SOURCE_END: upipe_warn(upipe, "Remote shutdown"); - restart = true; struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, NULL, UCLOCK_FREQ, 0); upump_start(u); @@ -150,7 +149,6 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, switch (event) { case UPROBE_SOURCE_END: upipe_warn(upipe, "Remote end not listening, can't receive SRT"); - restart = true; struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, NULL, UCLOCK_FREQ, 0); upump_start(u); @@ -283,10 +281,8 @@ static void stop(struct upump *upump) upipe_release(upipe_udpsrc); upipe_release(upipe_srt_handshake_sub); - if (restart) { - restart = false; + if (restart) start(); - } } static void sig_cb(struct upump *upump) @@ -297,6 +293,7 @@ static void sig_cb(struct upump *upump) abort(); done = true; + restart = false; stop(NULL); } From 9794a6b387088a2c422fa3239e8b855de7f5999f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 24 Nov 2023 14:33:22 +0100 Subject: [PATCH 030/231] srth: 192/256 bits AES --- examples/rist_rx.c | 11 ++++++++--- examples/rist_tx.c | 9 +++++++-- include/upipe-srt/upipe_srt_handshake.h | 10 +++++----- lib/upipe-srt/upipe_srt_handshake.c | 18 +++++++++++++++--- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 7ff0da9c7..396f22ad5 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -170,6 +170,7 @@ static struct uprobe *logger; static char *dirpath; static char *srcpath; static char *password; +static int key_length = 128; static char *latency; static bool restart; @@ -213,7 +214,7 @@ static int start(void) if (!ubase_check(upipe_set_option(upipe_srth, "latency", latency))) return EXIT_FAILURE; - upipe_srt_handshake_set_password(upipe_srth, password); + upipe_srt_handshake_set_password(upipe_srth, password, key_length / 8); upipe_mgr_release(upipe_srt_handshake_mgr); upipe_srth_sub = upipe_void_alloc_sub(upipe_srth, @@ -335,10 +336,11 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, } static void usage(const char *argv0) { - fprintf(stdout, "Usage: %s [-d] [-k password] ", argv0); + fprintf(stdout, "Usage: %s [-d] [-k password] [-l 128] ", argv0); fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); fprintf(stdout, " -k encryption password\n"); + fprintf(stdout, " -l key length in bits\n"); exit(EXIT_FAILURE); } @@ -347,7 +349,7 @@ int main(int argc, char *argv[]) int opt; /* parse options */ - while ((opt = getopt(argc, argv, "qdk:")) != -1) { + while ((opt = getopt(argc, argv, "qdk:l:")) != -1) { switch (opt) { case 'd': loglevel--; @@ -358,6 +360,9 @@ int main(int argc, char *argv[]) case 'k': password = optarg; break; + case 'l': + key_length = atoi(optarg); + break; default: usage(argv[0]); } diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 4b778e47b..1957a8d4e 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -75,6 +75,7 @@ static void usage(const char *argv0) { fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); fprintf(stdout, " -k encryption password\n"); + fprintf(stdout, " -l key length in bits\n"); exit(EXIT_FAILURE); } @@ -92,6 +93,7 @@ static char *srcpath; static char *dirpath; static char *latency; static char *password; +static int key_length = 128; static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; @@ -213,7 +215,7 @@ static int start(void) struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_hs), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); - upipe_srt_handshake_set_password(upipe_srt_handshake, password); + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); upipe_mgr_release(upipe_srt_handshake_mgr); @@ -303,7 +305,7 @@ int main(int argc, char *argv[]) int opt; /* parse options */ - while ((opt = getopt(argc, argv, "qdk:")) != -1) { + while ((opt = getopt(argc, argv, "qdk:l:")) != -1) { switch (opt) { case 'q': loglevel++; @@ -315,6 +317,9 @@ int main(int argc, char *argv[]) case 'k': password = optarg; break; + case 'l': + key_length = atoi(optarg); + break; default: usage(argv[0]); } diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h index 876d75a15..aea1b1a8e 100644 --- a/include/upipe-srt/upipe_srt_handshake.h +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -48,7 +48,7 @@ enum upipe_srt_handshake_command { /** set our peer address (const struct sockaddr *, socklen_t) **/ UPIPE_SRT_HANDSHAKE_SET_PEER, - /** set the encryption password (const char *) */ + /** set the encryption password (const char *, int) */ UPIPE_SRT_HANDSHAKE_SET_PASSWORD, }; @@ -69,15 +69,15 @@ static inline int upipe_srt_handshake_set_peer(struct upipe *upipe, /** @This sets the encryption key * * @param upipe description structure of the pipe - * @param even key - * @param odd key + * @param password passphrase + * @param key_len key length in bytes * @return false in case of error */ static inline int upipe_srt_handshake_set_password(struct upipe *upipe, - const char *password) + const char *password, int key_len) { return upipe_control(upipe, UPIPE_SRT_HANDSHAKE_SET_PASSWORD, UPIPE_SRT_HANDSHAKE_SIGNATURE, - password); + password, key_len); } /** @This returns the management structure for all srt handshakes sources. diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 48a39e7ce..8030d2147 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -729,8 +729,18 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, case UPIPE_SRT_HANDSHAKE_SET_PASSWORD: { UBASE_SIGNATURE_CHECK(args, UPIPE_SRT_HANDSHAKE_SIGNATURE) const char *password = va_arg(args, const char*); + upipe_srt_handshake->sek_len = va_arg(args, int); free(upipe_srt_handshake->password); upipe_srt_handshake->password = password ? strdup(password) : NULL; + switch (upipe_srt_handshake->sek_len) { + case 128/8: + case 192/8: + case 256/8: + break; + default: + upipe_err_va(upipe, "Invalid key length %d, using 128 bits", 8*upipe_srt_handshake->sek_len); + upipe_srt_handshake->sek_len = 128/8; + } return UBASE_ERR_NONE; } @@ -881,7 +891,9 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * } uint8_t klen = 4 * srt_km_get_klen(ext); - // FIXME: check key length + if (upipe_srt_handshake->sek_len != klen) + upipe_warn_va(upipe, "Requested key length %u, got %u. Proceeding.", + 8*upipe_srt_handshake->sek_len, 8*klen); memcpy(upipe_srt_handshake->salt, srt_km_get_salt(ext), 16); @@ -923,6 +935,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * gcry_cipher_close(aes); upipe_srt_handshake->sek_len = klen; + memcpy(upipe_srt_handshake->sek[0], osek, klen); return true; @@ -1048,7 +1061,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin size_t size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; - uint8_t klen = 128/8; // FIXME: 192 and 256 + const uint8_t klen = upipe_srt_handshake->sek_len; if (upipe_srt_handshake->password) { size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + (8+klen); extension |= SRT_HANDSHAKE_EXT_KMREQ; @@ -1116,7 +1129,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin gcry_randomize(upipe_srt_handshake->sek[0], klen, GCRY_STRONG_RANDOM); gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); - upipe_srt_handshake->sek_len = klen; srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); From 97aacc7cff6212a907d26c33018d66e1243d09a7 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 28 Nov 2023 18:03:37 +0000 Subject: [PATCH 031/231] rist_tx: Only set password if password is not null --- examples/rist_tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 1957a8d4e..edc32178d 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -215,7 +215,8 @@ static int start(void) struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_hs), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); - upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + if (password) + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); upipe_mgr_release(upipe_srt_handshake_mgr); From f3b4bacfdd688329fa31525ba52f146cf473a3f4 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 29 Nov 2023 11:27:04 +0000 Subject: [PATCH 032/231] upipe_srt_handshake: Respond to remote keepalives --- lib/upipe-srt/upipe_srt_handshake.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 8030d2147..72655fdcf 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1332,6 +1332,34 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } } +static struct uref *upipe_srt_handshake_handle_keepalive(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + + struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + if (!uref) + return NULL; + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_KEEPALIVE); + srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, srt_get_control_packet_type_specific(buf)); + + uref_block_unmap(uref, 0); + return uref; + // should go to sender +} + static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -1373,6 +1401,7 @@ static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const if (type == SRT_CONTROL_TYPE_HANDSHAKE) { return upipe_srt_handshake_handle_hs(upipe, buf, size, now); } else if (type == SRT_CONTROL_TYPE_KEEPALIVE) { + return upipe_srt_handshake_handle_keepalive(upipe, buf, size, now); } else if (type == SRT_CONTROL_TYPE_ACK) { return upipe_srt_handshake_handle_ack(upipe, buf, size, now); } else if (type == SRT_CONTROL_TYPE_NAK) { From 498c45ccd138c6a9ef96d244e42c08de41e43468 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 29 Nov 2023 11:52:34 +0000 Subject: [PATCH 033/231] upipe_srt_sender: Set out of order flag to 0 as per the IETF document "In the case of live streaming, it is set to 0 allowing out of order delivery of a packet. However, in this use case the Order Flag has to be ignored by the receiver. " --- lib/upipe-srt/upipe_srt_sender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 57062861a..32cd4a743 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -562,7 +562,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref srt_set_data_packet_message_number(buf, seqnum); srt_set_data_packet_seq(buf, seqnum); srt_set_data_packet_position(buf, SRT_DATA_POSITION_ONLY); - srt_set_data_packet_order(buf, true); + srt_set_data_packet_order(buf, false); srt_set_data_packet_retransmit(buf, false); #ifdef UPIPE_HAVE_GCRYPT_H From 06a1e299f4f8f53b3673f86f386afeea60073fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 09:31:41 +0100 Subject: [PATCH 034/231] Fix non-gcrypt build --- lib/upipe-srt/upipe_srt_handshake.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 72655fdcf..f76e26463 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1062,10 +1062,12 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; const uint8_t klen = upipe_srt_handshake->sek_len; +#ifdef UPIPE_HAVE_GCRYPT_H if (upipe_srt_handshake->password) { size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + (8+klen); extension |= SRT_HANDSHAKE_EXT_KMREQ; } +#endif if (upipe_srt_handshake->stream_id) { size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; extension |= SRT_HANDSHAKE_EXT_CONFIG; From b9e83959d619cc258d37293e9953432226bb95dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 09:34:29 +0100 Subject: [PATCH 035/231] srth: fix no password run --- lib/upipe-srt/upipe_srt_handshake.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f76e26463..ed7fa2349 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -731,15 +731,20 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, const char *password = va_arg(args, const char*); upipe_srt_handshake->sek_len = va_arg(args, int); free(upipe_srt_handshake->password); - upipe_srt_handshake->password = password ? strdup(password) : NULL; - switch (upipe_srt_handshake->sek_len) { - case 128/8: - case 192/8: - case 256/8: - break; - default: - upipe_err_va(upipe, "Invalid key length %d, using 128 bits", 8*upipe_srt_handshake->sek_len); - upipe_srt_handshake->sek_len = 128/8; + if (password) { + upipe_srt_handshake->password = strdup(password); + switch (upipe_srt_handshake->sek_len) { + case 128/8: + case 192/8: + case 256/8: + break; + default: + upipe_err_va(upipe, "Invalid key length %d, using 128 bits", 8*upipe_srt_handshake->sek_len); + upipe_srt_handshake->sek_len = 128/8; + } + } else { + upipe_srt_handshake->password = NULL; + upipe_srt_handshake->sek_len = 0; } return UBASE_ERR_NONE; } From 361c1067c400964f8bf4848a9d9414437a5a8d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 09:39:15 +0100 Subject: [PATCH 036/231] Revert "rist_tx: Only set password if password is not null" This reverts commit 97aacc7cff6212a907d26c33018d66e1243d09a7. --- examples/rist_tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index edc32178d..1957a8d4e 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -215,8 +215,7 @@ static int start(void) struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_hs), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); - if (password) - upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); upipe_mgr_release(upipe_srt_handshake_mgr); From e88b5f88e44ca9866dde5236e40fa330bb8ab4f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 10:43:56 +0100 Subject: [PATCH 037/231] srtr: fix leak --- lib/upipe-srt/upipe_srt_receiver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 031965522..982fdf8d8 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1227,8 +1227,11 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, */ static void upipe_srt_receiver_free(struct upipe *upipe) { + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); upipe_throw_dead(upipe); + free(upipe_srt_receiver->acks); + upipe_srt_receiver_clean_output(upipe); upipe_srt_receiver_clean_upump_timer(upipe); upipe_srt_receiver_clean_upump_timer_lost(upipe); From c0d5ca798f5dd444f4403cb863f4d5f73c12b287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 10:48:32 +0100 Subject: [PATCH 038/231] rist_tx: actually stop --- examples/rist_tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 1957a8d4e..7790e964b 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -368,7 +368,8 @@ int main(int argc, char *argv[]) return ret; if (0) { - upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); + restart = false; + //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, NULL, UCLOCK_FREQ, 0); upump_start(u); From 8201c5a6226412e7b5d42a6040d343042e2125ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 10:49:15 +0100 Subject: [PATCH 039/231] srth: remove subpipe control goes through srt receiver and srt sender sub, then gets forwarded to udpsink --- examples/rist_rx.c | 16 +-- examples/rist_tx.c | 8 -- lib/upipe-srt/upipe_srt_handshake.c | 210 ++-------------------------- lib/upipe-srt/upipe_srt_receiver.c | 11 +- lib/upipe-srt/upipe_srt_sender.c | 22 +-- 5 files changed, 34 insertions(+), 233 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 396f22ad5..6c1e26e7c 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -160,7 +160,6 @@ static struct upump_mgr *upump_mgr; static struct upipe *upipe_udpsrc; static struct upipe *upipe_udp_sink; -static struct upipe *upipe_srth_sub; static struct upipe *upipe_srtr_sub; static struct uprobe uprobe_udp; @@ -217,14 +216,6 @@ static int start(void) upipe_srt_handshake_set_password(upipe_srth, password, key_length / 8); upipe_mgr_release(upipe_srt_handshake_mgr); - upipe_srth_sub = upipe_void_alloc_sub(upipe_srth, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srth_sub")); - assert(upipe_srth_sub); - upipe_udp_sink = upipe_void_alloc_output(upipe_srth_sub, - udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, - "udpsink")); - upipe_release(upipe_udp_sink); - struct upipe_mgr *upipe_srt_receiver_mgr = upipe_srt_receiver_mgr_alloc(); struct upipe *upipe_srtr = upipe_void_chain_output(upipe_srth, upipe_srt_receiver_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr")); @@ -237,7 +228,11 @@ static int start(void) upipe_srtr_sub = upipe_void_alloc_sub(upipe_srtr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr_sub")); assert(upipe_srtr_sub); - upipe_set_output(upipe_srtr_sub, upipe_udp_sink); + + upipe_udp_sink = upipe_void_alloc_output(upipe_srtr_sub, + udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, + "udpsink")); + upipe_release(upipe_udp_sink); int udp_fd; /* receive SRT */ @@ -280,7 +275,6 @@ static void stop(struct upump *upump) upump_stop(upump); upump_free(upump); - upipe_release(upipe_srth_sub); upipe_release(upipe_srtr_sub); upipe_release(upipe_udpsrc); diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 7790e964b..5d52e00b5 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -82,7 +82,6 @@ static void usage(const char *argv0) { static struct upipe *upipe_udpsink; static struct upipe *upipe_udpsrc_srt; static struct upipe *upipe_udpsrc; -static struct upipe *upipe_srt_handshake_sub; static struct upipe *upipe_srt_sender; static struct upipe *upipe_srt_sender_sub; @@ -221,10 +220,6 @@ static int start(void) upipe_mgr_release(upipe_udpsrc_mgr); - upipe_srt_handshake_sub = upipe_void_alloc_sub(upipe_srt_handshake, - uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt handshake sub %u", z)); - assert(upipe_srt_handshake_sub); - upipe_srt_sender_sub = upipe_void_chain_output_sub(upipe_srt_handshake, upipe_srt_sender, uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender sub %u", z)); @@ -237,8 +232,6 @@ static int start(void) uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp sink %u", z)); upipe_release(upipe_udpsink); - upipe_set_output(upipe_srt_handshake_sub, upipe_udpsink); - int udp_fd = -1; if (listener) { if (!ubase_check(upipe_set_uri(upipe_udpsrc_srt, dirpath))) { @@ -281,7 +274,6 @@ static void stop(struct upump *upump) upipe_release(upipe_udpsrc_srt); upipe_release(upipe_udpsrc); - upipe_release(upipe_srt_handshake_sub); if (restart) start(); diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index ed7fa2349..99ec5ba01 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -38,9 +38,7 @@ #include "upipe/uref_attr.h" #include "upipe/upipe.h" #include "upipe/upipe_helper_upipe.h" -#include "upipe/upipe_helper_subpipe.h" #include "upipe/upipe_helper_urefcount.h" -#include "upipe/upipe_helper_urefcount_real.h" #include "upipe/upipe_helper_void.h" #include "upipe/upipe_helper_uref_mgr.h" #include "upipe/upipe_helper_ubuf_mgr.h" @@ -63,15 +61,9 @@ static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_form /** @internal @This is the private context of a SRT handshake pipe. */ struct upipe_srt_handshake { - /** real refcount management structure */ - struct urefcount urefcount_real; - /** refcount management structure exported to the public structure */ + /** refcount management structure */ struct urefcount urefcount; - struct upipe_mgr sub_mgr; - /** list of output subpipes */ - struct uchain outputs; - struct upump_mgr *upump_mgr; struct upump *upump_timer; struct upump *upump_timeout; @@ -132,15 +124,12 @@ struct upipe_srt_handshake { uint64_t last_hs_sent; - struct upipe *control; - /** public upipe structure */ struct upipe upipe; }; UPIPE_HELPER_UPIPE(upipe_srt_handshake, upipe, UPIPE_SRT_HANDSHAKE_SIGNATURE) -UPIPE_HELPER_UREFCOUNT(upipe_srt_handshake, urefcount, upipe_srt_handshake_no_input) -UPIPE_HELPER_UREFCOUNT_REAL(upipe_srt_handshake, urefcount_real, upipe_srt_handshake_free); +UPIPE_HELPER_UREFCOUNT(upipe_srt_handshake, urefcount, upipe_srt_handshake_free); UPIPE_HELPER_VOID(upipe_srt_handshake) @@ -191,99 +180,9 @@ struct upipe_srt_handshake_output { struct upipe upipe; }; -static int upipe_srt_handshake_output_check(struct upipe *upipe, struct uref *flow_format); -UPIPE_HELPER_UPIPE(upipe_srt_handshake_output, upipe, UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE) -UPIPE_HELPER_VOID(upipe_srt_handshake_output); -UPIPE_HELPER_UREFCOUNT(upipe_srt_handshake_output, urefcount, upipe_srt_handshake_output_free) -UPIPE_HELPER_OUTPUT(upipe_srt_handshake_output, output, flow_def, output_state, request_list) -UPIPE_HELPER_UREF_MGR(upipe_srt_handshake_output, uref_mgr, uref_mgr_request, - upipe_srt_handshake_output_check, - upipe_srt_handshake_output_register_output_request, - upipe_srt_handshake_output_unregister_output_request) -UPIPE_HELPER_UBUF_MGR(upipe_srt_handshake_output, ubuf_mgr, flow_format, ubuf_mgr_request, - upipe_srt_handshake_output_check, - upipe_srt_handshake_output_register_output_request, - upipe_srt_handshake_output_unregister_output_request) -UPIPE_HELPER_SUBPIPE(upipe_srt_handshake, upipe_srt_handshake_output, output, sub_mgr, outputs, - uchain) - -static int upipe_srt_handshake_output_check(struct upipe *upipe, struct uref *flow_format) -{ - struct upipe_srt_handshake_output *upipe_srt_handshake_output = upipe_srt_handshake_output_from_upipe(upipe); - if (flow_format) - upipe_srt_handshake_output_store_flow_def(upipe, flow_format); - - if (upipe_srt_handshake_output->uref_mgr == NULL) { - upipe_srt_handshake_output_require_uref_mgr(upipe); - return UBASE_ERR_NONE; - } - - if (upipe_srt_handshake_output->ubuf_mgr == NULL) { - struct uref *flow_format = - uref_block_flow_alloc_def(upipe_srt_handshake_output->uref_mgr, NULL); - if (unlikely(flow_format == NULL)) { - upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); - return UBASE_ERR_ALLOC; - } - upipe_srt_handshake_output_require_ubuf_mgr(upipe, flow_format); - return UBASE_ERR_NONE; - } - - return UBASE_ERR_NONE; -} - -/** @This is called when there is no external reference to the pipe anymore. - * - * @param upipe description structure of the pipe - */ -static void upipe_srt_handshake_no_input(struct upipe *upipe) -{ - upipe_srt_handshake_throw_sub_outputs(upipe, UPROBE_SOURCE_END); - upipe_srt_handshake_release_urefcount_real(upipe); -} -/** @internal @This allocates an output subpipe of a dup pipe. - * - * @param mgr common management structure - * @param uprobe structure used to raise events - * @param signature signature of the pipe allocator - * @param args optional arguments - * @return pointer to upipe or NULL in case of allocation error - */ -static struct upipe *upipe_srt_handshake_output_alloc(struct upipe_mgr *mgr, - struct uprobe *uprobe, - uint32_t signature, va_list args) -{ - if (mgr->signature != UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE) - return NULL; - - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_sub_mgr(mgr); - if (upipe_srt_handshake->control) - return NULL; - - struct upipe *upipe = upipe_srt_handshake_output_alloc_void(mgr, uprobe, signature, args); - if (unlikely(upipe == NULL)) - return NULL; - -// struct upipe_srt_handshake_output *upipe_srt_handshake_output = upipe_srt_handshake_output_from_upipe(upipe); - - upipe_srt_handshake->control = upipe; - - upipe_srt_handshake_output_init_urefcount(upipe); - upipe_srt_handshake_output_init_output(upipe); - upipe_srt_handshake_output_init_sub(upipe); - upipe_srt_handshake_output_init_ubuf_mgr(upipe); - upipe_srt_handshake_output_init_uref_mgr(upipe); - - upipe_throw_ready(upipe); - - upipe_srt_handshake_output_require_uref_mgr(upipe); - - return upipe; -} - -static void upipe_srt_handshake_output_shutdown(struct upipe *upipe) +static void upipe_srt_handshake_shutdown(struct upipe *upipe) { - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_sub_mgr(upipe->mgr); + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); uint64_t now = uclock_now(upipe_srt_handshake->uclock); uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; @@ -308,30 +207,11 @@ static void upipe_srt_handshake_output_shutdown(struct upipe *upipe) memset(extra, 0, 4); uref_block_unmap(uref, 0); - upipe_srt_handshake_output_output(upipe, uref, + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, &upipe_srt_handshake->upump_timer); } -/** @This frees a upipe. - * - * @param upipe description structure of the pipe - */ -static void upipe_srt_handshake_output_free(struct upipe *upipe) -{ - upipe_srt_handshake_output_shutdown(upipe); - upipe_throw_dead(upipe); - - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_sub_mgr(upipe->mgr); - upipe_srt_handshake->control = NULL; - upipe_srt_handshake_output_clean_output(upipe); - upipe_srt_handshake_output_clean_sub(upipe); - upipe_srt_handshake_output_clean_urefcount(upipe); - upipe_srt_handshake_output_clean_ubuf_mgr(upipe); - upipe_srt_handshake_output_clean_uref_mgr(upipe); - upipe_srt_handshake_output_free_void(upipe); -} - static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_size, uint32_t timestamp, uint8_t **cif) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -416,79 +296,11 @@ static void upipe_srt_handshake_timer(struct upump *upump) uref_block_unmap(uref, 0); - /* control goes through subpipe */ - upipe_srt_handshake_output_output(upipe_srt_handshake->control, uref, + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, &upipe_srt_handshake->upump_timer); upipe_srt_handshake->last_hs_sent = now; } -/** @internal @This sets the input flow definition. - * - * @param upipe description structure of the pipe - * @param flow_def flow definition packet - * @return an error code - */ -static int upipe_srt_handshake_output_set_flow_def(struct upipe *upipe, struct uref *flow_def) -{ - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - if (flow_def == NULL) - return UBASE_ERR_INVALID; - UBASE_RETURN(uref_flow_match_def(flow_def, "block.")) - - if (upipe_srt_handshake->control) { - struct uref *flow_def_dup = uref_dup(flow_def); - if (unlikely(flow_def_dup == NULL)) - return UBASE_ERR_ALLOC; - upipe_srt_handshake_output_store_flow_def(upipe_srt_handshake->control, flow_def_dup); - } - - return UBASE_ERR_NONE; -} - -/** @internal @This processes control commands on an output subpipe of a dup - * pipe. - * - * @param upipe description structure of the pipe - * @param command type of command to process - * @param args arguments of the command - * @return an error code - */ -static int _upipe_srt_handshake_output_control(struct upipe *upipe, - int command, va_list args) -{ - UBASE_HANDLED_RETURN(upipe_srt_handshake_output_control_super(upipe, command, args)); - UBASE_HANDLED_RETURN(upipe_srt_handshake_output_control_output(upipe, command, args)); - switch (command) { - case UPIPE_SET_FLOW_DEF: { - struct uref *flow_def = va_arg(args, struct uref *); - return upipe_srt_handshake_output_set_flow_def(upipe, flow_def); - } - default: - return UBASE_ERR_UNHANDLED; - } -} -static int upipe_srt_handshake_output_control(struct upipe *upipe, int command, va_list args) -{ - UBASE_RETURN(_upipe_srt_handshake_output_control(upipe, command, args)) - return upipe_srt_handshake_output_check(upipe, NULL); -} - -/** @internal @This initializes the output manager for a srt set pipe. - * - * @param upipe description structure of the pipe - */ -static void upipe_srt_handshake_init_sub_mgr(struct upipe *upipe) -{ - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - struct upipe_mgr *sub_mgr = &upipe_srt_handshake->sub_mgr; - sub_mgr->refcount = upipe_srt_handshake_to_urefcount_real(upipe_srt_handshake); - sub_mgr->signature = UPIPE_SRT_HANDSHAKE_OUTPUT_SIGNATURE; - sub_mgr->upipe_alloc = upipe_srt_handshake_output_alloc; - sub_mgr->upipe_input = NULL; - sub_mgr->upipe_control = upipe_srt_handshake_output_control; -} - - /** @internal @This allocates a SRT handshake pipe. * * @param mgr common management structure @@ -514,9 +326,6 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, #endif upipe_srt_handshake_init_urefcount(upipe); - upipe_srt_handshake_init_urefcount_real(upipe); - upipe_srt_handshake_init_sub_outputs(upipe); - upipe_srt_handshake_init_sub_mgr(upipe); upipe_srt_handshake_init_uref_mgr(upipe); upipe_srt_handshake_init_ubuf_mgr(upipe); @@ -539,7 +348,6 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->last_hs_sent = 0; upipe_srt_handshake->expect_conclusion = false; - upipe_srt_handshake->control = NULL; upipe_srt_handshake->stream_id = NULL; upipe_srt_handshake->stream_id_len = 0; @@ -697,7 +505,6 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); UBASE_HANDLED_RETURN(upipe_srt_handshake_control_output(upipe, command, args)); - UBASE_HANDLED_RETURN(upipe_srt_handshake_control_outputs(upipe, command, args)); switch (command) { case UPIPE_ATTACH_UPUMP_MGR: @@ -1473,7 +1280,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, } else { uref_free(uref); if (reply) { - upipe_srt_handshake_output_output(upipe_srt_handshake->control, reply, upump_p); + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, reply, upump_p); } } } else { @@ -1490,6 +1297,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, static void upipe_srt_handshake_free(struct upipe *upipe) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + upipe_srt_handshake_shutdown(upipe); upipe_throw_dead(upipe); free(upipe_srt_handshake->password); @@ -1503,8 +1311,6 @@ static void upipe_srt_handshake_free(struct upipe *upipe) upipe_srt_handshake_clean_ubuf_mgr(upipe); upipe_srt_handshake_clean_uref_mgr(upipe); upipe_srt_handshake_clean_urefcount(upipe); - upipe_srt_handshake_clean_urefcount_real(upipe); - upipe_srt_handshake_clean_sub_outputs(upipe); upipe_srt_handshake_free_void(upipe); } diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 982fdf8d8..b6352fc40 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1084,10 +1084,15 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, upipe_srt_receiver->rtt_variance += var; upipe_srt_receiver->rtt_variance /= 4; } + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + } else { + ubase_assert(uref_block_unmap(uref, 0)); + if (upipe_srt_receiver->control) + upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, NULL); + else + uref_free(uref); } - - ubase_assert(uref_block_unmap(uref, 0)); - uref_free(uref); return; } diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 32cd4a743..b0e965ee7 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -139,6 +139,12 @@ struct upipe_srt_sender_input { static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts, struct upump **upump_p); +UPIPE_HELPER_UPIPE(upipe_srt_sender_input, upipe, UPIPE_SRT_SENDER_INPUT_SIGNATURE) +UPIPE_HELPER_UREFCOUNT(upipe_srt_sender_input, urefcount, upipe_srt_sender_input_free) +UPIPE_HELPER_VOID(upipe_srt_sender_input); +UPIPE_HELPER_SUBPIPE(upipe_srt_sender, upipe_srt_sender_input, output, sub_mgr, inputs, + uchain) + /** @internal @This handles SRT messages. * * @param upipe description structure of the pipe @@ -175,18 +181,16 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, while (srt_get_nak_range(&buf, &s, &seq, &packets)) { upipe_srt_sender_lost_sub_n(upipe, seq, packets, upump_p); } + uref_block_unmap(uref, 0); + uref_free(uref); + } else { + struct upipe *upipe_super = NULL; + upipe_srt_sender_input_get_super(upipe, &upipe_super); + uref_block_unmap(uref, 0); + upipe_srt_sender_output(upipe_super, uref, NULL); } - - uref_block_unmap(uref, 0); - uref_free(uref); } -UPIPE_HELPER_UPIPE(upipe_srt_sender_input, upipe, UPIPE_SRT_SENDER_INPUT_SIGNATURE) -UPIPE_HELPER_UREFCOUNT(upipe_srt_sender_input, urefcount, upipe_srt_sender_input_free) -UPIPE_HELPER_VOID(upipe_srt_sender_input); -UPIPE_HELPER_SUBPIPE(upipe_srt_sender, upipe_srt_sender_input, output, sub_mgr, inputs, - uchain) - /** @internal @This retransmits a number of packets */ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint32_t pkts, struct upump **upump_p) { From 03dbfeed832c6c41d137ac1de8b3e2920fcf24ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 11:09:43 +0100 Subject: [PATCH 040/231] srt_sender: use right timestamp --- lib/upipe-srt/upipe_srt_sender.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index b0e965ee7..23f85537b 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -186,6 +186,15 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, } else { struct upipe *upipe_super = NULL; upipe_srt_sender_input_get_super(upipe, &upipe_super); + if (type == SRT_CONTROL_TYPE_HANDSHAKE) { + uint64_t ts = srt_get_packet_timestamp(buf); + if (ts) { + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); + uint64_t now = uclock_now(upipe_srt_sender->uclock); + upipe_srt_sender->establish_time = now - ts * UCLOCK_FREQ / 1000000; + } + } + uref_block_unmap(uref, 0); upipe_srt_sender_output(upipe_super, uref, NULL); } @@ -380,7 +389,6 @@ static int upipe_srt_sender_check(struct upipe *upipe, struct uref *flow_format) return UBASE_ERR_NONE; if (upipe_srt_sender->upump_timer == NULL) { - upipe_srt_sender->establish_time = uclock_now(upipe_srt_sender->uclock); // FIXME struct upump *upump = upump_alloc_timer(upipe_srt_sender->upump_mgr, upipe_srt_sender_timer, upipe, upipe->refcount, From 04b08a0b779fd9d177718b62238582761e605d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 30 Nov 2023 13:57:26 +0100 Subject: [PATCH 041/231] srt sender: do not output handshake packet if no data yet gets rid of warning: [srt sender 1] no flow def, dropping uref --- lib/upipe-srt/upipe_srt_sender.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 23f85537b..a185ddac2 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -186,17 +186,18 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, } else { struct upipe *upipe_super = NULL; upipe_srt_sender_input_get_super(upipe, &upipe_super); + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); if (type == SRT_CONTROL_TYPE_HANDSHAKE) { uint64_t ts = srt_get_packet_timestamp(buf); if (ts) { - struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); uint64_t now = uclock_now(upipe_srt_sender->uclock); upipe_srt_sender->establish_time = now - ts * UCLOCK_FREQ / 1000000; } } uref_block_unmap(uref, 0); - upipe_srt_sender_output(upipe_super, uref, NULL); + if (upipe_srt_sender->flow_def) + upipe_srt_sender_output(upipe_super, uref, NULL); } } From a8b966a9b1b713e2200e36f20f3463126380644f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 4 Dec 2023 08:15:49 +0000 Subject: [PATCH 042/231] upipe-srt: Free uref if we can't output it --- lib/upipe-srt/upipe_srt_sender.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index a185ddac2..8b6c4fe2c 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -198,6 +198,8 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, uref_block_unmap(uref, 0); if (upipe_srt_sender->flow_def) upipe_srt_sender_output(upipe_super, uref, NULL); + else + uref_free(uref); } } From d354b3a764098a681baad6336e6ebca46134423a Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 4 Dec 2023 09:09:49 +0000 Subject: [PATCH 043/231] upipe-srt: memset the end of control packets to placate valgrind --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 99ec5ba01..bba40622b 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1168,6 +1168,8 @@ static struct uref *upipe_srt_handshake_handle_keepalive(struct upipe *upipe, co srt_set_control_packet_type(out, SRT_CONTROL_TYPE_KEEPALIVE); srt_set_control_packet_subtype(out, 0); srt_set_control_packet_type_specific(out, srt_get_control_packet_type_specific(buf)); + uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); + memset(extra, 0, 4); uref_block_unmap(uref, 0); return uref; @@ -1196,6 +1198,8 @@ static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const ui srt_set_control_packet_type(out, SRT_CONTROL_TYPE_ACKACK); srt_set_control_packet_subtype(out, 0); srt_set_control_packet_type_specific(out, srt_get_control_packet_type_specific(buf)); + uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); + memset(extra, 0, 4); uref_block_unmap(uref, 0); return uref; From 7e73297ad0fc75b0afd37f7b46d79d534dae6b8a Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 4 Dec 2023 09:17:14 +0000 Subject: [PATCH 044/231] upipe-srt: Set control_packet_type_specific in shutdown message to placate valgrind --- lib/upipe-srt/upipe_srt_handshake.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index bba40622b..ef3362a08 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -203,6 +203,7 @@ static void upipe_srt_handshake_shutdown(struct upipe *upipe) srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); srt_set_control_packet_type(out, SRT_CONTROL_TYPE_SHUTDOWN); srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, 0); uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); memset(extra, 0, 4); From b350927a2bdd5416a80ec3187ff311629a6da7f5 Mon Sep 17 00:00:00 2001 From: James Darnley Date: Mon, 4 Dec 2023 13:18:53 +0100 Subject: [PATCH 045/231] rist_tx: use dynamically allocated uprobes --- examples/rist_tx.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 5d52e00b5..db5f2b8ca 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -96,8 +96,6 @@ static int key_length = 128; static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; -static struct uprobe uprobe_udp_srt; -static struct uprobe uprobe_hs; static struct uprobe *logger; static bool restart = true; @@ -204,15 +202,13 @@ static int start(void) if (!ubase_check(upipe_set_option(upipe_srt_sender, "latency", latency))) return EXIT_FAILURE; - uprobe_init(&uprobe_udp_srt, catch_udp, uprobe_use(logger)); - uprobe_init(&uprobe_hs, catch_hs, uprobe_use(logger)); upipe_udpsrc_srt = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc_va(&uprobe_udp_srt, loglevel, "udp source srt %u", z)); + uprobe_pfx_alloc_va(uprobe_alloc(catch_udp, uprobe_use(logger)), loglevel, "udp source srt %u", z)); upipe_attach_uclock(upipe_udpsrc_srt); struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, - uprobe_pfx_alloc_va(uprobe_use(&uprobe_hs), loglevel, "srt handshake %u", z)); + uprobe_pfx_alloc_va(uprobe_alloc(catch_hs, uprobe_use(logger)), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); @@ -379,8 +375,6 @@ int main(int argc, char *argv[]) upump_free(sigint_pump); uprobe_release(logger); - uprobe_clean(&uprobe_udp_srt); - uprobe_clean(&uprobe_hs); upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); From fbe3277d7be7ccb06d5c89da77ad3fee8a5369c8 Mon Sep 17 00:00:00 2001 From: James Darnley Date: Mon, 4 Dec 2023 13:25:55 +0100 Subject: [PATCH 046/231] rist_tx: set pointers to null to prevent double frees --- examples/rist_tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index db5f2b8ca..5aa25f520 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -269,7 +269,9 @@ static void stop(struct upump *upump) } upipe_release(upipe_udpsrc_srt); + upipe_udpsrc_srt = NULL; upipe_release(upipe_udpsrc); + upipe_udpsrc = NULL; if (restart) start(); From 396cb9c8d320a3bb2d18eaf7c7118477813f729e Mon Sep 17 00:00:00 2001 From: James Darnley Date: Mon, 4 Dec 2023 13:38:27 +0100 Subject: [PATCH 047/231] upipe-srt: fix header guards --- include/upipe-srt/upipe_srt_handshake.h | 4 ++-- include/upipe-srt/upipe_srt_receiver.h | 4 ++-- include/upipe-srt/upipe_srt_sender.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h index aea1b1a8e..f2edcc96e 100644 --- a/include/upipe-srt/upipe_srt_handshake.h +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -27,9 +27,9 @@ * @short Upipe module for SRT handshakes */ -#ifndef _UPIPE_MODULES_UPIPE_SRT_HANDSHAKE_H_ +#ifndef _UPIPE_SRT_UPIPE_SRT_HANDSHAKE_H_ /** @hidden */ -#define _UPIPE_MODULES_UPIPE_SRT_HANDSHAKE_H_ +#define _UPIPE_SRT_UPIPE_SRT_HANDSHAKE_H_ #ifdef __cplusplus extern "C" { #endif diff --git a/include/upipe-srt/upipe_srt_receiver.h b/include/upipe-srt/upipe_srt_receiver.h index ea16d6042..226e71893 100644 --- a/include/upipe-srt/upipe_srt_receiver.h +++ b/include/upipe-srt/upipe_srt_receiver.h @@ -27,9 +27,9 @@ * @short Upipe module for SRT handshakes */ -#ifndef _UPIPE_MODULES_UPIPE_SRT_RECEIVER_H_ +#ifndef _UPIPE_SRT_UPIPE_SRT_RECEIVER_H_ /** @hidden */ -#define _UPIPE_MODULES_UPIPE_SRT_RECEIVER_H_ +#define _UPIPE_SRT_UPIPE_SRT_RECEIVER_H_ #ifdef __cplusplus extern "C" { #endif diff --git a/include/upipe-srt/upipe_srt_sender.h b/include/upipe-srt/upipe_srt_sender.h index 29465a811..7ec9025af 100644 --- a/include/upipe-srt/upipe_srt_sender.h +++ b/include/upipe-srt/upipe_srt_sender.h @@ -27,9 +27,9 @@ * @short Upipe module sending SRT */ -#ifndef _UPIPE_FILTERS_UPIPE_SRT_SENDER_H_ +#ifndef _UPIPE_SRT_UPIPE_SRT_SENDER_H_ /** @hidden */ -#define _UPIPE_FILTERS_UPIPE_SRT_SENDER_H_ +#define _UPIPE_SRT_UPIPE_SRT_SENDER_H_ #ifdef __cplusplus extern "C" { #endif From 2da3cfdd7f79c3e06f0ba6fe282acb136d6e22a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Dec 2023 09:28:58 +0100 Subject: [PATCH 048/231] srth: pass random seed through upipe manager --- examples/rist_rx.c | 2 +- examples/rist_tx.c | 2 +- include/upipe-srt/upipe_srt_handshake.h | 2 +- lib/upipe-srt/upipe_srt_handshake.c | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 6c1e26e7c..4bdb0b517 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -205,7 +205,7 @@ static int start(void) upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); upipe_mgr_release(upipe_udpsrc_mgr); - struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); + struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc); struct upipe *upipe_srth = upipe_void_alloc_output(upipe_udpsrc, upipe_srt_handshake_mgr, &uprobe_srt); assert(upipe_srth); diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 5aa25f520..0f86a7da8 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -206,7 +206,7 @@ static int start(void) uprobe_pfx_alloc_va(uprobe_alloc(catch_udp, uprobe_use(logger)), loglevel, "udp source srt %u", z)); upipe_attach_uclock(upipe_udpsrc_srt); - struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc(); + struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc_srt); struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, uprobe_pfx_alloc_va(uprobe_alloc(catch_hs, uprobe_use(logger)), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h index f2edcc96e..a8e072d4f 100644 --- a/include/upipe-srt/upipe_srt_handshake.h +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -84,7 +84,7 @@ static inline int upipe_srt_handshake_set_password(struct upipe *upipe, * * @return pointer to manager */ -struct upipe_mgr *upipe_srt_handshake_mgr_alloc(void); +struct upipe_mgr *upipe_srt_handshake_mgr_alloc(long seed); #ifdef __cplusplus } diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index ef3362a08..6d17c3a50 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -338,7 +338,6 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_init_uclock(upipe); upipe_srt_handshake_require_uclock(upipe); - srand48((long)&uprobe); // FIXME upipe_srt_handshake->isn = 0; upipe_srt_handshake->remote_socket_id = 0; // will be set with remote first packet upipe_srt_handshake->mtu = 1500; @@ -1334,8 +1333,10 @@ static struct upipe_mgr upipe_srt_handshake_mgr = { /** @This returns the management structure for all SRT handshake sources * * @return pointer to manager + * @param seed random seed for socket id and syn cookie */ -struct upipe_mgr *upipe_srt_handshake_mgr_alloc(void) +struct upipe_mgr *upipe_srt_handshake_mgr_alloc(long seed) { + srand48(seed); return &upipe_srt_handshake_mgr; } From 783fe551ff7e65fb400602d7556d85abbcacb659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Dec 2023 16:01:35 +0100 Subject: [PATCH 049/231] srth: warning --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 6d17c3a50..97601d818 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -467,7 +467,7 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio return UBASE_ERR_ALLOC; } - strncpy(stream_id, value, stream_id_len); + strncpy((char*)stream_id, value, stream_id_len); for (size_t i = 0; i < stream_id_len; i += 4) { uint8_t tmp = stream_id[i+0]; From 222e8385c8459a66329f46fd33bb05721710d40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Dec 2023 16:07:07 +0100 Subject: [PATCH 050/231] handshake: handle key refresh, and odd keys --- lib/upipe-srt/upipe_srt_handshake.c | 138 ++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 30 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 97601d818..8bedf5542 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -650,7 +650,10 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) upipe_err(upipe, "damn"); - // TODO: odd key ? + opaque.v = upipe_srt_handshake->sek[1]; + opaque.size = upipe_srt_handshake->sek_len; + if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.odd_key"))) + upipe_err(upipe, "damn"); uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); @@ -723,7 +726,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * *wrap_len = ((*kk == 3) ? 2 : 1) * klen + 8; - uint8_t osek[32]; + uint8_t osek[64]; /* 2x 256 bits keys */ gcry_cipher_hd_t aes; err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); @@ -734,13 +737,13 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * err = gcry_cipher_setkey(aes, kek, klen); if (err) { - upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); + upipe_err_va(upipe, "Couldn't use key encrypting key (%s)", gcry_strerror(err)); goto key_error; } - err = gcry_cipher_decrypt(aes, osek, klen, *wrap, *wrap_len); + err = gcry_cipher_decrypt(aes, osek, ((*kk == 3) ? 2 : 1) * klen, *wrap, *wrap_len); if (err) { - upipe_err_va(upipe, "Couldn't decrypt session key (0x%x)", err); + upipe_err_va(upipe, "Couldn't decrypt session key (%s)", gcry_strerror(err)); goto key_error; } @@ -748,7 +751,12 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * upipe_srt_handshake->sek_len = klen; - memcpy(upipe_srt_handshake->sek[0], osek, klen); + if (*kk == 3) { + memcpy(upipe_srt_handshake->sek[0], osek, klen); + memcpy(upipe_srt_handshake->sek[1], &osek[klen], klen); + } else { + memcpy(upipe_srt_handshake->sek[(*kk & (1<<0)) ? 0 : 1], osek, klen); + } return true; @@ -1146,6 +1154,61 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } } +static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + + uint8_t kk = 0; + const uint8_t *wrap; + uint8_t wrap_len = 0; + + const uint8_t *cif = srt_get_control_packet_cif(buf); + size -= SRT_HEADER_SIZE; + + if (!srt_check_km(buf, size) || !upipe_srt_handshake_parse_kmreq(upipe, buf, &kk, &wrap, &wrap_len)) + if (!upipe_srt_handshake_parse_kmreq(upipe, cif, &kk, &wrap, &wrap_len)) { + upipe_err_va(upipe, "parse failed"); + return NULL; + } + + struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); + if (!uref) + return NULL; + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); + srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_KMRSP); + srt_set_control_packet_type_specific(out, 0); + uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); + memset(extra, 0, SRT_KMREQ_COMMON_SIZE); + + if (wrap_len) { + extra[0] = 0x12; // S V PT + extra[1] = 0x20; extra[2] = 0x29; // Sign + srt_km_set_kk(extra, kk); + srt_km_set_cipher(extra, SRT_KMREQ_CIPHER_AES); + extra[10] = 2; // SE + extra[14] = 4; // slen; + srt_km_set_klen(extra, upipe_srt_handshake->sek_len / 4); + memcpy(&extra[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + memcpy(&extra[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + } + upipe_srt_handshake_finalize(upipe); + + uref_block_unmap(uref, 0); + return uref; +} + static struct uref *upipe_srt_handshake_handle_keepalive(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -1212,34 +1275,49 @@ static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const uint16_t type = srt_get_control_packet_type(buf); uint64_t now = uclock_now(upipe_srt_handshake->uclock); + const uint8_t *cif = srt_get_control_packet_cif(buf); upipe_verbose_va(upipe, "control pkt %s", get_ctrl_type(type)); *handled = true; - if (type == SRT_CONTROL_TYPE_HANDSHAKE) { - return upipe_srt_handshake_handle_hs(upipe, buf, size, now); - } else if (type == SRT_CONTROL_TYPE_KEEPALIVE) { - return upipe_srt_handshake_handle_keepalive(upipe, buf, size, now); - } else if (type == SRT_CONTROL_TYPE_ACK) { - return upipe_srt_handshake_handle_ack(upipe, buf, size, now); - } else if (type == SRT_CONTROL_TYPE_NAK) { - *handled = false; - } else if (type == SRT_CONTROL_TYPE_ACKACK) { - *handled = false; // send to next pipe for RTT estimation - } else if (type == SRT_CONTROL_TYPE_SHUTDOWN) { - upipe_err_va(upipe, "shutdown requested"); - upipe_throw_source_end(upipe); - } else if (type == SRT_CONTROL_TYPE_DROPREQ) { - const uint8_t *cif = srt_get_control_packet_cif(buf); - if (!srt_check_dropreq(cif, size - SRT_HEADER_SIZE)) { - upipe_err_va(upipe, "dropreq pkt invalid"); - } else { - uint32_t first = srt_get_dropreq_first_seq(cif); - uint32_t last = srt_get_dropreq_last_seq(cif); - upipe_dbg_va(upipe, "sender dropped packets from %u to %u", first, last); - } - } else { - *handled = false; + if (size < SRT_HEADER_SIZE) { + upipe_err_va(upipe, "control packet too small (%d)", size); + return NULL; + } + + switch (type) { + case SRT_CONTROL_TYPE_HANDSHAKE: + return upipe_srt_handshake_handle_hs(upipe, buf, size, now); + + case SRT_CONTROL_TYPE_KEEPALIVE: + return upipe_srt_handshake_handle_keepalive(upipe, buf, size, now); + + case SRT_CONTROL_TYPE_ACK: + return upipe_srt_handshake_handle_ack(upipe, buf, size, now); + + case SRT_CONTROL_TYPE_USER: + return upipe_srt_handshake_handle_user(upipe, buf, size, now); + + case SRT_CONTROL_TYPE_SHUTDOWN: + upipe_err_va(upipe, "shutdown requested"); + upipe_throw_source_end(upipe); + break; + + case SRT_CONTROL_TYPE_DROPREQ: + if (!srt_check_dropreq(cif, size - SRT_HEADER_SIZE)) { + upipe_err_va(upipe, "dropreq pkt invalid"); + } else { + uint32_t first = srt_get_dropreq_first_seq(cif); + uint32_t last = srt_get_dropreq_last_seq(cif); + upipe_dbg_va(upipe, "sender dropped packets from %u to %u", first, last); + } + break; + + case SRT_CONTROL_TYPE_NAK: /* fallthrough */ + case SRT_CONTROL_TYPE_ACKACK: // send to next pipe for RTT estimation + default: + *handled = false; + break; } return NULL; From e15b7ea3a4e7c3d0c0087a4edb7c1e362e65bd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Dec 2023 16:07:25 +0100 Subject: [PATCH 051/231] srt receiver: handle odd keys --- lib/upipe-srt/upipe_srt_receiver.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index b6352fc40..901c00dd1 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -852,6 +852,13 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo upipe_srt_receiver->sek_len = opaque.size; memcpy(upipe_srt_receiver->sek[0], opaque.v, opaque.size); } + + if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.odd_key"))) { + if (opaque.size > sizeof(upipe_srt_receiver->sek[1])) + opaque.size = sizeof(upipe_srt_receiver->sek[1]); + upipe_srt_receiver->sek_len = opaque.size; + memcpy(upipe_srt_receiver->sek[1], opaque.v, opaque.size); + } #endif flow_def = uref_dup(flow_def); @@ -1106,6 +1113,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, bool retransmit = srt_get_data_packet_retransmit(buf); uint32_t num = srt_get_data_packet_message_number(buf); uint32_t ts = srt_get_packet_timestamp(buf); + uint8_t kk = srt_get_data_packet_encryption(buf); ubase_assert(uref_block_unmap(uref, 0)); uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ @@ -1134,7 +1142,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, #ifdef UPIPE_HAVE_GCRYPT_H } else { const uint8_t *salt = upipe_srt_receiver->salt; - const uint8_t *sek = upipe_srt_receiver->sek[0]; + const uint8_t *sek = upipe_srt_receiver->sek[(kk & (1<<0))? 0 : 1]; int key_len = upipe_srt_receiver->sek_len; uint8_t iv[16]; From c13d563769d6f5754acf9e780fb1905e24676125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Dec 2023 16:08:49 +0100 Subject: [PATCH 052/231] srts: sets odd key, it's not used yet though --- lib/upipe-srt/upipe_srt_sender.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 8b6c4fe2c..2a8e195a2 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -436,6 +436,13 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref upipe_srt_sender->sek_len = opaque.size; memcpy(upipe_srt_sender->sek[0], opaque.v, opaque.size); } + + if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.odd_key"))) { + if (opaque.size > sizeof(upipe_srt_sender->sek[1])) + opaque.size = sizeof(upipe_srt_sender->sek[1]); + upipe_srt_sender->sek_len = opaque.size; + memcpy(upipe_srt_sender->sek[1], opaque.v, opaque.size); + } #endif return uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF); From 8e473515590ebd456b1f7ddaaa3027501fba8c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Dec 2023 13:15:23 +0000 Subject: [PATCH 053/231] srtr: send keepalive if no packet since 1s --- lib/upipe-srt/upipe_srt_receiver.c | 52 +++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 901c00dd1..c0c0c01e9 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -126,6 +126,9 @@ struct upipe_srt_receiver { /** last time a NACK was sent */ uint64_t last_nack[65536]; + /** last time any SRT packet was sent */ + uint64_t last_sent; + /** number of packets in the buffer */ uint64_t packets; @@ -334,15 +337,43 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) struct upipe *upipe = upump_get_opaque(upump, struct upipe *); struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); - if (upipe_srt_receiver->buffered == 0) - return; - uint64_t expected_seq = UINT64_MAX; uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); uint64_t now = uclock_now(upipe_srt_receiver->uclock); + if (now - upipe_srt_receiver->last_sent > UCLOCK_FREQ) { + struct uref *uref = uref_block_alloc(upipe_srt_receiver->uref_mgr, + upipe_srt_receiver->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + if (uref) { + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, now / 27); + srt_set_packet_dst_socket_id(out, upipe_srt_receiver->socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_KEEPALIVE); + srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, 0); + uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); + memset(extra, 0, 4); + + uref_block_unmap(uref, 0); + + upipe_srt_receiver->last_sent = now; + upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, + &upipe_srt_receiver->upump_timer_lost); + } + } + + if (upipe_srt_receiver->buffered == 0) + return; + /* space out NACKs a bit more than RTT. XXX: tune me */ uint64_t next_nack = now - rtt * 12 / 10; @@ -491,6 +522,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uref_block_unmap(uref, 0); upipe_srt_receiver->last_ack = now; assert(upipe_srt_receiver->control); + upipe_srt_receiver->last_sent = now; upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, NULL); upipe_srt_receiver->acks[upipe_srt_receiver->ack_widx].ack_num = ack_num; @@ -517,6 +549,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uref_block_resize(pkt, 0, 1472 - s); + upipe_srt_receiver->last_sent = now; upipe_srt_receiver_output_output(upipe_srt_receiver->control, pkt, NULL); } } @@ -731,6 +764,7 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->dups = 0; upipe_srt_receiver->latency = 0; + upipe_srt_receiver->last_sent = 0; upipe_srt_receiver->packets = 0; upipe_srt_receiver->bytes = 0; @@ -1068,11 +1102,12 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, return; } - uint64_t now = uclock_now(upipe_srt_receiver->uclock); if (srt_get_packet_control(buf)) { - if (srt_get_control_packet_type(buf) == SRT_CONTROL_TYPE_ACKACK) { + uint16_t type = srt_get_control_packet_type(buf); + + if (type == SRT_CONTROL_TYPE_ACKACK) { uint32_t ack_num = srt_get_control_packet_type_specific(buf); uint64_t rtt = upipe_srt_receiver_ackack(upipe, ack_num, now); upipe_verbose_va(upipe, "RTT %.2f", (float) rtt / 27000.); @@ -1095,9 +1130,10 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uref_free(uref); } else { ubase_assert(uref_block_unmap(uref, 0)); - if (upipe_srt_receiver->control) - upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, NULL); - else + if (upipe_srt_receiver->control) { + upipe_srt_receiver->last_sent = now; + upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, upump_p); + } else uref_free(uref); } return; From 28b47dcc2a20467070ef2250ef53d78dfe6614da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Dec 2023 13:22:59 +0000 Subject: [PATCH 054/231] srts: send keepalive every second if needed max timeout: 1.24s (between 1.00 and 1.24s) could do between 0.75 and 0.99s if needed --- lib/upipe-srt/upipe_srt_sender.c | 65 ++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 2a8e195a2..955cb45f1 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -104,6 +104,8 @@ struct upipe_srt_sender { uint8_t sek[2][32]; uint8_t sek_len; + uint64_t last_sent; + /** public upipe structure */ struct upipe upipe; }; @@ -154,6 +156,17 @@ UPIPE_HELPER_SUBPIPE(upipe_srt_sender, upipe_srt_sender_input, output, sub_mgr, static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { + struct upipe *upipe_super = NULL; + upipe_srt_sender_input_get_super(upipe, &upipe_super); + struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); + + upipe_srt_sender_check(upipe_super, NULL); + + uint64_t now = 0; + + if (upipe_srt_sender->uclock) + now = uclock_now(upipe_srt_sender->uclock); + size_t total_size; ubase_assert(uref_block_size(uref, &total_size)); @@ -184,21 +197,17 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, uref_block_unmap(uref, 0); uref_free(uref); } else { - struct upipe *upipe_super = NULL; - upipe_srt_sender_input_get_super(upipe, &upipe_super); - struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); if (type == SRT_CONTROL_TYPE_HANDSHAKE) { uint64_t ts = srt_get_packet_timestamp(buf); - if (ts) { - uint64_t now = uclock_now(upipe_srt_sender->uclock); + if (ts) upipe_srt_sender->establish_time = now - ts * UCLOCK_FREQ / 1000000; - } } uref_block_unmap(uref, 0); - if (upipe_srt_sender->flow_def) - upipe_srt_sender_output(upipe_super, uref, NULL); - else + if (upipe_srt_sender->flow_def) { + upipe_srt_sender->last_sent = now; + upipe_srt_sender_output(upipe_super, uref, upump_p); + } else uref_free(uref); } } @@ -210,6 +219,8 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 upipe_srt_sender_input_get_super(upipe, &upipe_super); struct upipe_srt_sender *upipe_srt_sender = upipe_srt_sender_from_upipe(upipe_super); + uint64_t now = uclock_now(upipe_srt_sender->uclock); + struct uchain *uchain; ulist_foreach(&upipe_srt_sender->queue, uchain) { struct uref *uref = uref_from_uchain(uchain); @@ -235,6 +246,7 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 uref_block_unmap(uref, 0); } + upipe_srt_sender->last_sent = now; upipe_srt_sender_output(upipe_super, uref_dup(uref), NULL); if (--pkts == 0) return; @@ -259,8 +271,6 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 return; } - uint64_t now = uclock_now(upipe_srt_sender->uclock); - memset(buf, 0, s); srt_set_packet_control(buf, true); srt_set_control_packet_type(buf, SRT_CONTROL_TYPE_DROPREQ); @@ -274,6 +284,7 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 srt_set_dropreq_last_seq(cif, seq + pkts - 1); uref_block_unmap(uref, 0); + upipe_srt_sender->last_sent = now; upipe_srt_sender_output(&upipe_srt_sender->upipe, uref, upump_p); } @@ -334,6 +345,33 @@ static void upipe_srt_sender_timer(struct upump *upump) uint64_t now = uclock_now(upipe_srt_sender->uclock); + if (now - upipe_srt_sender->last_sent > UCLOCK_FREQ) { + struct uref *uref = uref_block_alloc(upipe_srt_sender->uref_mgr, + upipe_srt_sender->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + if (uref) { + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, (now - upipe_srt_sender->establish_time) / 27); + srt_set_packet_dst_socket_id(out, upipe_srt_sender->socket_id); + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_KEEPALIVE); + srt_set_control_packet_subtype(out, 0); + srt_set_control_packet_type_specific(out, 0); + uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); + memset(extra, 0, 4); + + uref_block_unmap(uref, 0); + + upipe_srt_sender->last_sent = now; + upipe_srt_sender_output(upipe, uref, &upipe_srt_sender->upump_timer); + } + } + struct uchain *uchain, *uchain_tmp; ulist_delete_foreach(&upipe_srt_sender->queue, uchain, uchain_tmp) { struct uref *uref = uref_from_uchain(uchain); @@ -395,7 +433,7 @@ static int upipe_srt_sender_check(struct upipe *upipe, struct uref *flow_format) struct upump *upump = upump_alloc_timer(upipe_srt_sender->upump_mgr, upipe_srt_sender_timer, upipe, upipe->refcount, - UCLOCK_FREQ, UCLOCK_FREQ); + UCLOCK_FREQ, UCLOCK_FREQ / 4); upipe_srt_sender_set_upump_timer(upipe, upump); upump_start(upump); @@ -531,6 +569,8 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->sek_len = 0; + upipe_srt_sender->last_sent = 0; + upipe_throw_ready(upipe); return upipe; } @@ -663,6 +703,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref uref_attr_set_priv(uref, seqnum); /* Output packet immediately */ + upipe_srt_sender->last_sent = now; upipe_srt_sender_output(upipe, uref_dup(uref), upump_p); upipe_verbose_va(upipe, "Output & buffer %u", seqnum); From 4dbd8f54003e9d3a2f5f499a7720d4fb5ba4e9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Dec 2023 14:27:26 +0100 Subject: [PATCH 055/231] srth: do not reply to keepalive pipes already send them when needed --- lib/upipe-srt/upipe_srt_handshake.c | 32 +---------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 8bedf5542..6b59fb7a4 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1209,36 +1209,6 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u return uref; } -static struct uref *upipe_srt_handshake_handle_keepalive(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) -{ - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; - - struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); - if (!uref) - return NULL; - uint8_t *out; - int output_size = -1; - if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { - uref_free(uref); - upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); - } - - srt_set_packet_control(out, true); - srt_set_packet_timestamp(out, timestamp); - srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); - srt_set_control_packet_type(out, SRT_CONTROL_TYPE_KEEPALIVE); - srt_set_control_packet_subtype(out, 0); - srt_set_control_packet_type_specific(out, srt_get_control_packet_type_specific(buf)); - uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); - memset(extra, 0, 4); - - uref_block_unmap(uref, 0); - return uref; - // should go to sender -} - static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -1290,7 +1260,7 @@ static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const return upipe_srt_handshake_handle_hs(upipe, buf, size, now); case SRT_CONTROL_TYPE_KEEPALIVE: - return upipe_srt_handshake_handle_keepalive(upipe, buf, size, now); + break; case SRT_CONTROL_TYPE_ACK: return upipe_srt_handshake_handle_ack(upipe, buf, size, now); From 20be6bbdffc5f7af148b31067992525b7e060981 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 11 Dec 2023 19:44:48 +0000 Subject: [PATCH 056/231] upipe-srt/handshake: Do not output an ACKACK on Light ACKS or Small ACKS --- lib/upipe-srt/upipe_srt_handshake.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 6b59fb7a4..ec769ff4b 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1213,6 +1213,11 @@ static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const ui { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + uint32_t ack_number = srt_get_control_packet_type_specific(buf); + + /* Don't output an ACKACK on Light ACKs or Small ACKs */ + if (!ack_number) + return NULL; struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); @@ -1230,7 +1235,7 @@ static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const ui srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); srt_set_control_packet_type(out, SRT_CONTROL_TYPE_ACKACK); srt_set_control_packet_subtype(out, 0); - srt_set_control_packet_type_specific(out, srt_get_control_packet_type_specific(buf)); + srt_set_control_packet_type_specific(out, ack_number); uint8_t *extra = (uint8_t*)srt_get_control_packet_cif(out); memset(extra, 0, 4); From 7eb2f707f7b253ce35b86ae311dbcf6bc6a0a08f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 11 Dec 2023 20:02:43 +0000 Subject: [PATCH 057/231] upipe-srt/sender: seqnum is 31-bits, not 32 --- lib/upipe-srt/upipe_srt_sender.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 955cb45f1..723931a8b 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -617,6 +617,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref uint64_t now = uclock_now(upipe_srt_sender->uclock); uint32_t seqnum = upipe_srt_sender->seqnum++; + seqnum &= (1U << 31) - 1; memset(buf, 0, SRT_HEADER_SIZE); srt_set_packet_control(buf, false); srt_set_packet_timestamp(buf, (now - upipe_srt_sender->establish_time) / 27); From 1ec61343fe08674906dd11310b7a7c7ae42ed490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 14 Dec 2023 10:43:11 +0100 Subject: [PATCH 058/231] srtr: use 31bits arithmetic when needed --- lib/upipe-srt/upipe_srt_receiver.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index c0c0c01e9..6cc400e1a 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -404,7 +404,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) if (last_received == UINT64_MAX) last_received = expected_seq - 1; - for (uint32_t seq = expected_seq; seq != seqnum; seq++) { + for (uint32_t seq = expected_seq; seq != seqnum; seq = (seq + 1) & ~(1 << 31)) { /* if packet was lost, we should have detected it already */ if (upipe_srt_receiver->last_nack[seq & 0xffff] == 0) { upipe_err_va(upipe, "packet %u missing but was not marked as lost!", seq); @@ -422,7 +422,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) } /* update NACK request time */ - for (uint32_t seq = expected_seq; seq != seqnum; seq++) { + for (uint32_t seq = expected_seq; seq != seqnum; seq = (seq + 1) & ~(1 << 31)) { upipe_srt_receiver->last_nack[seq & 0xffff] = now; } @@ -480,7 +480,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) } next: - expected_seq = (seqnum + 1) & UINT32_MAX; + expected_seq = (seqnum + 1) & ~(1 << 31); } // A Full ACK control packet is sent every 10 ms and has all the fields of Figure 13. @@ -581,6 +581,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); if (likely(upipe_srt_receiver->last_output_seqnum != UINT64_MAX)) { uint32_t diff = seqnum - upipe_srt_receiver->last_output_seqnum - 1; + diff &= ~(1 << 31); // seqnums are 31 bits if (diff) { upipe_srt_receiver->loss += diff; upipe_dbg_va(upipe, "PKT LOSS: %" PRIu64 " -> %"PRIu64" DIFF %u", From 012bda8c6e792757264787ee32be83e320eb65d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 14 Dec 2023 16:46:23 +0100 Subject: [PATCH 059/231] srt sender: be consistent with srt receiver --- lib/upipe-srt/upipe_srt_sender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 723931a8b..cdab2a9d8 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -617,7 +617,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref uint64_t now = uclock_now(upipe_srt_sender->uclock); uint32_t seqnum = upipe_srt_sender->seqnum++; - seqnum &= (1U << 31) - 1; + seqnum &= ~(1 << 31); memset(buf, 0, SRT_HEADER_SIZE); srt_set_packet_control(buf, false); srt_set_packet_timestamp(buf, (now - upipe_srt_sender->establish_time) / 27); From ca7d29547c4d16cfec925b68fdd2160e9526db26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 15 Dec 2023 13:00:15 +0100 Subject: [PATCH 060/231] rist_rx: add upipe_dump debug --- examples/rist_rx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 4bdb0b517..51a5dbae9 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -28,6 +28,7 @@ #undef NDEBUG #include "upipe/uprobe.h" +#include "upipe/upipe_dump.h" #include "upipe/uprobe_stdio.h" #include "upipe/uprobe_prefix.h" #include "upipe/uprobe_uref_mgr.h" @@ -417,6 +418,8 @@ int main(int argc, char *argv[]) return ret; if (0) { + //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsrc, NULL); + struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, UCLOCK_FREQ, 0); upump_start(u); From 87b5f9d26fd7e54f907fc8b61fc66cc50ae4d35d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 15 Dec 2023 15:51:34 +0100 Subject: [PATCH 061/231] SRT: fix wraparound logic --- lib/upipe-srt/upipe_srt_receiver.c | 10 +++++++--- lib/upipe-srt/upipe_srt_sender.c | 20 ++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 6cc400e1a..4f9ecefa7 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -988,8 +988,11 @@ static bool upipe_srt_receiver_insert_inner(struct upipe *upipe, struct uref *ur return true; } + diff &= ~(1<<31); /* seqnums are 31 bits */ + /* browse the list until we find a seqnum bigger than ours */ - if (diff < 0x8000000) // seqnum > next_seqnum + + if (diff < 1<<30) // make sure seqnum > next_seqnum return false; /* if there's no previous packet we're too late */ @@ -1236,8 +1239,9 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, upipe_srt_receiver->expected_seqnum = seqnum; uint32_t diff = seqnum - upipe_srt_receiver->expected_seqnum; + diff &= ~(1 << 31); // seqnums are 31 bits - if (diff < 0x80000000U) { // seqnum > last seq, insert at the end + if (diff < 1<<30) { // seqnum > last seq, insert at the end /* packet is from the future */ upipe_srt_receiver->buffered++; @@ -1255,7 +1259,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, upipe_srt_receiver->last_nack[seq & 0xffff] = fake_last_nack; } - upipe_srt_receiver->expected_seqnum = seqnum + 1; + upipe_srt_receiver->expected_seqnum = (seqnum + 1) & ~(1 << 31); return; } diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index cdab2a9d8..340fdfdf8 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -228,13 +228,14 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 uref_attr_get_priv(uref, &uref_seqnum); uint32_t diff = uref_seqnum - seq; - if (diff >= pkts) { - /* packet not in range */ - if (diff < 0x80000000) { - /* packet after range */ - break; - } + diff &= ~(1<<31); + + if (diff > (1<<30)) { + /* Look at next packet */ continue; + } else if (diff >= pkts) { + /* packet after range, give up */ + break; } upipe_verbose_va(upipe, "Retransmit %" PRIu64, uref_seqnum); @@ -248,9 +249,12 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 upipe_srt_sender->last_sent = now; upipe_srt_sender_output(upipe_super, uref_dup(uref), NULL); - if (--pkts == 0) + + diff++; + seq += diff; + pkts -= diff; + if (pkts == 0) return; - seq++; } /* XXX: Is it needed? */ From 371b0f976db7ce20b8d1d79da81fb324fc83e3f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 15 Dec 2023 16:07:09 +0100 Subject: [PATCH 062/231] srt: shutdown connection if not data for 10s --- lib/upipe-srt/upipe_srt_handshake.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index ec769ff4b..cc8fb500c 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -67,6 +67,7 @@ struct upipe_srt_handshake { struct upump_mgr *upump_mgr; struct upump *upump_timer; struct upump *upump_timeout; + struct upump *upump_keepalive_timeout; struct uclock *uclock; struct urequest uclock_request; @@ -137,6 +138,7 @@ UPIPE_HELPER_OUTPUT(upipe_srt_handshake, output, flow_def, output_state, request UPIPE_HELPER_UPUMP_MGR(upipe_srt_handshake, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timer, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timeout, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_keepalive_timeout, upump_mgr) UPIPE_HELPER_UCLOCK(upipe_srt_handshake, uclock, uclock_request, NULL, upipe_throw_provide_request, NULL) UPIPE_HELPER_UREF_MGR(upipe_srt_handshake, uref_mgr, uref_mgr_request, @@ -262,13 +264,24 @@ static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_si return uref; } +static void upipe_srt_handshake_keepalive_timeout(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + upipe_err(upipe, "No data in 10s"); + upipe_throw_source_end(upipe); + + upipe_srt_handshake->expect_conclusion = false; +} + static void upipe_srt_handshake_timeout(struct upump *upump) { struct upipe *upipe = upump_get_opaque(upump, struct upipe *); struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_err(upipe, "Connection timed out"); - + upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); upipe_srt_handshake->expect_conclusion = false; } @@ -335,6 +348,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_init_upump_mgr(upipe); upipe_srt_handshake_init_upump_timer(upipe); upipe_srt_handshake_init_upump_timeout(upipe); + upipe_srt_handshake_init_upump_keepalive_timeout(upipe); upipe_srt_handshake_init_uclock(upipe); upipe_srt_handshake_require_uclock(upipe); @@ -510,6 +524,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, case UPIPE_ATTACH_UPUMP_MGR: upipe_srt_handshake_set_upump_timer(upipe, NULL); upipe_srt_handshake_set_upump_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); return upipe_srt_handshake_attach_upump_mgr(upipe); case UPIPE_SET_FLOW_DEF: { @@ -1328,6 +1343,14 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, return; } + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_keepalive_timeout, + upipe, upipe->refcount, + 10*UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_keepalive_timeout(upipe, upump); + if (srt_get_packet_control(buf)) { bool handled = false; struct uref *reply = upipe_srt_handshake_input_control(upipe, buf, size, &handled); @@ -1363,6 +1386,7 @@ static void upipe_srt_handshake_free(struct upipe *upipe) upipe_srt_handshake_clean_output(upipe); upipe_srt_handshake_clean_upump_timer(upipe); upipe_srt_handshake_clean_upump_timeout(upipe); + upipe_srt_handshake_clean_upump_keepalive_timeout(upipe); upipe_srt_handshake_clean_upump_mgr(upipe); upipe_srt_handshake_clean_uclock(upipe); upipe_srt_handshake_clean_ubuf_mgr(upipe); From 1d12c2f735338831f2f0122383601949bb3713a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 10:02:03 +0000 Subject: [PATCH 063/231] srtr: account for RTT when releasing packet --- lib/upipe-srt/upipe_srt_receiver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 4f9ecefa7..972812604 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -562,6 +562,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); uint64_t now = uclock_now(upipe_srt_receiver->uclock); + uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); struct uchain *uchain, *uchain_tmp; ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { @@ -575,7 +576,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) upipe_warn_va(upipe, "Couldn't read cr_sys in %s()", __func__); - if (now - cr_sys <= upipe_srt_receiver->latency) + if (now - cr_sys <= upipe_srt_receiver->latency - rtt) break; upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); From cfab2c951beda82d6e2e18ff7dfc192acd30fb7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 10:02:58 +0000 Subject: [PATCH 064/231] srtr: rename func --- lib/upipe-srt/upipe_srt_receiver.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 972812604..434920306 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -315,7 +315,7 @@ static void upipe_srt_receiver_output_free(struct upipe *upipe) upipe_srt_receiver_output_free_void(upipe); } -static uint64_t _upipe_srt_receiver_get_rtt(struct upipe *upipe) +static uint64_t upipe_srt_receiver_get_rtt(struct upipe *upipe) { struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); @@ -339,7 +339,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uint64_t expected_seq = UINT64_MAX; - uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + uint64_t rtt = upipe_srt_receiver_get_rtt(upipe); uint64_t now = uclock_now(upipe_srt_receiver->uclock); @@ -562,7 +562,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); uint64_t now = uclock_now(upipe_srt_receiver->uclock); - uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + uint64_t rtt = upipe_srt_receiver_get_rtt(upipe); struct uchain *uchain, *uchain_tmp; ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { @@ -620,7 +620,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) static void upipe_srt_receiver_restart_timer(struct upipe *upipe) { struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); - uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + uint64_t rtt = upipe_srt_receiver_get_rtt(upipe); upipe_srt_receiver_set_upump_timer_lost(upipe, NULL); if (upipe_srt_receiver->upump_mgr) { @@ -1252,7 +1252,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, upipe_srt_receiver->last_nack[seqnum & 0xffff] = 0; if (diff != 0) { - uint64_t rtt = _upipe_srt_receiver_get_rtt(upipe); + uint64_t rtt = upipe_srt_receiver_get_rtt(upipe); /* wait a bit to send a NACK, in case of reordering */ uint64_t fake_last_nack = uclock_now(upipe_srt_receiver->uclock) - rtt; for (uint32_t seq = upipe_srt_receiver->expected_seqnum; seq != seqnum; seq++) From f4c9f669f83323e4b28db6a3f58504cc0e341de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 15:12:06 +0100 Subject: [PATCH 065/231] srth: make sure user packets are actually kmrsp type --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index cc8fb500c..9100fc81f 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1174,6 +1174,10 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + uint16_t subtype = srt_get_control_packet_subtype(buf); + if (subtype != SRT_HANDSHAKE_EXT_TYPE_KMRSP) + return NULL; + uint8_t kk = 0; const uint8_t *wrap; uint8_t wrap_len = 0; From 717b14ae594376864b1dddc49d02bbe6be9223f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 15:12:19 +0100 Subject: [PATCH 066/231] srth: handle v4 handshake --- lib/upipe-srt/upipe_srt_handshake.c | 41 ++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 9100fc81f..61abbf689 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1053,8 +1053,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } - if (version != SRT_HANDSHAKE_VERSION - || syn_cookie != upipe_srt_handshake->syn_cookie + if (syn_cookie != upipe_srt_handshake->syn_cookie || dst_socket_id != 0) { upipe_err(upipe, "Malformed conclusion handshake"); upipe_srt_handshake->expect_conclusion = false; @@ -1063,7 +1062,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin /* At least HSREQ is expected */ size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; - if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { + if (version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { upipe_err(upipe, "Malformed conclusion handshake (size)"); upipe_srt_handshake->expect_conclusion = false; return NULL; @@ -1162,6 +1161,39 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); } + if (version == SRT_HANDSHAKE_VERSION_MIN) { + struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 12); + if (!next) + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + else { + uint8_t *out; + int output_size = -1; + if (likely(ubase_check(uref_block_write(next, 0, &output_size, &out)))) { + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); + srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_HSREQ); + srt_set_control_packet_type_specific(out, 0); + + uint8_t *out_ext = &out[SRT_HEADER_SIZE]; + srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, + upipe_srt_handshake->minor, upipe_srt_handshake->patch); + srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + + uref_block_unmap(next, 0); + ulist_init(&uref->uchain); + ulist_add(&uref->uchain, &next->uchain); + } else { + uref_free(next); + } + } + } + upipe_srt_handshake_finalize(upipe); uref_block_unmap(uref, 0); @@ -1364,7 +1396,10 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, } else { uref_free(uref); if (reply) { + struct uchain *next = ulist_peek(&reply->uchain); upipe_srt_handshake_output(&upipe_srt_handshake->upipe, reply, upump_p); + if (next) + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref_from_uchain(next), upump_p); } } } else { From 4c0081a7c3d3852cad823b7184a6e65db9f86261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 15:24:56 +0100 Subject: [PATCH 067/231] rist_tx: srth needs latency --- examples/rist_tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 0f86a7da8..843900f98 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -210,6 +210,8 @@ static int start(void) struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, uprobe_pfx_alloc_va(uprobe_alloc(catch_hs, uprobe_use(logger)), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); + if (!ubase_check(upipe_set_option(upipe_srt_handshake, "latency", latency))) + return EXIT_FAILURE; upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); upipe_mgr_release(upipe_srt_handshake_mgr); From 873677cffcd45c81abfb3e3293fea3c87c1a1d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 15:25:24 +0100 Subject: [PATCH 068/231] srth: fix v4 handshake, encryption not working yet --- lib/upipe-srt/upipe_srt_handshake.c | 37 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 61abbf689..58bd2ff4c 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1103,8 +1103,11 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin size -= ext_len; } - extension = SRT_HANDSHAKE_EXT_HSREQ; - size = SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; + extension = 0; + if (version == SRT_HANDSHAKE_VERSION) { + extension = SRT_HANDSHAKE_EXT_HSREQ; + size = SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; + } if (wrap_len) { size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; extension |= SRT_HANDSHAKE_EXT_KMREQ; @@ -1118,22 +1121,26 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (!uref) return NULL; - srt_set_handshake_extension(out_cif, extension); + if (extension) + srt_set_handshake_extension(out_cif, extension); + else + srt_set_handshake_extension(out_cif, 2 /* SRT_DGRAM */); srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); - ext = srt_get_handshake_extension_buf((uint8_t*)cif); uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); - - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSRSP); - srt_set_handshake_extension_len(out_ext, SRT_HANDSHAKE_HSREQ_SIZE / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, - upipe_srt_handshake->minor, upipe_srt_handshake->patch); - srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - - out_ext += SRT_HANDSHAKE_HSREQ_SIZE; + if (version == SRT_HANDSHAKE_VERSION) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSRSP); + srt_set_handshake_extension_len(out_ext, SRT_HANDSHAKE_HSREQ_SIZE / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, + upipe_srt_handshake->minor, upipe_srt_handshake->patch); + srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + + out_ext += SRT_HANDSHAKE_HSREQ_SIZE; + } else + srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); if (upipe_srt_handshake->stream_id) { srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); From cdfe35348931748836814709b7c2221bfc91b798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 16:35:03 +0100 Subject: [PATCH 069/231] srth: use define --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 58bd2ff4c..6a6a0ee13 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1170,7 +1170,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (version == SRT_HANDSHAKE_VERSION_MIN) { struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 12); + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_HANDSHAKE_HSREQ_SIZE); if (!next) upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); else { From fa95f5609c00dcb7c0df1bee31ee063672922ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Dec 2023 16:35:16 +0100 Subject: [PATCH 070/231] srth: v4 encryption kmreq is sent by sender, not by caller --- lib/upipe-srt/upipe_srt_handshake.c | 96 +++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 6a6a0ee13..82fed6c10 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1193,12 +1193,96 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); uref_block_unmap(next, 0); - ulist_init(&uref->uchain); - ulist_add(&uref->uchain, &next->uchain); + uref->uchain.next = &next->uchain; } else { uref_free(next); } } + +#ifdef UPIPE_HAVE_GCRYPT_H + if (upipe_srt_handshake->password) { + const uint8_t klen = upipe_srt_handshake->sek_len; + uint8_t kk = 1; + size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; + next = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); + if (!next) + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + else { + uint8_t *out; + int output_size = -1; + if (likely(ubase_check(uref_block_write(next, 0, &output_size, &out)))) { + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); + srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_KMREQ); + srt_set_control_packet_type_specific(out, 0); + + uint8_t *out_ext = &out[SRT_HEADER_SIZE]; + + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + // XXX: move to bitstream? + + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + + uint8_t wrap[8+256/8] = {0}; + + + gcry_randomize(upipe_srt_handshake->sek[0], klen, GCRY_STRONG_RANDOM); + gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); + + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + + uint8_t kek[32]; + gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, + strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, + &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); + if (err) { + upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); + return false; + } + + gcry_cipher_hd_t aes; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + return false; + } + + err = gcry_cipher_setkey(aes, kek, klen); + if (err) { + gcry_cipher_close(aes); + upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); + return false; + } + + err = gcry_cipher_encrypt(aes, wrap, wrap_len, upipe_srt_handshake->sek[0], klen); + if (err) { + gcry_cipher_close(aes); + upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); + return false; + } + + gcry_cipher_close(aes); + + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + + uref_block_unmap(next, 0); + uref->uchain.next->next = &next->uchain; + } else { + uref_free(next); + } + } + } +#endif } upipe_srt_handshake_finalize(upipe); @@ -1403,10 +1487,14 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, } else { uref_free(uref); if (reply) { - struct uchain *next = ulist_peek(&reply->uchain); + struct uchain *next = reply->uchain.next; upipe_srt_handshake_output(&upipe_srt_handshake->upipe, reply, upump_p); - if (next) + if (next) { + struct uchain *next2 = next->next; upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref_from_uchain(next), upump_p); + if (next2) + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref_from_uchain(next2), upump_p); + } } } } else { From 0829b93e6f6ebe7321e884de9c2eb80a18feb54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Dec 2023 09:45:25 +0100 Subject: [PATCH 071/231] srth: fix key rotation --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 82fed6c10..3a2a3eb35 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1298,7 +1298,7 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; uint16_t subtype = srt_get_control_packet_subtype(buf); - if (subtype != SRT_HANDSHAKE_EXT_TYPE_KMRSP) + if (subtype != SRT_HANDSHAKE_EXT_TYPE_KMRSP && subtype != SRT_HANDSHAKE_EXT_TYPE_KMREQ) return NULL; uint8_t kk = 0; From b8231d5587171bc4cf24c3d1d8fff2e24f995856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Dec 2023 13:45:18 +0100 Subject: [PATCH 072/231] srtr: handle rtt > latency --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 434920306..6993044e4 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -576,7 +576,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) upipe_warn_va(upipe, "Couldn't read cr_sys in %s()", __func__); - if (now - cr_sys <= upipe_srt_receiver->latency - rtt) + if (rtt < upipe_srt_receiver->latency && now <= cr_sys + upipe_srt_receiver->latency - rtt) break; upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); From 14dc83eb5767fcb744557b8463e931468628ee1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Dec 2023 13:47:12 +0100 Subject: [PATCH 073/231] srtr: fix obd timing XXX: why is it not needed for rist? --- lib/upipe-srt/upipe_srt_receiver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 6993044e4..37abf3db8 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -598,6 +598,8 @@ static void upipe_srt_receiver_timer(struct upump *upump) if (unlikely(!ubase_check(uref_block_size(uref, &size)))) size = 0; upipe_srt_receiver->bytes -= size; + + uref_clock_set_cr_sys(uref, cr_sys + upipe_srt_receiver->latency); upipe_srt_receiver_output(upipe, uref, NULL); // XXX: use timer upump ? static uint64_t old; From 46ab7ec607ce1a28d39f7120eb747872845402c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Dec 2023 15:18:51 +0100 Subject: [PATCH 074/231] Revert "srtr: handle rtt > latency" This reverts commit b8231d5587171bc4cf24c3d1d8fff2e24f995856. --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 37abf3db8..095c0c381 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -576,7 +576,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) upipe_warn_va(upipe, "Couldn't read cr_sys in %s()", __func__); - if (rtt < upipe_srt_receiver->latency && now <= cr_sys + upipe_srt_receiver->latency - rtt) + if (now - cr_sys <= upipe_srt_receiver->latency - rtt) break; upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); From 7e5f5dc79a54812f9dfcafdd765ad2c01df0bfce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Dec 2023 15:22:36 +0100 Subject: [PATCH 075/231] srtr: stats --- include/upipe-srt/upipe_srt_receiver.h | 18 +++++++++++++++++ lib/upipe-srt/upipe_srt_receiver.c | 27 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/upipe-srt/upipe_srt_receiver.h b/include/upipe-srt/upipe_srt_receiver.h index 226e71893..77e490f3c 100644 --- a/include/upipe-srt/upipe_srt_receiver.h +++ b/include/upipe-srt/upipe_srt_receiver.h @@ -39,6 +39,24 @@ extern "C" { #define UPIPE_SRT_RECEIVER_SIGNATURE UBASE_FOURCC('s','r','t','r') #define UPIPE_SRT_RECEIVER_OUTPUT_SIGNATURE UBASE_FOURCC('s','r','r','o') +enum upipe_srt_receiver_command { + UPIPE_SRTR_SENTINEL = UPIPE_CONTROL_LOCAL, + + /** get counters (unsigned *, unsigned *, size_t *, size_t *, size_t *, size_t *, size_t *) */ + UPIPE_SRTR_GET_STATS, +}; + +static inline int upipe_srt_receiver_get_stats(struct upipe *upipe, + unsigned *expected_seqnum, unsigned *last_output_seqnum, + size_t *buffered, size_t *nacks, size_t *repaired, + size_t *lost, size_t *duplicates) +{ + return upipe_control(upipe, UPIPE_SRTR_GET_STATS, + UPIPE_SRT_RECEIVER_SIGNATURE, expected_seqnum, last_output_seqnum, + buffered, nacks, repaired, lost, duplicates); +} + + /** @This returns the management structure for all srt receiver sources. * * @return pointer to manager diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 095c0c381..445606025 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -955,6 +955,33 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, return UBASE_ERR_NONE; } + case UPIPE_SRTR_GET_STATS: { + UBASE_SIGNATURE_CHECK(args, UPIPE_SRT_RECEIVER_SIGNATURE) + unsigned *expected_seqnum = va_arg(args, unsigned*); + unsigned *last_output_seqnum = va_arg(args, unsigned*); + size_t *buffered = va_arg(args, size_t*); + size_t *nacks = va_arg(args, size_t*); + size_t *repaired = va_arg(args, size_t*); + size_t *loss = va_arg(args, size_t*); + size_t *dups = va_arg(args, size_t*); + + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + *buffered = upipe_srt_receiver->buffered; + *expected_seqnum = upipe_srt_receiver->expected_seqnum; + *last_output_seqnum = upipe_srt_receiver->last_output_seqnum; + *nacks = upipe_srt_receiver->nacks; + *repaired = upipe_srt_receiver->repaired; + *loss = upipe_srt_receiver->loss; + *dups = upipe_srt_receiver->dups; + + upipe_srt_receiver->nacks = 0; + upipe_srt_receiver->repaired = 0; + upipe_srt_receiver->loss = 0; + upipe_srt_receiver->dups = 0; + + return UBASE_ERR_NONE; + } + default: return UBASE_ERR_UNHANDLED; } From 3f1784414237a8a9cafdf409989a301c2d4e9424 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 2 Jan 2024 18:15:01 +0000 Subject: [PATCH 076/231] upipe_srt_receiver: Reset buffered counter correctly during buffer empty --- lib/upipe-srt/upipe_srt_receiver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 445606025..bf488e0e0 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -856,6 +856,7 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo upipe_warn(upipe, "Emptying buffer"); upipe_srt_receiver->expected_seqnum = UINT64_MAX; upipe_srt_receiver->last_output_seqnum = UINT64_MAX; + upipe_srt_receiver->buffered = 0; struct uchain *uchain, *uchain_tmp; ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { ulist_delete(uchain); From 1f0d950e06c1295ae25504c62121df334570622d Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 2 Jan 2024 18:15:30 +0000 Subject: [PATCH 077/231] upipe_srt_receiver: Free urefs during buffer empty --- lib/upipe-srt/upipe_srt_receiver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index bf488e0e0..8f96588b3 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -859,7 +859,9 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo upipe_srt_receiver->buffered = 0; struct uchain *uchain, *uchain_tmp; ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { + struct uref *uref = uref_from_uchain(uchain); ulist_delete(uchain); + uref_free(uref); } if (flow_def == NULL) From e3f96fad63cdf6e3f299dea7f8c8e885409ee038 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 2 Jan 2024 18:33:46 +0000 Subject: [PATCH 078/231] upipe_srt_receiver: Set acks to NULL after freeing --- lib/upipe-srt/upipe_srt_receiver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 8f96588b3..7e19cdfa0 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1318,6 +1318,7 @@ static void upipe_srt_receiver_free(struct upipe *upipe) upipe_throw_dead(upipe); free(upipe_srt_receiver->acks); + upipe_srt_receiver->acks = NULL; upipe_srt_receiver_clean_output(upipe); upipe_srt_receiver_clean_upump_timer(upipe); From 11247dad6562244fbd36844ade2423acab91cc91 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 2 Jan 2024 18:35:55 +0000 Subject: [PATCH 079/231] upipe_srt_receiver: Empty buffer when pipe closes --- lib/upipe-srt/upipe_srt_receiver.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 7e19cdfa0..35d30fdc4 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -842,13 +842,7 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma return UBASE_ERR_NONE; } -/** @internal @This sets the input flow definition. - * - * @param upipe description structure of the pipe - * @param flow_def flow definition packet - * @return an error code - */ -static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flow_def) +static void upipe_srt_receiver_empty_buffer(struct upipe *upipe) { struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); @@ -863,6 +857,20 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo ulist_delete(uchain); uref_free(uref); } +} + +/** @internal @This sets the input flow definition. + * + * @param upipe description structure of the pipe + * @param flow_def flow definition packet + * @return an error code + */ +static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + + /* FIXME: Don't do this on a new key flow def */ + upipe_srt_receiver_empty_buffer(upipe); if (flow_def == NULL) return UBASE_ERR_INVALID; @@ -1330,6 +1338,7 @@ static void upipe_srt_receiver_free(struct upipe *upipe) upipe_srt_receiver_clean_urefcount(upipe); upipe_srt_receiver_clean_urefcount_real(upipe); upipe_srt_receiver_clean_sub_outputs(upipe); + upipe_srt_receiver_empty_buffer(upipe); upipe_srt_receiver_free_void(upipe); } From 56f6387aa372244b33a61a9a3bfba52c744b7bbb Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 2 Jan 2024 18:50:15 +0000 Subject: [PATCH 080/231] rist_rx: Port signal handling code from rist_tx --- examples/rist_rx.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 51a5dbae9..430b2d746 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -273,8 +273,10 @@ static int start(void) static void stop(struct upump *upump) { - upump_stop(upump); - upump_free(upump); + if (upump) { + upump_stop(upump); + upump_free(upump); + } upipe_release(upipe_srtr_sub); upipe_release(upipe_udpsrc); @@ -285,6 +287,18 @@ static void stop(struct upump *upump) } } +static void sig_cb(struct upump *upump) +{ + static int done = false; + + if (done) + abort(); + done = true; + + restart = false; + stop(NULL); +} + static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { @@ -425,11 +439,17 @@ int main(int argc, char *argv[]) upump_start(u); } + struct upump *sigint_pump = + upump_alloc_signal(upump_mgr, sig_cb, + (void *)SIGINT, NULL, SIGINT); + upump_set_status(sigint_pump, false); + upump_start(sigint_pump); + /* fire loop ! */ upump_mgr_run(upump_mgr, NULL); - /* should never be here for the moment. todo: sighandler. - * release everything */ + upump_free(sigint_pump); + uprobe_clean(&uprobe_srt); uprobe_clean(&uprobe_udp); uprobe_release(logger); From 349acc4494325ad0d736d78c37fa22e0656f74a5 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 3 Jan 2024 17:55:33 +0000 Subject: [PATCH 081/231] upipe_srt_receiver: Don't empty buffer during a key rotation --- lib/upipe-srt/upipe_srt_receiver.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 35d30fdc4..8ca2f2b8e 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -869,9 +869,6 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo { struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); - /* FIXME: Don't do this on a new key flow def */ - upipe_srt_receiver_empty_buffer(upipe); - if (flow_def == NULL) return UBASE_ERR_INVALID; @@ -884,8 +881,16 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo } uint64_t id; - if (ubase_check(uref_flow_get_id(flow_def, &id))) + if (ubase_check(uref_flow_get_id(flow_def, &id))) { + if (upipe_srt_receiver->socket_id != id) + upipe_srt_receiver_empty_buffer(upipe); + upipe_srt_receiver->socket_id = id; + } + else { + /* XXX: Is this reachable in reality? */ + upipe_srt_receiver_empty_buffer(upipe); + } struct udict_opaque opaque; if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) { From e963d855dd77ce11d2e8ffd98f728826bb68db58 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 16 Jan 2024 13:04:12 +0000 Subject: [PATCH 082/231] examples: Support source filtering in srt listener mode --- examples/rist_rx.c | 2 +- examples/rist_tx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 430b2d746..bd0c05e43 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -201,7 +201,7 @@ static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) static int start(void) { - bool listener = srcpath && *srcpath == '@'; + bool listener = srcpath && strchr(srcpath, '@'); struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); upipe_mgr_release(upipe_udpsrc_mgr); diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 843900f98..f431a1578 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -181,7 +181,7 @@ static int start(void) static unsigned z = 0; z++; - bool listener = dirpath && *dirpath == '@'; + bool listener = dirpath && strchr(dirpath, '@'); /* rtp source */ struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); From 3d5b649a62e337728a5b31fda2467dd5a9580971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 18 Jan 2024 09:44:48 +0100 Subject: [PATCH 083/231] srt receiver: fix heap overflow i++ is done after the whole loop, so the i != max check wasn't being done at the right time --- lib/upipe-srt/upipe_srt_receiver.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 8ca2f2b8e..735827c76 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1096,13 +1096,13 @@ static uint64_t upipe_srt_receiver_ackack(struct upipe *upipe, uint32_t ack_num, struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); const size_t n = upipe_srt_receiver->n_acks; - const size_t ridx = upipe_srt_receiver->ack_ridx;; + const size_t ridx = upipe_srt_receiver->ack_ridx; //upipe_verbose_va(upipe,"%s(%u), start at %zu", __func__, ack_num, ridx); size_t max = (ridx > 0) ? (ridx - 1) : (n - 1); // end of loop - for (size_t i = ridx; ; i++) { + for (size_t i = ridx; i != max; i = (i + 1) % n) { uint32_t a = upipe_srt_receiver->acks[i].ack_num; if (upipe_srt_receiver->acks[i].timestamp == UINT64_MAX) { // already acked @@ -1120,10 +1120,6 @@ static uint64_t upipe_srt_receiver_ackack(struct upipe *upipe, uint32_t ack_num, upipe_srt_receiver->ack_ridx = (i+1) % n; // advance return rtt; } - - i %= n; - if (i == max) - break; } //upipe_verbose_va(upipe, "%d not found", ack_num); From 1da2aadde3786d04468f2736a824859d099bff9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 18 Jan 2024 10:52:49 +0100 Subject: [PATCH 084/231] srt handshake: prepare for even key encryption --- lib/upipe-srt/upipe_srt_handshake.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 3a2a3eb35..f9586d1a0 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -896,10 +896,13 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin size_t size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; - const uint8_t klen = upipe_srt_handshake->sek_len; #ifdef UPIPE_HAVE_GCRYPT_H + const uint8_t klen = upipe_srt_handshake->sek_len; + // XXX: move to bitstream? + uint8_t kk = 1; // 3 + size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; if (upipe_srt_handshake->password) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + (8+klen); + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; extension |= SRT_HANDSHAKE_EXT_KMREQ; } #endif @@ -950,8 +953,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - // XXX: move to bitstream? - uint8_t kk = 1; out_ext[0] = 0x12; // S V PT out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign srt_km_set_kk(out_ext, kk); @@ -961,9 +962,8 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint8_t wrap[8+256/8] = {0}; - size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; - gcry_randomize(upipe_srt_handshake->sek[0], klen, GCRY_STRONG_RANDOM); + gcry_randomize(upipe_srt_handshake->sek[1], klen, GCRY_STRONG_RANDOM); gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); @@ -992,7 +992,10 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return false; } - err = gcry_cipher_encrypt(aes, wrap, wrap_len, upipe_srt_handshake->sek[0], klen); + uint8_t clear_wrap[2*256/8]; + memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); + memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); + err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); if (err) { gcry_cipher_close(aes); upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); From a48190933840a81b011db8289130df25d20b9369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 18 Jan 2024 17:07:26 +0100 Subject: [PATCH 085/231] srt sender: only set isn if unset --- lib/upipe-srt/upipe_srt_sender.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 340fdfdf8..e9de52599 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -462,6 +462,7 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref uint64_t isn; if (ubase_check(uref_pic_get_number(flow_def, &isn))) + if (!upipe_srt_sender->seqnum) upipe_srt_sender->seqnum = isn; struct udict_opaque opaque; From 6470896254727ad0c50ef2aed210855481787e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 19 Jan 2024 11:23:00 +0100 Subject: [PATCH 086/231] srt: key rotation --- examples/rist_tx.c | 22 ++- lib/upipe-srt/upipe_srt_handshake.c | 218 ++++++++++++++++------------ lib/upipe-srt/upipe_srt_sender.c | 33 ++++- 3 files changed, 175 insertions(+), 98 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index f431a1578..7793a4133 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -85,6 +85,8 @@ static struct upipe *upipe_udpsrc; static struct upipe *upipe_srt_sender; static struct upipe *upipe_srt_sender_sub; +static struct upipe *upipe_srt_handshake; + static struct upump_mgr *upump_mgr; static struct uref_mgr *uref_mgr; @@ -207,7 +209,7 @@ static int start(void) upipe_attach_uclock(upipe_udpsrc_srt); struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc_srt); - struct upipe *upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, + upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, uprobe_pfx_alloc_va(uprobe_alloc(catch_hs, uprobe_use(logger)), loglevel, "srt handshake %u", z)); upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); if (!ubase_check(upipe_set_option(upipe_srt_handshake, "latency", latency))) @@ -263,6 +265,16 @@ static int start(void) return 0; } +static void kmrefresh(struct upump *upump) +{ + if (upipe_srt_handshake) + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + else { + upump_stop(upump); + upump_free(upump); + } +} + static void stop(struct upump *upump) { if (upump) { @@ -275,6 +287,8 @@ static void stop(struct upump *upump) upipe_release(upipe_udpsrc); upipe_udpsrc = NULL; + upipe_srt_handshake = NULL; + if (restart) start(); } @@ -359,6 +373,12 @@ int main(int argc, char *argv[]) if (ret) return ret; + if (1) { + struct upump *u = upump_alloc_timer(upump_mgr, kmrefresh, NULL, + NULL, 5*UCLOCK_FREQ, 5*UCLOCK_FREQ); + upump_start(u); + } + if (0) { restart = false; //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f9586d1a0..59168de0c 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -110,6 +110,7 @@ struct upipe_srt_handshake { uint8_t salt[16]; uint8_t sek[2][32]; uint8_t sek_len; + bool update_even; char *password; @@ -337,6 +338,10 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_free_void(upipe); return NULL; } + + gcry_randomize(upipe_srt_handshake->sek[0], 32, GCRY_STRONG_RANDOM); + gcry_randomize(upipe_srt_handshake->sek[1], 32, GCRY_STRONG_RANDOM); + gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); #endif upipe_srt_handshake_init_urefcount(upipe); @@ -374,6 +379,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->patch = 0; upipe_srt_handshake->sek_len = 0; + upipe_srt_handshake->update_even = false; upipe_srt_handshake->password = NULL; upipe_throw_ready(upipe); @@ -413,7 +419,7 @@ static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_form return UBASE_ERR_NONE; } - if (upipe_srt_handshake->upump_mgr && !upipe_srt_handshake->upump_timer && !upipe_srt_handshake->listener) { + if (upipe_srt_handshake->upump_mgr && !upipe_srt_handshake->upump_keepalive_timeout && !upipe_srt_handshake->upump_timer && !upipe_srt_handshake->listener) { upipe_srt_handshake->socket_id = mrand48(); upipe_srt_handshake->syn_cookie = 0; struct upump *upump = @@ -507,6 +513,11 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio return UBASE_ERR_INVALID; } +#ifdef UPIPE_HAVE_GCRYPT_H +static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t timestamp); +#endif +static void upipe_srt_handshake_finalize(struct upipe *upipe); + /** @internal @This processes control commands on a SRT handshake pipe. * * @param upipe description structure of the pipe @@ -564,6 +575,21 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, upipe_err_va(upipe, "Invalid key length %d, using 128 bits", 8*upipe_srt_handshake->sek_len); upipe_srt_handshake->sek_len = 128/8; } + if (upipe_srt_handshake->upump_keepalive_timeout) { +#ifdef UPIPE_HAVE_GCRYPT_H + // KM refresh + gcry_randomize(upipe_srt_handshake->sek[!upipe_srt_handshake->update_even], upipe_srt_handshake->sek_len, GCRY_STRONG_RANDOM); + upipe_srt_handshake->update_even = !upipe_srt_handshake->update_even; + + uint64_t now = uclock_now(upipe_srt_handshake->uclock); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + struct uref *kmreq = upipe_srt_handshake_make_kmreq(upipe, timestamp); + if (kmreq) { + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, kmreq, NULL); + upipe_srt_handshake_finalize(upipe); + } +#endif + } } else { upipe_srt_handshake->password = NULL; upipe_srt_handshake->sek_len = 0; @@ -787,6 +813,98 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * #endif } +#ifdef UPIPE_HAVE_GCRYPT_H +static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t timestamp) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + const uint8_t klen = upipe_srt_handshake->sek_len; + const uint8_t kk = 3; + size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; + struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); + if (!next) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return NULL; + } + + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(next, 0, &output_size, &out)))) { + goto error; + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); + srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_KMREQ); + srt_set_control_packet_type_specific(out, 0); + + uint8_t *out_ext = &out[SRT_HEADER_SIZE]; + + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + // XXX: move to bitstream? + + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + + uint8_t wrap[8+256/8] = {0}; + + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + + uint8_t kek[32]; + gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, + strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, + &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); + if (err) { + upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); + goto error; + } + + gcry_cipher_hd_t aes; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + goto error; + } + + err = gcry_cipher_setkey(aes, kek, klen); + if (err) { + upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); + goto aes_error; + } + + uint8_t clear_wrap[2*256/8]; + memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); + memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); + err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); + if (err) { + upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); + goto aes_error; + } + + gcry_cipher_close(aes); + + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + + uref_block_unmap(next, 0); + + return next; + +aes_error: + gcry_cipher_close(aes); +error: + uref_free(next); + return NULL; +} +#endif + static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -899,7 +1017,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin #ifdef UPIPE_HAVE_GCRYPT_H const uint8_t klen = upipe_srt_handshake->sek_len; // XXX: move to bitstream? - uint8_t kk = 1; // 3 + const uint8_t kk = 3; size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; if (upipe_srt_handshake->password) { size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; @@ -962,10 +1080,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint8_t wrap[8+256/8] = {0}; - gcry_randomize(upipe_srt_handshake->sek[0], klen, GCRY_STRONG_RANDOM); - gcry_randomize(upipe_srt_handshake->sek[1], klen, GCRY_STRONG_RANDOM); - gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); @@ -1204,86 +1318,9 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin #ifdef UPIPE_HAVE_GCRYPT_H if (upipe_srt_handshake->password) { - const uint8_t klen = upipe_srt_handshake->sek_len; - uint8_t kk = 1; - size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; - next = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); - if (!next) - upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); - else { - uint8_t *out; - int output_size = -1; - if (likely(ubase_check(uref_block_write(next, 0, &output_size, &out)))) { - srt_set_packet_control(out, true); - srt_set_packet_timestamp(out, timestamp); - srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); - - srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); - srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_KMREQ); - srt_set_control_packet_type_specific(out, 0); - - uint8_t *out_ext = &out[SRT_HEADER_SIZE]; - - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - // XXX: move to bitstream? - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - - uint8_t wrap[8+256/8] = {0}; - - - gcry_randomize(upipe_srt_handshake->sek[0], klen, GCRY_STRONG_RANDOM); - gcry_randomize(upipe_srt_handshake->salt, 16, GCRY_STRONG_RANDOM); - - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - - uint8_t kek[32]; - gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, - strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, - &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); - if (err) { - upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); - return false; - } - - gcry_cipher_hd_t aes; - err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); - if (err) { - upipe_err_va(upipe, "Cipher open failed (0x%x)", err); - return false; - } - - err = gcry_cipher_setkey(aes, kek, klen); - if (err) { - gcry_cipher_close(aes); - upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); - return false; - } - - err = gcry_cipher_encrypt(aes, wrap, wrap_len, upipe_srt_handshake->sek[0], klen); - if (err) { - gcry_cipher_close(aes); - upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); - return false; - } - - gcry_cipher_close(aes); - - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); - - uref_block_unmap(next, 0); - uref->uchain.next->next = &next->uchain; - } else { - uref_free(next); - } - } + next = upipe_srt_handshake_make_kmreq(upipe, timestamp); + if (next) + uref->uchain.next->next = &next->uchain; } #endif } @@ -1312,10 +1349,13 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u size -= SRT_HEADER_SIZE; if (!srt_check_km(buf, size) || !upipe_srt_handshake_parse_kmreq(upipe, buf, &kk, &wrap, &wrap_len)) - if (!upipe_srt_handshake_parse_kmreq(upipe, cif, &kk, &wrap, &wrap_len)) { - upipe_err_va(upipe, "parse failed"); + if (!upipe_srt_handshake_parse_kmreq(upipe, cif, &kk, &wrap, &wrap_len)) { + upipe_err_va(upipe, "parse failed"); + return NULL; + } + + if (subtype == SRT_HANDSHAKE_EXT_TYPE_KMRSP) return NULL; - } struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index e9de52599..a29bb40b7 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -102,7 +102,9 @@ struct upipe_srt_sender { uint8_t salt[16]; uint8_t sek[2][32]; - uint8_t sek_len; + uint8_t sek_len[2]; + + int even_key; uint64_t last_sent; @@ -476,16 +478,28 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) { if (opaque.size > sizeof(upipe_srt_sender->sek[0])) opaque.size = sizeof(upipe_srt_sender->sek[0]); - upipe_srt_sender->sek_len = opaque.size; + upipe_srt_sender->sek_len[0] = opaque.size; memcpy(upipe_srt_sender->sek[0], opaque.v, opaque.size); } if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.odd_key"))) { if (opaque.size > sizeof(upipe_srt_sender->sek[1])) opaque.size = sizeof(upipe_srt_sender->sek[1]); - upipe_srt_sender->sek_len = opaque.size; + upipe_srt_sender->sek_len[1] = opaque.size; memcpy(upipe_srt_sender->sek[1], opaque.v, opaque.size); } + + int even_key = !upipe_srt_sender->even_key; // switch key + upipe_srt_sender->even_key = even_key; + if (!upipe_srt_sender->sek_len[even_key] && upipe_srt_sender->sek_len[!even_key]) { + upipe_err_va(upipe, "Couldn't switch encryption keys: %s key is absent", + even_key ? "even" : "odd"); + upipe_srt_sender->even_key = !even_key; + } else if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { + upipe_dbg_va(upipe, "Switching to %s key", even_key ? "even" : "odd"); + } else { + upipe_dbg(upipe, "Encryption disabled"); + } #endif return uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF); @@ -572,7 +586,9 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->seqnum = 0; upipe_srt_sender->syn_cookie = 1; - upipe_srt_sender->sek_len = 0; + upipe_srt_sender->sek_len[0] = 0; + upipe_srt_sender->sek_len[1] = 0; + upipe_srt_sender->even_key = false; upipe_srt_sender->last_sent = 0; @@ -634,14 +650,15 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref srt_set_data_packet_retransmit(buf, false); #ifdef UPIPE_HAVE_GCRYPT_H - if (upipe_srt_sender->sek_len) { + int key = !upipe_srt_sender->even_key; + if (upipe_srt_sender->sek_len[key]) { // uint8_t *data; int s = -1; if (ubase_check(uref_block_write(uref, 0, &s, &data))) { const uint8_t *salt = upipe_srt_sender->salt; - const uint8_t *sek = upipe_srt_sender->sek[0]; - int key_len = upipe_srt_sender->sek_len; + const uint8_t *sek = upipe_srt_sender->sek[key]; + int key_len = upipe_srt_sender->sek_len[key]; uint8_t iv[16]; memset(&iv, 0, 16); @@ -693,7 +710,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref } // - srt_set_data_packet_encryption(buf, SRT_DATA_ENCRYPTION_EVEN); + srt_set_data_packet_encryption(buf, key ? SRT_DATA_ENCRYPTION_ODD : SRT_DATA_ENCRYPTION_EVEN); } else #endif srt_set_data_packet_encryption(buf, SRT_DATA_ENCRYPTION_CLEAR); From 4426e5f4c3efef688e5bc9c82b45907fc6691ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 19 Jan 2024 14:54:34 +0100 Subject: [PATCH 087/231] SRT: send KMREQ every second if we do not get a KMRSP --- lib/upipe-srt/upipe_srt_handshake.c | 59 +++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 59168de0c..61efd1b96 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -68,6 +68,7 @@ struct upipe_srt_handshake { struct upump *upump_timer; struct upump *upump_timeout; struct upump *upump_keepalive_timeout; + struct upump *upump_kmreq; struct uclock *uclock; struct urequest uclock_request; @@ -112,6 +113,8 @@ struct upipe_srt_handshake { uint8_t sek_len; bool update_even; + struct uref *kmreq; + char *password; struct sockaddr_storage addr; @@ -140,6 +143,7 @@ UPIPE_HELPER_UPUMP_MGR(upipe_srt_handshake, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timer, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timeout, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_keepalive_timeout, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_kmreq, upump_mgr) UPIPE_HELPER_UCLOCK(upipe_srt_handshake, uclock, uclock_request, NULL, upipe_throw_provide_request, NULL) UPIPE_HELPER_UREF_MGR(upipe_srt_handshake, uref_mgr, uref_mgr_request, @@ -265,6 +269,31 @@ static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_si return uref; } +static void upipe_srt_handshake_kmreq(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + + struct uref *kmreq = upipe_srt_handshake->kmreq; + + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(kmreq, 0, &output_size, &out)))) { + return; + } + + uint64_t now = uclock_now(upipe_srt_handshake->uclock); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + + srt_set_packet_timestamp(out, timestamp); + + uref_block_unmap(kmreq, 0); + + upipe_dbg(upipe, "Sending key update"); + + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref_dup(kmreq), NULL); +} + static void upipe_srt_handshake_keepalive_timeout(struct upump *upump) { struct upipe *upipe = upump_get_opaque(upump, struct upipe *); @@ -354,6 +383,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_init_upump_timer(upipe); upipe_srt_handshake_init_upump_timeout(upipe); upipe_srt_handshake_init_upump_keepalive_timeout(upipe); + upipe_srt_handshake_init_upump_kmreq(upipe); upipe_srt_handshake_init_uclock(upipe); upipe_srt_handshake_require_uclock(upipe); @@ -380,6 +410,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->sek_len = 0; upipe_srt_handshake->update_even = false; + upipe_srt_handshake->kmreq = NULL; upipe_srt_handshake->password = NULL; upipe_throw_ready(upipe); @@ -536,6 +567,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, upipe_srt_handshake_set_upump_timer(upipe, NULL); upipe_srt_handshake_set_upump_timeout(upipe, NULL); upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_kmreq(upipe, NULL); return upipe_srt_handshake_attach_upump_mgr(upipe); case UPIPE_SET_FLOW_DEF: { @@ -575,7 +607,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, upipe_err_va(upipe, "Invalid key length %d, using 128 bits", 8*upipe_srt_handshake->sek_len); upipe_srt_handshake->sek_len = 128/8; } - if (upipe_srt_handshake->upump_keepalive_timeout) { + if (upipe_srt_handshake->upump_keepalive_timeout) { /* already started */ #ifdef UPIPE_HAVE_GCRYPT_H // KM refresh gcry_randomize(upipe_srt_handshake->sek[!upipe_srt_handshake->update_even], upipe_srt_handshake->sek_len, GCRY_STRONG_RANDOM); @@ -585,8 +617,16 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; struct uref *kmreq = upipe_srt_handshake_make_kmreq(upipe, timestamp); if (kmreq) { - upipe_srt_handshake_output(&upipe_srt_handshake->upipe, kmreq, NULL); - upipe_srt_handshake_finalize(upipe); + if (upipe_srt_handshake->kmreq) + uref_free(upipe_srt_handshake->kmreq); + upipe_srt_handshake->kmreq = kmreq; + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_kmreq, + upipe, upipe->refcount, + 0, UCLOCK_FREQ); // every second + upump_start(upump); + upipe_srt_handshake_set_upump_kmreq(upipe, upump); } #endif } @@ -1354,8 +1394,15 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u return NULL; } - if (subtype == SRT_HANDSHAKE_EXT_TYPE_KMRSP) + if (subtype == SRT_HANDSHAKE_EXT_TYPE_KMRSP) { + if (upipe_srt_handshake->kmreq) { + upipe_srt_handshake_set_upump_kmreq(upipe, NULL); + uref_free(upipe_srt_handshake->kmreq); + upipe_srt_handshake->kmreq = NULL; + } + upipe_srt_handshake_finalize(upipe); return NULL; + } struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); @@ -1560,10 +1607,14 @@ static void upipe_srt_handshake_free(struct upipe *upipe) free(upipe_srt_handshake->password); free(upipe_srt_handshake->stream_id); + if (upipe_srt_handshake->kmreq) + uref_free(upipe_srt_handshake->kmreq); + upipe_srt_handshake_clean_output(upipe); upipe_srt_handshake_clean_upump_timer(upipe); upipe_srt_handshake_clean_upump_timeout(upipe); upipe_srt_handshake_clean_upump_keepalive_timeout(upipe); + upipe_srt_handshake_clean_upump_kmreq(upipe); upipe_srt_handshake_clean_upump_mgr(upipe); upipe_srt_handshake_clean_uclock(upipe); upipe_srt_handshake_clean_ubuf_mgr(upipe); From f7628d018603c40d9241ebe71b4d2d8614e7f64c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 19 Jan 2024 16:29:25 +0100 Subject: [PATCH 088/231] srth: ignore handshake when already connected --- lib/upipe-srt/upipe_srt_handshake.c | 59 +++++++++++++++++++---------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 61efd1b96..781c84902 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -715,6 +715,14 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) upipe_srt_handshake->expect_conclusion = false; upipe_srt_handshake_set_upump_timeout(upipe, NULL); + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_keepalive_timeout, + upipe, upipe->refcount, + 10*UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_keepalive_timeout(upipe, upump); + struct uref *flow_def; if (ubase_check(upipe_srt_handshake_get_flow_def(upipe, &flow_def))) { flow_def = uref_dup(flow_def); @@ -964,17 +972,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint32_t syn_cookie = srt_get_handshake_syn_cookie(cif); uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); - if (!upipe_srt_handshake->upump_timeout) { - /* connection has to succeed within 3 seconds */ - struct upump *upump = - upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_timeout, - upipe, upipe->refcount, - 3 * UCLOCK_FREQ, 0); - upump_start(upump); - upipe_srt_handshake_set_upump_timeout(upipe, upump); - } - if (!upipe_srt_handshake->listener) { if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); @@ -1031,6 +1028,11 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin /* */ + if (upipe_srt_handshake->upump_keepalive_timeout) { + upipe_dbg(upipe, "Ignore handshake, already connected"); + return NULL; + } + if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); return NULL; @@ -1042,6 +1044,17 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } + if (!upipe_srt_handshake->upump_timeout) { + /* connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_timeout(upipe, upump); + } + upipe_srt_handshake->mtu = srt_get_handshake_mtu(cif); upipe_srt_handshake->mfw = srt_get_handshake_mfw(cif); upipe_srt_handshake->isn = srt_get_handshake_isn(cif); @@ -1169,6 +1182,11 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } if (!upipe_srt_handshake->expect_conclusion) { + if (upipe_srt_handshake->upump_keepalive_timeout) { + upipe_dbg(upipe, "Ignore handshake, already connected"); + return NULL; + } + if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); return NULL; @@ -1181,6 +1199,17 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } + if (!upipe_srt_handshake->upump_timeout) { + /* connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_timeout(upipe, upump); + } + upipe_srt_handshake->establish_time = now; timestamp = 0; upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); @@ -1560,14 +1589,6 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, return; } - struct upump *upump = - upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_keepalive_timeout, - upipe, upipe->refcount, - 10*UCLOCK_FREQ, 0); - upump_start(upump); - upipe_srt_handshake_set_upump_keepalive_timeout(upipe, upump); - if (srt_get_packet_control(buf)) { bool handled = false; struct uref *reply = upipe_srt_handshake_input_control(upipe, buf, size, &handled); From dfa8a31adfc17b7abb68184707be7108df45e552 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sun, 28 Jan 2024 17:10:28 +0000 Subject: [PATCH 089/231] srt: Use the correct timeout for handshake timeout --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 781c84902..8435e423d 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -311,7 +311,7 @@ static void upipe_srt_handshake_timeout(struct upump *upump) struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_err(upipe, "Connection timed out"); - upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_timeout(upipe, NULL); upipe_srt_handshake->expect_conclusion = false; } From f0a33bdc38eef25ed9e5773d794b2ec58fccb707 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sun, 28 Jan 2024 17:11:37 +0000 Subject: [PATCH 090/231] srt: Clarify the name of the handshake timeout --- lib/upipe-srt/upipe_srt_handshake.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 8435e423d..7d9b214dc 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -66,7 +66,7 @@ struct upipe_srt_handshake { struct upump_mgr *upump_mgr; struct upump *upump_timer; - struct upump *upump_timeout; + struct upump *upump_handshake_timeout; struct upump *upump_keepalive_timeout; struct upump *upump_kmreq; struct uclock *uclock; @@ -141,7 +141,7 @@ UPIPE_HELPER_VOID(upipe_srt_handshake) UPIPE_HELPER_OUTPUT(upipe_srt_handshake, output, flow_def, output_state, request_list) UPIPE_HELPER_UPUMP_MGR(upipe_srt_handshake, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timer, upump_mgr) -UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timeout, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_handshake_timeout, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_keepalive_timeout, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_kmreq, upump_mgr) UPIPE_HELPER_UCLOCK(upipe_srt_handshake, uclock, uclock_request, NULL, upipe_throw_provide_request, NULL) @@ -311,7 +311,7 @@ static void upipe_srt_handshake_timeout(struct upump *upump) struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_err(upipe, "Connection timed out"); - upipe_srt_handshake_set_upump_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); upipe_srt_handshake->expect_conclusion = false; } @@ -381,7 +381,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_init_upump_mgr(upipe); upipe_srt_handshake_init_upump_timer(upipe); - upipe_srt_handshake_init_upump_timeout(upipe); + upipe_srt_handshake_init_upump_handshake_timeout(upipe); upipe_srt_handshake_init_upump_keepalive_timeout(upipe); upipe_srt_handshake_init_upump_kmreq(upipe); upipe_srt_handshake_init_uclock(upipe); @@ -565,7 +565,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, switch (command) { case UPIPE_ATTACH_UPUMP_MGR: upipe_srt_handshake_set_upump_timer(upipe, NULL); - upipe_srt_handshake_set_upump_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); upipe_srt_handshake_set_upump_kmreq(upipe, NULL); return upipe_srt_handshake_attach_upump_mgr(upipe); @@ -713,7 +713,7 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_srt_handshake->expect_conclusion = false; - upipe_srt_handshake_set_upump_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); struct upump *upump = upump_alloc_timer(upipe_srt_handshake->upump_mgr, @@ -1044,7 +1044,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } - if (!upipe_srt_handshake->upump_timeout) { + if (!upipe_srt_handshake->upump_handshake_timeout) { /* connection has to succeed within 3 seconds */ struct upump *upump = upump_alloc_timer(upipe_srt_handshake->upump_mgr, @@ -1052,7 +1052,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe, upipe->refcount, 3 * UCLOCK_FREQ, 0); upump_start(upump); - upipe_srt_handshake_set_upump_timeout(upipe, upump); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); } upipe_srt_handshake->mtu = srt_get_handshake_mtu(cif); @@ -1199,7 +1199,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } - if (!upipe_srt_handshake->upump_timeout) { + if (!upipe_srt_handshake->upump_handshake_timeout) { /* connection has to succeed within 3 seconds */ struct upump *upump = upump_alloc_timer(upipe_srt_handshake->upump_mgr, @@ -1207,7 +1207,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe, upipe->refcount, 3 * UCLOCK_FREQ, 0); upump_start(upump); - upipe_srt_handshake_set_upump_timeout(upipe, upump); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); } upipe_srt_handshake->establish_time = now; @@ -1633,7 +1633,7 @@ static void upipe_srt_handshake_free(struct upipe *upipe) upipe_srt_handshake_clean_output(upipe); upipe_srt_handshake_clean_upump_timer(upipe); - upipe_srt_handshake_clean_upump_timeout(upipe); + upipe_srt_handshake_clean_upump_handshake_timeout(upipe); upipe_srt_handshake_clean_upump_keepalive_timeout(upipe); upipe_srt_handshake_clean_upump_kmreq(upipe); upipe_srt_handshake_clean_upump_mgr(upipe); From 8f237b702d44d756ea78bde8698e207ea835cd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 1 Feb 2024 14:36:41 +0100 Subject: [PATCH 091/231] srtr: do not restart timer if subpipe is freed --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 735827c76..04b1b7ba6 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -825,7 +825,7 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma return UBASE_ERR_NONE; } - if (upipe_srt_receiver->upump_mgr && !upipe_srt_receiver->upump_timer) { + if (upipe_srt_receiver->upump_mgr && !upipe_srt_receiver->upump_timer && upipe_srt_receiver->control) { struct upump *upump = upump_alloc_timer(upipe_srt_receiver->upump_mgr, upipe_srt_receiver_timer, From 75d7818d0e9e5d4a14aa1f69c875bd423eca11ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 2 Feb 2024 13:54:25 +0100 Subject: [PATCH 092/231] srth: comment different upump functions --- lib/upipe-srt/upipe_srt_handshake.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 781c84902..872600cc7 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -65,10 +65,10 @@ struct upipe_srt_handshake { struct urefcount urefcount; struct upump_mgr *upump_mgr; - struct upump *upump_timer; - struct upump *upump_timeout; - struct upump *upump_keepalive_timeout; - struct upump *upump_kmreq; + struct upump *upump_timer; /* send handshakes every 250ms until connected */ + struct upump *upump_timeout; /* abort connection if not successful */ + struct upump *upump_keepalive_timeout; /* reset connection if no keep alive in 10s */ + struct upump *upump_kmreq; /* re-send key update if not acknowledged */ struct uclock *uclock; struct urequest uclock_request; From e12374339838c23a05cf9dbe2558afe7726b2f51 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 5 Feb 2024 16:05:32 +0000 Subject: [PATCH 093/231] srtr: Replace assertion with if() Fixes assertion hits. --- lib/upipe-srt/upipe_srt_receiver.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 04b1b7ba6..9dde92997 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -521,7 +521,10 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uref_block_unmap(uref, 0); upipe_srt_receiver->last_ack = now; - assert(upipe_srt_receiver->control); + if (!upipe_srt_receiver->control) { + uref_free(uref); + return; + } upipe_srt_receiver->last_sent = now; upipe_srt_receiver_output_output(upipe_srt_receiver->control, uref, NULL); @@ -1186,7 +1189,11 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, } /* data */ - assert(upipe_srt_receiver->control); + if (!upipe_srt_receiver->control) { + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + return; + } uint32_t seqnum = srt_get_data_packet_seq(buf); uint32_t position = srt_get_data_packet_position(buf); From 42c3c411cfca03004a586e95701980ff10440ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 2 Feb 2024 15:23:59 +0100 Subject: [PATCH 094/231] srth: split handle_hs in 4: caller/listener and induction/conclusion --- lib/upipe-srt/upipe_srt_handshake.c | 771 +++++++++++++++------------- 1 file changed, 402 insertions(+), 369 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index eb7dd3acc..0a34b30a6 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -953,451 +953,484 @@ static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t } #endif -static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) +struct hs_packet { + uint8_t *ext_buf; + uint32_t version; + uint16_t encryption; + uint16_t extension; + uint32_t syn_cookie; + uint32_t dst_socket_id; + uint32_t remote_socket_id; + uint32_t isn; + uint32_t mtu; + uint32_t mfw; +}; + +static struct uref *upipe_srt_handshake_handle_hs_caller_conclusion(struct upipe *upipe, int size, uint32_t timestamp, const struct hs_packet *hs_packet) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; - uint8_t *out_cif; - const uint8_t *cif = srt_get_control_packet_cif(buf); - if (!srt_check_handshake(cif, size - SRT_HEADER_SIZE)) { - upipe_err(upipe, "Malformed handshake"); + upipe_srt_handshake_set_upump_timer(upipe, NULL); + upipe_srt_handshake->remote_socket_id = hs_packet->remote_socket_id; + + /* At least HSREQ is expected */ + if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { + upipe_err_va(upipe, "Malformed conclusion handshake (size %u)", size); + upipe_srt_handshake->expect_conclusion = false; return NULL; } - uint32_t version = srt_get_handshake_version(cif); - uint16_t encryption = srt_get_handshake_encryption(cif); - uint16_t extension = srt_get_handshake_extension(cif); - uint32_t hs_type = srt_get_handshake_type(cif); - uint32_t syn_cookie = srt_get_handshake_syn_cookie(cif); - uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); + uint8_t *ext = hs_packet->ext_buf; - if (!upipe_srt_handshake->listener) { - if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { - upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); - upipe_srt_handshake->expect_conclusion = false; - return NULL; + while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { + uint16_t ext_type = srt_get_handshake_extension_type(ext); + uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); + + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + if (ext_len > size) { + upipe_err_va(upipe, "Malformed extension: %u > %u", ext_len, size); + break; } - if (upipe_srt_handshake->expect_conclusion) { - if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { - upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); - return NULL; - } + if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSRSP) { + if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) + upipe_srt_handshake_parse_hsreq(upipe, ext); + else + upipe_err_va(upipe, "Malformed HSRSP: %u < %u\n", ext_len, + SRT_HANDSHAKE_HSREQ_SIZE); + } - upipe_srt_handshake_set_upump_timer(upipe, NULL); - upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); - - /* At least HSREQ is expected */ - size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; - if (size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { - upipe_err_va(upipe, "Malformed conclusion handshake (size %u)", size); - upipe_srt_handshake->expect_conclusion = false; - return NULL; - } + ext += ext_len; + size -= ext_len; + } - uint8_t *ext = srt_get_handshake_extension_buf((uint8_t*)cif); + upipe_srt_handshake_finalize(upipe); + return NULL; +} - while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { - uint16_t ext_type = srt_get_handshake_extension_type(ext); - uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); +static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe *upipe, int size, uint32_t timestamp, const struct hs_packet *hs_packet) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + if (hs_packet->version != SRT_HANDSHAKE_VERSION || hs_packet->dst_socket_id != upipe_srt_handshake->socket_id) { + upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", + hs_packet->dst_socket_id, upipe_srt_handshake->socket_id); + return NULL; + } - if (ext_len > size) { - upipe_err_va(upipe, "Malformed extension: %u > %u", ext_len, size); - break; - } + if (!upipe_srt_handshake->upump_handshake_timeout) { + /* connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); + } - if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSRSP) { - if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) - upipe_srt_handshake_parse_hsreq(upipe, ext); - else - upipe_err_va(upipe, "Malformed HSRSP: %u < %u\n", ext_len, - SRT_HANDSHAKE_HSREQ_SIZE); - } + upipe_srt_handshake->mtu = hs_packet->mtu; + upipe_srt_handshake->mfw = hs_packet->mfw; + upipe_srt_handshake->isn = hs_packet->isn; - ext += ext_len; - size -= ext_len; - } + upipe_dbg_va(upipe, "mtu %u mfw %u isn %u", upipe_srt_handshake->mtu, upipe_srt_handshake->mfw, upipe_srt_handshake->isn); + upipe_verbose_va(upipe, "cookie %08x", hs_packet->syn_cookie); - upipe_srt_handshake_finalize(upipe); - return NULL; - } + upipe_srt_handshake->syn_cookie = hs_packet->syn_cookie; + const size_t ext_size = SRT_HANDSHAKE_HSREQ_SIZE; + size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; - /* */ +#ifdef UPIPE_HAVE_GCRYPT_H + const uint8_t klen = upipe_srt_handshake->sek_len; + // XXX: move to bitstream? + const uint8_t kk = 3; + size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; + if (upipe_srt_handshake->password) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; + extension |= SRT_HANDSHAKE_EXT_KMREQ; + } +#endif + if (upipe_srt_handshake->stream_id) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; + extension |= SRT_HANDSHAKE_EXT_CONFIG; + } - if (upipe_srt_handshake->upump_keepalive_timeout) { - upipe_dbg(upipe, "Ignore handshake, already connected"); - return NULL; - } + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + if (!uref) + return NULL; - if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { - upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); - return NULL; - } + uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); - if (version != SRT_HANDSHAKE_VERSION || dst_socket_id != upipe_srt_handshake->socket_id) { - upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", - dst_socket_id, upipe_srt_handshake->socket_id); - return NULL; + srt_set_handshake_extension(out_cif, extension); + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSREQ); + srt_set_handshake_extension_len(out_ext, ext_size / 4); + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + srt_set_handshake_extension_srt_version(out_ext, 2, 2, 2); // made up version + uint32_t flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK + | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; + srt_set_handshake_extension_srt_flags(out_ext, flags); + + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + size -= ext_size; + out_ext += ext_size; + + if (upipe_srt_handshake->stream_id) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); + srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); + size -= upipe_srt_handshake->stream_id_len; + out_ext += upipe_srt_handshake->stream_id_len; + } + +#ifdef UPIPE_HAVE_GCRYPT_H + if (upipe_srt_handshake->password) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMREQ); + srt_set_handshake_extension_len(out_ext, (size - SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) / 4); + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + + uint8_t wrap[8+256/8] = {0}; + + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + + uint8_t kek[32]; + gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, + strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, + &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); + if (err) { + upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); + return false; } - if (!upipe_srt_handshake->upump_handshake_timeout) { - /* connection has to succeed within 3 seconds */ - struct upump *upump = - upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_timeout, - upipe, upipe->refcount, - 3 * UCLOCK_FREQ, 0); - upump_start(upump); - upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); + gcry_cipher_hd_t aes; + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) { + upipe_err_va(upipe, "Cipher open failed (0x%x)", err); + return false; } - upipe_srt_handshake->mtu = srt_get_handshake_mtu(cif); - upipe_srt_handshake->mfw = srt_get_handshake_mfw(cif); - upipe_srt_handshake->isn = srt_get_handshake_isn(cif); + err = gcry_cipher_setkey(aes, kek, klen); + if (err) { + gcry_cipher_close(aes); + upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); + return false; + } - upipe_dbg_va(upipe, "mtu %u mfw %u isn %u", upipe_srt_handshake->mtu, upipe_srt_handshake->mfw, upipe_srt_handshake->isn); - upipe_verbose_va(upipe, "cookie %08x", syn_cookie); + uint8_t clear_wrap[2*256/8]; + memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); + memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); + err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); + if (err) { + gcry_cipher_close(aes); + upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); + return false; + } - upipe_srt_handshake->syn_cookie = syn_cookie; - const size_t ext_size = SRT_HANDSHAKE_HSREQ_SIZE; - size_t size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; + gcry_cipher_close(aes); -#ifdef UPIPE_HAVE_GCRYPT_H - const uint8_t klen = upipe_srt_handshake->sek_len; - // XXX: move to bitstream? - const uint8_t kk = 3; - size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; - if (upipe_srt_handshake->password) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; - extension |= SRT_HANDSHAKE_EXT_KMREQ; - } + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + } #endif - if (upipe_srt_handshake->stream_id) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; - extension |= SRT_HANDSHAKE_EXT_CONFIG; - } - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); - if (!uref) - return NULL; + upipe_srt_handshake->expect_conclusion = true; - uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); + uref_block_unmap(uref, 0); + return uref; +} - srt_set_handshake_extension(out_cif, extension); - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSREQ); - srt_set_handshake_extension_len(out_ext, ext_size / 4); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; +static struct uref *upipe_srt_handshake_handle_hs_listener_induction(struct upipe *upipe, int size, uint32_t timestamp, const struct hs_packet *hs_packet) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - srt_set_handshake_extension_srt_version(out_ext, 2, 2, 2); // made up version - uint32_t flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK - | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; - srt_set_handshake_extension_srt_flags(out_ext, flags); + if (hs_packet->version != SRT_HANDSHAKE_VERSION_MIN || hs_packet->encryption != SRT_HANDSHAKE_CIPHER_NONE || + hs_packet->extension != SRT_HANDSHAKE_EXT_KMREQ || + hs_packet->syn_cookie != 0 || hs_packet->dst_socket_id != 0) { + upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", hs_packet->syn_cookie, hs_packet->dst_socket_id); + return NULL; + } - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); - size -= ext_size; - out_ext += ext_size; - - if (upipe_srt_handshake->stream_id) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); - srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); - size -= upipe_srt_handshake->stream_id_len; - out_ext += upipe_srt_handshake->stream_id_len; - } + if (!upipe_srt_handshake->upump_handshake_timeout) { + /* connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); + } -#ifdef UPIPE_HAVE_GCRYPT_H - if (upipe_srt_handshake->password) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMREQ); - srt_set_handshake_extension_len(out_ext, (size - SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) / 4); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - - uint8_t wrap[8+256/8] = {0}; - - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - - uint8_t kek[32]; - gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, - strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, - &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); - if (err) { - upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); - return false; - } + timestamp = 0; + upipe_srt_handshake->remote_socket_id = hs_packet->remote_socket_id; + upipe_srt_handshake->socket_id = mrand48(); + upipe_srt_handshake->syn_cookie = mrand48(); - gcry_cipher_hd_t aes; - err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); - if (err) { - upipe_err_va(upipe, "Cipher open failed (0x%x)", err); - return false; - } + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + if (!uref) + return NULL; - err = gcry_cipher_setkey(aes, kek, klen); - if (err) { - gcry_cipher_close(aes); - upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); - return false; - } + srt_set_handshake_extension(out_cif, SRT_MAGIC_CODE); + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); - uint8_t clear_wrap[2*256/8]; - memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); - memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); - err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); - if (err) { - gcry_cipher_close(aes); - upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); - return false; - } + upipe_srt_handshake->expect_conclusion = true; - gcry_cipher_close(aes); + uref_block_unmap(uref, 0); + return uref; +} - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); - } -#endif +static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upipe *upipe, int size, uint32_t timestamp, const struct hs_packet *hs_packet) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - upipe_srt_handshake->expect_conclusion = true; + if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie + || hs_packet->dst_socket_id != 0) { + upipe_err(upipe, "Malformed conclusion handshake"); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } - uref_block_unmap(uref, 0); - return uref; + /* At least HSREQ is expected */ + if (hs_packet->version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { + upipe_err(upipe, "Malformed conclusion handshake (size)"); + upipe_srt_handshake->expect_conclusion = false; + return NULL; } - if (!upipe_srt_handshake->expect_conclusion) { - if (upipe_srt_handshake->upump_keepalive_timeout) { - upipe_dbg(upipe, "Ignore handshake, already connected"); - return NULL; - } + upipe_srt_handshake->isn = hs_packet->isn; - if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { - upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); - return NULL; - } + uint8_t *ext = hs_packet->ext_buf; - if (version != SRT_HANDSHAKE_VERSION_MIN || encryption != SRT_HANDSHAKE_CIPHER_NONE || - extension != SRT_HANDSHAKE_EXT_KMREQ || - syn_cookie != 0 || dst_socket_id != 0) { - upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", syn_cookie, dst_socket_id); - return NULL; + uint8_t kk = 0; + const uint8_t *wrap; + uint8_t wrap_len = 0; + + while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { + uint16_t ext_type = srt_get_handshake_extension_type(ext); + uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); + + size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + if (ext_len > size) { + upipe_err_va(upipe, "Malformed extension: %u > %u", ext_len, size); + break; } - if (!upipe_srt_handshake->upump_handshake_timeout) { - /* connection has to succeed within 3 seconds */ - struct upump *upump = - upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_timeout, - upipe, upipe->refcount, - 3 * UCLOCK_FREQ, 0); - upump_start(upump); - upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); + if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSREQ) { + if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) + upipe_srt_handshake_parse_hsreq(upipe, ext); + else + upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, + SRT_HANDSHAKE_HSREQ_SIZE); + } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { + if (!srt_check_km(ext, ext_len) || !upipe_srt_handshake_parse_kmreq(upipe, ext, &kk, &wrap, &wrap_len)) + upipe_err(upipe, "Malformed KMREQ"); } - upipe_srt_handshake->establish_time = now; - timestamp = 0; - upipe_srt_handshake->remote_socket_id = srt_get_handshake_socket_id(cif); - upipe_srt_handshake->socket_id = mrand48(); - upipe_srt_handshake->syn_cookie = mrand48(); + ext += ext_len; + size -= ext_len; + } - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); - if (!uref) - return NULL; + int extension = 0; + if (hs_packet->version == SRT_HANDSHAKE_VERSION) { + extension = SRT_HANDSHAKE_EXT_HSREQ; + size = SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; + } + if (wrap_len) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; + extension |= SRT_HANDSHAKE_EXT_KMREQ; + } + if (upipe_srt_handshake->stream_id) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; + extension |= SRT_HANDSHAKE_EXT_CONFIG; + } - srt_set_handshake_extension(out_cif, SRT_MAGIC_CODE); - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + if (!uref) + return NULL; + + if (extension) + srt_set_handshake_extension(out_cif, extension); + else + srt_set_handshake_extension(out_cif, 2 /* SRT_DGRAM */); + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); + + uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); + if (hs_packet->version == SRT_HANDSHAKE_VERSION) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSRSP); + srt_set_handshake_extension_len(out_ext, SRT_HANDSHAKE_HSREQ_SIZE / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, + upipe_srt_handshake->minor, upipe_srt_handshake->patch); + srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - upipe_srt_handshake->expect_conclusion = true; + out_ext += SRT_HANDSHAKE_HSREQ_SIZE; + } else + srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); - uref_block_unmap(uref, 0); - return uref; - } else { - if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { - upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); - upipe_srt_handshake->expect_conclusion = false; - return NULL; - } + if (upipe_srt_handshake->stream_id) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); + srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); + out_ext += upipe_srt_handshake->stream_id_len; + } - if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { - upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); - return NULL; - } + if (wrap_len) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMRSP); + srt_set_handshake_extension_len(out_ext, (SRT_KMREQ_COMMON_SIZE + wrap_len) / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + // XXX: move to bitstream? - if (syn_cookie != upipe_srt_handshake->syn_cookie - || dst_socket_id != 0) { - upipe_err(upipe, "Malformed conclusion handshake"); - upipe_srt_handshake->expect_conclusion = false; - return NULL; + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + } + + if (hs_packet->version == SRT_HANDSHAKE_VERSION_MIN) { + struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_HANDSHAKE_HSREQ_SIZE); + if (!next) + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + else { + uint8_t *out; + int output_size = -1; + if (likely(ubase_check(uref_block_write(next, 0, &output_size, &out)))) { + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); + srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_HSREQ); + srt_set_control_packet_type_specific(out, 0); + + uint8_t *out_ext = &out[SRT_HEADER_SIZE]; + srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, + upipe_srt_handshake->minor, upipe_srt_handshake->patch); + srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + + uref_block_unmap(next, 0); + uref->uchain.next = &next->uchain; + } else { + uref_free(next); + } } - /* At least HSREQ is expected */ - size -= SRT_HEADER_SIZE + SRT_HANDSHAKE_CIF_SIZE; - if (version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { - upipe_err(upipe, "Malformed conclusion handshake (size)"); - upipe_srt_handshake->expect_conclusion = false; - return NULL; +#ifdef UPIPE_HAVE_GCRYPT_H + if (upipe_srt_handshake->password) { + next = upipe_srt_handshake_make_kmreq(upipe, timestamp); + if (next) + uref->uchain.next->next = &next->uchain; } +#endif + } - upipe_srt_handshake->isn = srt_get_handshake_isn(cif); + upipe_srt_handshake_finalize(upipe); - uint8_t *ext = srt_get_handshake_extension_buf((uint8_t*)cif); + uref_block_unmap(uref, 0); + return uref; +} - uint8_t kk = 0; - const uint8_t *wrap; - uint8_t wrap_len = 0; +static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; - while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { - uint16_t ext_type = srt_get_handshake_extension_type(ext); - uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); + struct hs_packet hs_packet; - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + const uint8_t *cif = srt_get_control_packet_cif(buf); + size -= SRT_HEADER_SIZE; + if (!srt_check_handshake(cif, size)) { + upipe_err(upipe, "Malformed handshake"); + return NULL; + } - if (ext_len > size) { - upipe_err_va(upipe, "Malformed extension: %u > %u", ext_len, size); - break; - } + hs_packet.version = srt_get_handshake_version(cif); + hs_packet.encryption = srt_get_handshake_encryption(cif); + hs_packet.extension = srt_get_handshake_extension(cif); + hs_packet.syn_cookie = srt_get_handshake_syn_cookie(cif); + hs_packet.dst_socket_id = srt_get_packet_dst_socket_id(buf); + hs_packet.remote_socket_id = srt_get_handshake_socket_id(cif); + hs_packet.mtu = srt_get_handshake_mtu(cif); + hs_packet.mfw = srt_get_handshake_mfw(cif); + hs_packet.isn = srt_get_handshake_isn(cif); + hs_packet.ext_buf = srt_get_handshake_extension_buf((uint8_t*)cif); - if (ext_type == SRT_HANDSHAKE_EXT_TYPE_HSREQ) { - if (ext_len >= SRT_HANDSHAKE_HSREQ_SIZE) - upipe_srt_handshake_parse_hsreq(upipe, ext); - else - upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, - SRT_HANDSHAKE_HSREQ_SIZE); - } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { - if (!srt_check_km(ext, ext_len) || !upipe_srt_handshake_parse_kmreq(upipe, ext, &kk, &wrap, &wrap_len)) - upipe_err(upipe, "Malformed KMREQ"); - } + size -= SRT_HANDSHAKE_CIF_SIZE; - ext += ext_len; - size -= ext_len; - } + uint32_t hs_type = srt_get_handshake_type(cif); + if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { + upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } - extension = 0; - if (version == SRT_HANDSHAKE_VERSION) { - extension = SRT_HANDSHAKE_EXT_HSREQ; - size = SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; - } - if (wrap_len) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; - extension |= SRT_HANDSHAKE_EXT_KMREQ; - } - if (upipe_srt_handshake->stream_id) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; - extension |= SRT_HANDSHAKE_EXT_CONFIG; + if (upipe_srt_handshake->expect_conclusion) { + if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { + upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); + return NULL; } - - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); - if (!uref) + } else { + if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { + upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); return NULL; - - if (extension) - srt_set_handshake_extension(out_cif, extension); - else - srt_set_handshake_extension(out_cif, 2 /* SRT_DGRAM */); - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); - - uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); - if (version == SRT_HANDSHAKE_VERSION) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSRSP); - srt_set_handshake_extension_len(out_ext, SRT_HANDSHAKE_HSREQ_SIZE / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, - upipe_srt_handshake->minor, upipe_srt_handshake->patch); - srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - - out_ext += SRT_HANDSHAKE_HSREQ_SIZE; - } else - srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); - - if (upipe_srt_handshake->stream_id) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); - srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); - out_ext += upipe_srt_handshake->stream_id_len; } - if (wrap_len) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMRSP); - srt_set_handshake_extension_len(out_ext, (SRT_KMREQ_COMMON_SIZE + wrap_len) / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - // XXX: move to bitstream? - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + if (upipe_srt_handshake->upump_keepalive_timeout) { + upipe_dbg(upipe, "Ignore handshake, already connected"); + return NULL; } + } - if (version == SRT_HANDSHAKE_VERSION_MIN) { - struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_HANDSHAKE_HSREQ_SIZE); - if (!next) - upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); - else { - uint8_t *out; - int output_size = -1; - if (likely(ubase_check(uref_block_write(next, 0, &output_size, &out)))) { - srt_set_packet_control(out, true); - srt_set_packet_timestamp(out, timestamp); - srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); - - srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); - srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_HSREQ); - srt_set_control_packet_type_specific(out, 0); - - uint8_t *out_ext = &out[SRT_HEADER_SIZE]; - srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, - upipe_srt_handshake->minor, upipe_srt_handshake->patch); - srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - - uref_block_unmap(next, 0); - uref->uchain.next = &next->uchain; - } else { - uref_free(next); - } - } + if (!upipe_srt_handshake->listener) { -#ifdef UPIPE_HAVE_GCRYPT_H - if (upipe_srt_handshake->password) { - next = upipe_srt_handshake_make_kmreq(upipe, timestamp); - if (next) - uref->uchain.next->next = &next->uchain; - } -#endif + if (upipe_srt_handshake->expect_conclusion) { + return upipe_srt_handshake_handle_hs_caller_conclusion(upipe, size, timestamp, &hs_packet); + } else { + return upipe_srt_handshake_handle_hs_caller_induction(upipe, size, timestamp, &hs_packet); + } + } else { /* listener */ + if (upipe_srt_handshake->expect_conclusion) { + return upipe_srt_handshake_handle_hs_listener_conclusion(upipe, size, timestamp, &hs_packet); + } else { + struct uref *uref = upipe_srt_handshake_handle_hs_listener_induction(upipe, size, timestamp, &hs_packet); + if (uref) + upipe_srt_handshake->establish_time = now; + return uref; } - - upipe_srt_handshake_finalize(upipe); - - uref_block_unmap(uref, 0); - return uref; } } From 5d8a5a9a49935dc5f6342ea74f228d193fa07f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 2 Feb 2024 15:56:42 +0100 Subject: [PATCH 095/231] srth: factorize induction/conclusion specific code --- lib/upipe-srt/upipe_srt_handshake.c | 94 +++++++++++++---------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 0a34b30a6..112c9e6b8 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -547,7 +547,6 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio #ifdef UPIPE_HAVE_GCRYPT_H static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t timestamp); #endif -static void upipe_srt_handshake_finalize(struct upipe *upipe); /** @internal @This processes control commands on a SRT handshake pipe. * @@ -1014,23 +1013,6 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - if (hs_packet->version != SRT_HANDSHAKE_VERSION || hs_packet->dst_socket_id != upipe_srt_handshake->socket_id) { - upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", - hs_packet->dst_socket_id, upipe_srt_handshake->socket_id); - return NULL; - } - - if (!upipe_srt_handshake->upump_handshake_timeout) { - /* connection has to succeed within 3 seconds */ - struct upump *upump = - upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_timeout, - upipe, upipe->refcount, - 3 * UCLOCK_FREQ, 0); - upump_start(upump); - upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); - } - upipe_srt_handshake->mtu = hs_packet->mtu; upipe_srt_handshake->mfw = hs_packet->mfw; upipe_srt_handshake->isn = hs_packet->isn; @@ -1152,8 +1134,6 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe } #endif - upipe_srt_handshake->expect_conclusion = true; - uref_block_unmap(uref, 0); return uref; } @@ -1162,24 +1142,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_induction(struct upip { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - if (hs_packet->version != SRT_HANDSHAKE_VERSION_MIN || hs_packet->encryption != SRT_HANDSHAKE_CIPHER_NONE || - hs_packet->extension != SRT_HANDSHAKE_EXT_KMREQ || - hs_packet->syn_cookie != 0 || hs_packet->dst_socket_id != 0) { - upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", hs_packet->syn_cookie, hs_packet->dst_socket_id); - return NULL; - } - - if (!upipe_srt_handshake->upump_handshake_timeout) { - /* connection has to succeed within 3 seconds */ - struct upump *upump = - upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_timeout, - upipe, upipe->refcount, - 3 * UCLOCK_FREQ, 0); - upump_start(upump); - upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); - } - timestamp = 0; upipe_srt_handshake->remote_socket_id = hs_packet->remote_socket_id; upipe_srt_handshake->socket_id = mrand48(); @@ -1193,8 +1155,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_induction(struct upip srt_set_handshake_extension(out_cif, SRT_MAGIC_CODE); srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); - upipe_srt_handshake->expect_conclusion = true; - uref_block_unmap(uref, 0); return uref; } @@ -1358,8 +1318,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi #endif } - upipe_srt_handshake_finalize(upipe); - uref_block_unmap(uref, 0); return uref; } @@ -1398,7 +1356,9 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } - if (upipe_srt_handshake->expect_conclusion) { + bool conclusion = upipe_srt_handshake->expect_conclusion; + + if (conclusion) { if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); return NULL; @@ -1415,23 +1375,55 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } } + struct uref *uref; if (!upipe_srt_handshake->listener) { - - if (upipe_srt_handshake->expect_conclusion) { - return upipe_srt_handshake_handle_hs_caller_conclusion(upipe, size, timestamp, &hs_packet); + if (conclusion) { + uref = upipe_srt_handshake_handle_hs_caller_conclusion(upipe, size, timestamp, &hs_packet); } else { - return upipe_srt_handshake_handle_hs_caller_induction(upipe, size, timestamp, &hs_packet); + if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { + upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", + hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); + return NULL; + } + uref = upipe_srt_handshake_handle_hs_caller_induction(upipe, size, timestamp, &hs_packet); } } else { /* listener */ - if (upipe_srt_handshake->expect_conclusion) { - return upipe_srt_handshake_handle_hs_listener_conclusion(upipe, size, timestamp, &hs_packet); + if (conclusion) { + uref = upipe_srt_handshake_handle_hs_listener_conclusion(upipe, size, timestamp, &hs_packet); } else { - struct uref *uref = upipe_srt_handshake_handle_hs_listener_induction(upipe, size, timestamp, &hs_packet); + if (hs_packet.version != SRT_HANDSHAKE_VERSION_MIN || hs_packet.encryption != SRT_HANDSHAKE_CIPHER_NONE || + hs_packet.extension != SRT_HANDSHAKE_EXT_KMREQ || + hs_packet.syn_cookie != 0 || hs_packet.dst_socket_id != 0) { + upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", hs_packet.syn_cookie, hs_packet.dst_socket_id); + return NULL; + } + + uref = upipe_srt_handshake_handle_hs_listener_induction(upipe, size, timestamp, &hs_packet); if (uref) upipe_srt_handshake->establish_time = now; - return uref; } } + + if (uref) { + if (!conclusion) { + upipe_srt_handshake->expect_conclusion = true; + + if (!upipe_srt_handshake->upump_handshake_timeout) { + /* connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); + } + } else { + upipe_srt_handshake_finalize(upipe); + } + } + + return uref; } static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) From f88eafde4f632cbc4cb7568abd82f0dc98b43bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 11:17:23 +0100 Subject: [PATCH 096/231] srth: fix potential bug handling early handshake version --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 112c9e6b8..42a44de11 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1214,8 +1214,8 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi int extension = 0; if (hs_packet->version == SRT_HANDSHAKE_VERSION) { - extension = SRT_HANDSHAKE_EXT_HSREQ; - size = SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; + extension |= SRT_HANDSHAKE_EXT_HSREQ; + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; } if (wrap_len) { size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; From d8f779ff126906e361e504363ff6b6cd56ede54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 11:17:02 +0100 Subject: [PATCH 097/231] srth: factorize handshake packet building with extensions --- lib/upipe-srt/upipe_srt_handshake.c | 196 ++++++++++++---------------- 1 file changed, 80 insertions(+), 116 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 42a44de11..09e7f8cca 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -403,7 +403,9 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->receiver_tsbpd_delay = 0; upipe_srt_handshake->sender_tsbpd_delay = 0; - upipe_srt_handshake->flags = 0; + upipe_srt_handshake->flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK + | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; + upipe_srt_handshake->major = 0; upipe_srt_handshake->minor = 0; upipe_srt_handshake->patch = 0; @@ -952,6 +954,59 @@ static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t } #endif +static void build_hs(struct upipe *upipe, uint8_t *out_cif, int extension, bool rsp, const uint8_t *wrap, size_t wrap_len) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); + const size_t ext_size = SRT_HANDSHAKE_HSREQ_SIZE; + + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); + + if (extension) { + srt_set_handshake_extension(out_cif, extension); + srt_set_handshake_extension_type(out_ext, rsp ? SRT_HANDSHAKE_EXT_TYPE_HSRSP : SRT_HANDSHAKE_EXT_TYPE_HSREQ); + srt_set_handshake_extension_len(out_ext, ext_size / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + srt_set_handshake_extension_srt_version(out_ext, 2, 2, 2); // made up version + srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); + srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); + srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); + out_ext += ext_size; + } else { + srt_set_handshake_extension(out_cif, 2 /* SRT_DGRAM */); + srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); + } + + if (upipe_srt_handshake->stream_id) { + srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); + srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); + out_ext += upipe_srt_handshake->stream_id_len; + } + + if (wrap_len) { + srt_set_handshake_extension_type(out_ext, rsp ? SRT_HANDSHAKE_EXT_TYPE_KMRSP : SRT_HANDSHAKE_EXT_TYPE_KMREQ); + srt_set_handshake_extension_len(out_ext, (SRT_KMREQ_COMMON_SIZE + wrap_len) / 4); + out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + const uint8_t kk = 3; + srt_km_set_kk(out_ext, kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + + srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + } +} + struct hs_packet { uint8_t *ext_buf; uint32_t version; @@ -1021,79 +1076,18 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe upipe_verbose_va(upipe, "cookie %08x", hs_packet->syn_cookie); upipe_srt_handshake->syn_cookie = hs_packet->syn_cookie; - const size_t ext_size = SRT_HANDSHAKE_HSREQ_SIZE; - size = ext_size + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; + size = SRT_HANDSHAKE_HSREQ_SIZE + SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; uint16_t extension = SRT_HANDSHAKE_EXT_HSREQ; -#ifdef UPIPE_HAVE_GCRYPT_H - const uint8_t klen = upipe_srt_handshake->sek_len; - // XXX: move to bitstream? - const uint8_t kk = 3; - size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; - if (upipe_srt_handshake->password) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; - extension |= SRT_HANDSHAKE_EXT_KMREQ; - } -#endif - if (upipe_srt_handshake->stream_id) { - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; - extension |= SRT_HANDSHAKE_EXT_CONFIG; - } - - uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); - if (!uref) - return NULL; - - uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); - - srt_set_handshake_extension(out_cif, extension); - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSREQ); - srt_set_handshake_extension_len(out_ext, ext_size / 4); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - - srt_set_handshake_extension_srt_version(out_ext, 2, 2, 2); // made up version - uint32_t flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK - | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; - srt_set_handshake_extension_srt_flags(out_ext, flags); - - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); - size -= ext_size; - out_ext += ext_size; - - if (upipe_srt_handshake->stream_id) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); - srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); - size -= upipe_srt_handshake->stream_id_len; - out_ext += upipe_srt_handshake->stream_id_len; - } - + size_t wrap_len = 0; + uint8_t wrap[8+256/8] = {0}; #ifdef UPIPE_HAVE_GCRYPT_H if (upipe_srt_handshake->password) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMREQ); - srt_set_handshake_extension_len(out_ext, (size - SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) / 4); - size -= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - - uint8_t wrap[8+256/8] = {0}; + const uint8_t klen = upipe_srt_handshake->sek_len; + // XXX: move to bitstream? + const uint8_t kk = 3; - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; uint8_t kek[32]; gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, @@ -1121,6 +1115,7 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe uint8_t clear_wrap[2*256/8]; memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); + err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); if (err) { gcry_cipher_close(aes); @@ -1130,10 +1125,23 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe gcry_cipher_close(aes); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; + extension |= SRT_HANDSHAKE_EXT_KMREQ; } #endif + if (upipe_srt_handshake->stream_id) { + size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + upipe_srt_handshake->stream_id_len; + extension |= SRT_HANDSHAKE_EXT_CONFIG; + } + + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + if (!uref) + return NULL; + + build_hs(upipe, out_cif, extension, false, wrap, wrap_len); + uref_block_unmap(uref, 0); return uref; } @@ -1213,6 +1221,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi } int extension = 0; + size = 0; if (hs_packet->version == SRT_HANDSHAKE_VERSION) { extension |= SRT_HANDSHAKE_EXT_HSREQ; size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE; @@ -1231,52 +1240,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (!uref) return NULL; - if (extension) - srt_set_handshake_extension(out_cif, extension); - else - srt_set_handshake_extension(out_cif, 2 /* SRT_DGRAM */); - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_CONCLUSION); - - uint8_t *out_ext = srt_get_handshake_extension_buf(out_cif); - if (hs_packet->version == SRT_HANDSHAKE_VERSION) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_HSRSP); - srt_set_handshake_extension_len(out_ext, SRT_HANDSHAKE_HSREQ_SIZE / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, - upipe_srt_handshake->minor, upipe_srt_handshake->patch); - srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); - srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); - srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); - - out_ext += SRT_HANDSHAKE_HSREQ_SIZE; - } else - srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); - - if (upipe_srt_handshake->stream_id) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_SID); - srt_set_handshake_extension_len(out_ext, upipe_srt_handshake->stream_id_len / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memcpy(out_ext, upipe_srt_handshake->stream_id, upipe_srt_handshake->stream_id_len); - out_ext += upipe_srt_handshake->stream_id_len; - } - - if (wrap_len) { - srt_set_handshake_extension_type(out_ext, SRT_HANDSHAKE_EXT_TYPE_KMRSP); - srt_set_handshake_extension_len(out_ext, (SRT_KMREQ_COMMON_SIZE + wrap_len) / 4); - out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - // XXX: move to bitstream? - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); - } + build_hs(upipe, out_cif, extension, true, wrap, wrap_len); if (hs_packet->version == SRT_HANDSHAKE_VERSION_MIN) { struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, From 00074f1c0bc2c226aca867c0b0f0976da5c8ab04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 11:33:46 +0100 Subject: [PATCH 098/231] srth: factorize km msg building Store kk in context, initialized to 3 (odd/even) Will be overwritten by remote if needed --- lib/upipe-srt/upipe_srt_handshake.c | 90 ++++++++++++----------------- 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 09e7f8cca..9570c10f8 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -111,6 +111,7 @@ struct upipe_srt_handshake { uint8_t salt[16]; uint8_t sek[2][32]; uint8_t sek_len; + uint8_t kk; bool update_even; struct uref *kmreq; @@ -411,6 +412,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->patch = 0; upipe_srt_handshake->sek_len = 0; + upipe_srt_handshake->kk = 3; upipe_srt_handshake->update_even = false; upipe_srt_handshake->kmreq = NULL; upipe_srt_handshake->password = NULL; @@ -598,6 +600,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, upipe_srt_handshake->sek_len = va_arg(args, int); free(upipe_srt_handshake->password); if (password) { + upipe_srt_handshake->kk = 3; upipe_srt_handshake->password = strdup(password); switch (upipe_srt_handshake->sek_len) { case 128/8: @@ -778,7 +781,7 @@ static void upipe_srt_handshake_parse_hsreq(struct upipe *upipe, const uint8_t * upipe_srt_handshake->receiver_tsbpd_delay, upipe_srt_handshake->sender_tsbpd_delay); } -static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, uint8_t *kk, const uint8_t **wrap, uint8_t *wrap_len) +static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, const uint8_t **wrap, uint8_t *wrap_len) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); if (!upipe_srt_handshake->password) { @@ -788,7 +791,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * #ifdef UPIPE_HAVE_GCRYPT_H - *kk = srt_km_get_kk(ext); + upipe_srt_handshake->kk = srt_km_get_kk(ext); uint8_t cipher = srt_km_get_cipher(ext); if (cipher != SRT_KMREQ_CIPHER_AES) { upipe_err_va(upipe, "Unsupported cipher %u", cipher); @@ -814,7 +817,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * return false; } - *wrap_len = ((*kk == 3) ? 2 : 1) * klen + 8; + *wrap_len = ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen + 8; uint8_t osek[64]; /* 2x 256 bits keys */ @@ -831,7 +834,7 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * goto key_error; } - err = gcry_cipher_decrypt(aes, osek, ((*kk == 3) ? 2 : 1) * klen, *wrap, *wrap_len); + err = gcry_cipher_decrypt(aes, osek, ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen, *wrap, *wrap_len); if (err) { upipe_err_va(upipe, "Couldn't decrypt session key (%s)", gcry_strerror(err)); goto key_error; @@ -841,11 +844,11 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * upipe_srt_handshake->sek_len = klen; - if (*kk == 3) { + if (upipe_srt_handshake->kk == 3) { memcpy(upipe_srt_handshake->sek[0], osek, klen); memcpy(upipe_srt_handshake->sek[1], &osek[klen], klen); } else { - memcpy(upipe_srt_handshake->sek[(*kk & (1<<0)) ? 0 : 1], osek, klen); + memcpy(upipe_srt_handshake->sek[(upipe_srt_handshake->kk & (1<<0)) ? 0 : 1], osek, klen); } return true; @@ -862,13 +865,31 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * #endif } +static void make_km_msg(struct upipe *upipe, uint8_t *out_ext, const uint8_t *wrap, size_t wrap_len) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + const uint8_t klen = upipe_srt_handshake->sek_len; + + memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); + + out_ext[0] = 0x12; // S V PT + out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign + srt_km_set_kk(out_ext, upipe_srt_handshake->kk); + srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); + out_ext[10] = 2; // SE + out_ext[14] = 4; // slen; + + srt_km_set_klen(out_ext, klen / 4); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); + memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); +} + #ifdef UPIPE_HAVE_GCRYPT_H static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t timestamp) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); const uint8_t klen = upipe_srt_handshake->sek_len; - const uint8_t kk = 3; - size_t wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; + size_t wrap_len = ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen + 8; struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); if (!next) { @@ -891,22 +912,8 @@ static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t srt_set_control_packet_type_specific(out, 0); uint8_t *out_ext = &out[SRT_HEADER_SIZE]; - - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - // XXX: move to bitstream? - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - uint8_t wrap[8+256/8] = {0}; - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - uint8_t kek[32]; gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, @@ -940,7 +947,7 @@ static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t gcry_cipher_close(aes); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + make_km_msg(upipe, out_ext, wrap, wrap_len); uref_block_unmap(next, 0); @@ -991,19 +998,7 @@ static void build_hs(struct upipe *upipe, uint8_t *out_cif, int extension, bool srt_set_handshake_extension_len(out_ext, (SRT_KMREQ_COMMON_SIZE + wrap_len) / 4); out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - memset(out_ext, 0, SRT_KMREQ_COMMON_SIZE); - - out_ext[0] = 0x12; // S V PT - out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign - const uint8_t kk = 3; - srt_km_set_kk(out_ext, kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); - out_ext[10] = 2; // SE - out_ext[14] = 4; // slen; - - srt_km_set_klen(out_ext, upipe_srt_handshake->sek_len / 4); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + make_km_msg(upipe, out_ext, wrap, wrap_len); } } @@ -1084,10 +1079,7 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe #ifdef UPIPE_HAVE_GCRYPT_H if (upipe_srt_handshake->password) { const uint8_t klen = upipe_srt_handshake->sek_len; - // XXX: move to bitstream? - const uint8_t kk = 3; - - wrap_len = ((kk == 3) ? 2 : 1) * klen + 8; + wrap_len = ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen + 8; uint8_t kek[32]; gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, @@ -1189,7 +1181,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi uint8_t *ext = hs_packet->ext_buf; - uint8_t kk = 0; const uint8_t *wrap; uint8_t wrap_len = 0; @@ -1212,7 +1203,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, SRT_HANDSHAKE_HSREQ_SIZE); } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { - if (!srt_check_km(ext, ext_len) || !upipe_srt_handshake_parse_kmreq(upipe, ext, &kk, &wrap, &wrap_len)) + if (!srt_check_km(ext, ext_len) || !upipe_srt_handshake_parse_kmreq(upipe, ext, &wrap, &wrap_len)) upipe_err(upipe, "Malformed KMREQ"); } @@ -1399,15 +1390,14 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u if (subtype != SRT_HANDSHAKE_EXT_TYPE_KMRSP && subtype != SRT_HANDSHAKE_EXT_TYPE_KMREQ) return NULL; - uint8_t kk = 0; const uint8_t *wrap; uint8_t wrap_len = 0; const uint8_t *cif = srt_get_control_packet_cif(buf); size -= SRT_HEADER_SIZE; - if (!srt_check_km(buf, size) || !upipe_srt_handshake_parse_kmreq(upipe, buf, &kk, &wrap, &wrap_len)) - if (!upipe_srt_handshake_parse_kmreq(upipe, cif, &kk, &wrap, &wrap_len)) { + if (!srt_check_km(buf, size) || !upipe_srt_handshake_parse_kmreq(upipe, buf, &wrap, &wrap_len)) + if (!upipe_srt_handshake_parse_kmreq(upipe, cif, &wrap, &wrap_len)) { upipe_err_va(upipe, "parse failed"); return NULL; } @@ -1443,15 +1433,7 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u memset(extra, 0, SRT_KMREQ_COMMON_SIZE); if (wrap_len) { - extra[0] = 0x12; // S V PT - extra[1] = 0x20; extra[2] = 0x29; // Sign - srt_km_set_kk(extra, kk); - srt_km_set_cipher(extra, SRT_KMREQ_CIPHER_AES); - extra[10] = 2; // SE - extra[14] = 4; // slen; - srt_km_set_klen(extra, upipe_srt_handshake->sek_len / 4); - memcpy(&extra[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); - memcpy(&extra[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); + make_km_msg(upipe, extra, wrap, wrap_len); } upipe_srt_handshake_finalize(upipe); From ba33cc20f1affa7b4dafbad5ba170d2164c416bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 11:48:01 +0100 Subject: [PATCH 099/231] srth: factorize key wrapping --- lib/upipe-srt/upipe_srt_handshake.c | 110 +++++++++++----------------- 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 9570c10f8..997c364f9 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -885,34 +885,11 @@ static void make_km_msg(struct upipe *upipe, uint8_t *out_ext, const uint8_t *wr } #ifdef UPIPE_HAVE_GCRYPT_H -static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t timestamp) +static bool upipe_srt_handshake_wrap_key(struct upipe *upipe, uint8_t *wrap) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); const uint8_t klen = upipe_srt_handshake->sek_len; size_t wrap_len = ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen + 8; - struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); - if (!next) { - upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); - return NULL; - } - - uint8_t *out; - int output_size = -1; - if (unlikely(!ubase_check(uref_block_write(next, 0, &output_size, &out)))) { - goto error; - } - - srt_set_packet_control(out, true); - srt_set_packet_timestamp(out, timestamp); - srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); - - srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); - srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_KMREQ); - srt_set_control_packet_type_specific(out, 0); - - uint8_t *out_ext = &out[SRT_HEADER_SIZE]; - uint8_t wrap[8+256/8] = {0}; uint8_t kek[32]; gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, @@ -920,41 +897,76 @@ static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); if (err) { upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); - goto error; + return false; } gcry_cipher_hd_t aes; err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); if (err) { upipe_err_va(upipe, "Cipher open failed (0x%x)", err); - goto error; + return false; } err = gcry_cipher_setkey(aes, kek, klen); if (err) { + gcry_cipher_close(aes); upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); - goto aes_error; + return false; } uint8_t clear_wrap[2*256/8]; memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); + err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); if (err) { + gcry_cipher_close(aes); upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); - goto aes_error; + return false; } gcry_cipher_close(aes); + return true; +} + +static struct uref *upipe_srt_handshake_make_kmreq(struct upipe *upipe, uint32_t timestamp) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + const uint8_t klen = upipe_srt_handshake->sek_len; + size_t wrap_len = ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen + 8; + struct uref *next = uref_block_alloc(upipe_srt_handshake->uref_mgr, + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len); + if (!next) { + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return NULL; + } + + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(next, 0, &output_size, &out)))) { + goto error; + } + + srt_set_packet_control(out, true); + srt_set_packet_timestamp(out, timestamp); + srt_set_packet_dst_socket_id(out, upipe_srt_handshake->remote_socket_id); + + srt_set_control_packet_type(out, SRT_CONTROL_TYPE_USER); + srt_set_control_packet_subtype(out, SRT_HANDSHAKE_EXT_TYPE_KMREQ); + srt_set_control_packet_type_specific(out, 0); + + uint8_t *out_ext = &out[SRT_HEADER_SIZE]; + uint8_t wrap[8+256/8] = {0}; + if (!upipe_srt_handshake_wrap_key(upipe, wrap)) + goto error; + make_km_msg(upipe, out_ext, wrap, wrap_len); uref_block_unmap(next, 0); return next; -aes_error: - gcry_cipher_close(aes); error: uref_free(next); return NULL; @@ -1080,43 +1092,9 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe if (upipe_srt_handshake->password) { const uint8_t klen = upipe_srt_handshake->sek_len; wrap_len = ((upipe_srt_handshake->kk == 3) ? 2 : 1) * klen + 8; - - uint8_t kek[32]; - gpg_error_t err = gcry_kdf_derive(upipe_srt_handshake->password, - strlen(upipe_srt_handshake->password), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, - &upipe_srt_handshake->salt[8], 8, 2048, klen, kek); - if (err) { - upipe_err_va(upipe, "pbkdf2 failed (%s)", gcry_strerror(err)); - return false; - } - - gcry_cipher_hd_t aes; - err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_AESWRAP, 0); - if (err) { - upipe_err_va(upipe, "Cipher open failed (0x%x)", err); - return false; - } - - err = gcry_cipher_setkey(aes, kek, klen); - if (err) { - gcry_cipher_close(aes); - upipe_err_va(upipe, "Couldn't use key encrypting key (0x%x)", err); - return false; - } - - uint8_t clear_wrap[2*256/8]; - memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); - memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); - - err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); - if (err) { - gcry_cipher_close(aes); - upipe_err_va(upipe, "Couldn't encrypt session key (0x%x)", err); - return false; + if (!upipe_srt_handshake_wrap_key(upipe, wrap)) { + return NULL; } - - gcry_cipher_close(aes); - size += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_KMREQ_COMMON_SIZE + wrap_len; extension |= SRT_HANDSHAKE_EXT_KMREQ; } From 19dec2862b1f8b1df0e2e2e929451130ab59865c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 16:38:39 +0100 Subject: [PATCH 100/231] srth: do not assume we received both odd and even keys --- lib/upipe-srt/upipe_srt_handshake.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 997c364f9..f14b6dc87 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -738,15 +738,21 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) upipe_err(upipe, "damn"); - opaque.v = upipe_srt_handshake->sek[0]; - opaque.size = upipe_srt_handshake->sek_len; - if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) - upipe_err(upipe, "damn"); + uint8_t kk = upipe_srt_handshake->kk; - opaque.v = upipe_srt_handshake->sek[1]; - opaque.size = upipe_srt_handshake->sek_len; - if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.odd_key"))) - upipe_err(upipe, "damn"); + if (kk & (1<<0)) { + opaque.v = upipe_srt_handshake->sek[0]; + opaque.size = upipe_srt_handshake->sek_len; + if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.even_key"))) + upipe_err(upipe, "damn"); + } + + if (kk & (1<<1)) { + opaque.v = upipe_srt_handshake->sek[1]; + opaque.size = upipe_srt_handshake->sek_len; + if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.odd_key"))) + upipe_err(upipe, "damn"); + } uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); From 4c92c2d4dd57e71aaa382006516fc3e0fd358940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 16:39:11 +0100 Subject: [PATCH 101/231] key rotation: typo --- lib/upipe-srt/upipe_srt_handshake.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f14b6dc87..9015dc903 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1380,11 +1380,10 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u const uint8_t *cif = srt_get_control_packet_cif(buf); size -= SRT_HEADER_SIZE; - if (!srt_check_km(buf, size) || !upipe_srt_handshake_parse_kmreq(upipe, buf, &wrap, &wrap_len)) - if (!upipe_srt_handshake_parse_kmreq(upipe, cif, &wrap, &wrap_len)) { - upipe_err_va(upipe, "parse failed"); - return NULL; - } + if (!srt_check_km(cif, size) || !upipe_srt_handshake_parse_kmreq(upipe, cif, &wrap, &wrap_len)) { + upipe_err_va(upipe, "KM parse failed"); + return NULL; + } if (subtype == SRT_HANDSHAKE_EXT_TYPE_KMRSP) { if (upipe_srt_handshake->kmreq) { From 722a83b42dd701749164f053b98537574e6917ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 16:46:20 +0100 Subject: [PATCH 102/231] srth: initialize socket_id --- lib/upipe-srt/upipe_srt_handshake.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 9015dc903..580192ecd 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -411,6 +411,8 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->minor = 0; upipe_srt_handshake->patch = 0; + upipe_srt_handshake->socket_id = 0; + upipe_srt_handshake->sek_len = 0; upipe_srt_handshake->kk = 3; upipe_srt_handshake->update_even = false; From 70bc2358a42c89c1b01cb4a2e2f2ec1c6f228961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 16:47:39 +0100 Subject: [PATCH 103/231] srth: initalize version only once --- lib/upipe-srt/upipe_srt_handshake.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 580192ecd..cbc18469c 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -407,9 +407,10 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->flags = SRT_HANDSHAKE_EXT_FLAG_CRYPT | SRT_HANDSHAKE_EXT_FLAG_PERIODICNAK | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; - upipe_srt_handshake->major = 0; - upipe_srt_handshake->minor = 0; - upipe_srt_handshake->patch = 0; + /* made up version */ + upipe_srt_handshake->major = 2; + upipe_srt_handshake->minor = 2; + upipe_srt_handshake->patch = 2; upipe_srt_handshake->socket_id = 0; @@ -995,7 +996,8 @@ static void build_hs(struct upipe *upipe, uint8_t *out_cif, int extension, bool srt_set_handshake_extension_len(out_ext, ext_size / 4); out_ext += SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE; - srt_set_handshake_extension_srt_version(out_ext, 2, 2, 2); // made up version + srt_set_handshake_extension_srt_version(out_ext, upipe_srt_handshake->major, + upipe_srt_handshake->minor, upipe_srt_handshake->patch); srt_set_handshake_extension_srt_flags(out_ext, upipe_srt_handshake->flags); srt_set_handshake_extension_receiver_tsbpd_delay(out_ext, upipe_srt_handshake->receiver_tsbpd_delay); srt_set_handshake_extension_sender_tsbpd_delay(out_ext, upipe_srt_handshake->sender_tsbpd_delay); From 0c677127956cb20e9b9915eec20bc55cef95eed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 8 Feb 2024 16:54:18 +0100 Subject: [PATCH 104/231] srth: check upump_mgr and uclock --- lib/upipe-srt/upipe_srt_handshake.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index cbc18469c..3f9b02002 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1522,6 +1522,18 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + if (!upipe_srt_handshake->upump_mgr) { + upipe_warn(upipe, "No upump mgr"); + upipe_srt_handshake_check(upipe, NULL); + uref_free(uref); + } + + if (!upipe_srt_handshake->uclock) { + upipe_warn(upipe, "No uclock"); + upipe_srt_handshake_check(upipe, NULL); + uref_free(uref); + } + size_t total_size; ubase_assert(uref_block_size(uref, &total_size)); From bfb6be9a6bcc4cbd96ebf27d053383e6e22898b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 9 Feb 2024 10:44:06 +0100 Subject: [PATCH 105/231] srth: fix keepalive --- lib/upipe-srt/upipe_srt_handshake.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 3f9b02002..f0c1385b5 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -716,19 +716,26 @@ static const char *get_hs_error(uint32_t hs_type) return hs_error[hs_type]; } -static void upipe_srt_handshake_finalize(struct upipe *upipe) +static void upipe_srt_handshake_restart_keepalive_timeout(struct upipe *upipe) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - upipe_srt_handshake->expect_conclusion = false; - upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); - struct upump *upump = upump_alloc_timer(upipe_srt_handshake->upump_mgr, upipe_srt_handshake_keepalive_timeout, upipe, upipe->refcount, 10*UCLOCK_FREQ, 0); upump_start(upump); + upipe_srt_handshake_set_upump_keepalive_timeout(upipe, upump); +} + +static void upipe_srt_handshake_finalize(struct upipe *upipe) +{ + struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); + + upipe_srt_handshake_restart_keepalive_timeout(upipe); struct uref *flow_def; if (ubase_check(upipe_srt_handshake_get_flow_def(upipe, &flow_def))) { @@ -1559,6 +1566,10 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, return; } + /* Only restart if timer is already alive, it means we're connected */ + if (upipe_srt_handshake->upump_keepalive_timeout) + upipe_srt_handshake_restart_keepalive_timeout(upipe); + if (srt_get_packet_control(buf)) { bool handled = false; struct uref *reply = upipe_srt_handshake_input_control(upipe, buf, size, &handled); From 0d8a1e1b6baac13c7c71ed1d4ce09fd3e9565cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 9 Feb 2024 10:52:11 +0100 Subject: [PATCH 106/231] srth: debug connection process --- lib/upipe-srt/upipe_srt_handshake.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f0c1385b5..69ad49ead 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -735,6 +735,10 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) upipe_srt_handshake->expect_conclusion = false; upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); + if (!upipe_srt_handshake->upump_keepalive_timeout) { + upipe_dbg_va(upipe, "[%s] Remote connected", + upipe_srt_handshake->listener ? "listener" : "caller"); + } upipe_srt_handshake_restart_keepalive_timeout(upipe); struct uref *flow_def; @@ -1325,6 +1329,10 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } } + upipe_dbg_va(upipe, "[%s] got %s handshake packet", + upipe_srt_handshake->listener ? "listener" : "caller", + conclusion ? "conclusion" : "induction"); + struct uref *uref; if (!upipe_srt_handshake->listener) { if (conclusion) { From fb3be7d41eac186c1721be9b50f63d8194122d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 9 Feb 2024 10:53:35 +0100 Subject: [PATCH 107/231] srtr: whitespace --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 9dde92997..07ae8a76b 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -858,7 +858,7 @@ static void upipe_srt_receiver_empty_buffer(struct upipe *upipe) ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { struct uref *uref = uref_from_uchain(uchain); ulist_delete(uchain); - uref_free(uref); + uref_free(uref); } } From 4b0d9c08242a84e88100c7e92e65e576466d4806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 9 Feb 2024 13:20:29 +0100 Subject: [PATCH 108/231] srth: more debug --- lib/upipe-srt/upipe_srt_handshake.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 69ad49ead..60a0dac50 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1162,9 +1162,13 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie - || hs_packet->dst_socket_id != 0) { - upipe_err(upipe, "Malformed conclusion handshake"); + if (hs_packet->dst_socket_id != 0) { + upipe_err_va(upipe, "Malformed conclusion handshake (dst_socket_id 0x%08x)", hs_packet->dst_socket_id); + upipe_srt_handshake->expect_conclusion = false; + return NULL; + } + if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie) { + upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); upipe_srt_handshake->expect_conclusion = false; return NULL; } From 839399ae8a0c014d82f868c4b9a3bbb3b8da64f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 9 Feb 2024 15:56:21 +0100 Subject: [PATCH 109/231] Test my bitstream --- .github/workflows/test-suite.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-suite.yaml b/.github/workflows/test-suite.yaml index dbe2466a0..53a4fe49e 100644 --- a/.github/workflows/test-suite.yaml +++ b/.github/workflows/test-suite.yaml @@ -150,7 +150,7 @@ jobs: - name: Install bitstream run: | - git clone --depth 1 https://code.videolan.org/videolan/bitstream.git + git clone --depth 1 https://github.com/funman/bitstream make -C bitstream install PREFIX="$PWD/usr-bitstream" set-env PKG_CONFIG_PATH "$PKG_CONFIG_PATH:$PWD/usr-bitstream/share/pkgconfig" if [ "${{ matrix.static }}" = "true" ]; then From 43207978af7291833702561e15e62bf12eaf3ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 16 Feb 2024 16:31:24 +0100 Subject: [PATCH 110/231] rist_rx: -r option to add rtp demux --- examples/rist_rx.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index bd0c05e43..4709bec14 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -51,6 +51,7 @@ #include "upipe/ustring.h" #include "upipe/upipe.h" #include "upipe-modules/upipe_udp_source.h" +#include #include "upipe-modules/upipe_udp_sink.h" #include "upipe-srt/upipe_srt_handshake.h" #include "upipe-srt/upipe_srt_receiver.h" @@ -175,6 +176,8 @@ static char *latency; static bool restart; +static struct upipe_mgr *rtpd_mgr; + static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) { uint16_t port = 0; @@ -235,6 +238,13 @@ static int start(void) "udpsink")); upipe_release(upipe_udp_sink); + if (rtpd_mgr) { + upipe_srtr = upipe_void_chain_output(upipe_srtr, rtpd_mgr, + uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "rtpd")); + assert(upipe_srtr); + } + int udp_fd; /* receive SRT */ if (listener) { @@ -345,9 +355,10 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, } static void usage(const char *argv0) { - fprintf(stdout, "Usage: %s [-d] [-k password] [-l 128] ", argv0); + fprintf(stdout, "Usage: %s [-dr] [-k password] [-l 128] ", argv0); fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); + fprintf(stdout, " -r: rtp demux\n"); fprintf(stdout, " -k encryption password\n"); fprintf(stdout, " -l key length in bits\n"); exit(EXIT_FAILURE); @@ -358,7 +369,7 @@ int main(int argc, char *argv[]) int opt; /* parse options */ - while ((opt = getopt(argc, argv, "qdk:l:")) != -1) { + while ((opt = getopt(argc, argv, "qrdk:l:")) != -1) { switch (opt) { case 'd': loglevel--; @@ -372,6 +383,9 @@ int main(int argc, char *argv[]) case 'l': key_length = atoi(optarg); break; + case 'r': + rtpd_mgr = upipe_rtpd_mgr_alloc(); + break; default: usage(argv[0]); } @@ -460,6 +474,7 @@ int main(int argc, char *argv[]) umem_mgr_release(umem_mgr); uclock_release(uclock); upipe_mgr_release(udp_sink_mgr); + upipe_mgr_release(rtpd_mgr); return 0; } From a8c9dbddce44ee626f8eafda59309ed32e553271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Mar 2024 09:59:56 +0100 Subject: [PATCH 111/231] srth: be less verbose when a packet arrives for another stream It happens when remote reconnects --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 60a0dac50..782468121 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1571,7 +1571,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); if (dst_socket_id && dst_socket_id != upipe_srt_handshake->socket_id) { - upipe_err_va(upipe, "0x%08x != 0x%08x", dst_socket_id, + upipe_dbg_va(upipe, "0x%08x != 0x%08x", dst_socket_id, upipe_srt_handshake->socket_id); ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); From 9d8169a2f297bde868702fa4aa4e17aab7dd1b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Mar 2024 10:00:37 +0100 Subject: [PATCH 112/231] srth: do not reset keepalive on induction packets We reject them if already connected This let us time out if remote fails and reconnects --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 782468121..578c40cff 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1579,7 +1579,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, } /* Only restart if timer is already alive, it means we're connected */ - if (upipe_srt_handshake->upump_keepalive_timeout) + if (upipe_srt_handshake->upump_keepalive_timeout && dst_socket_id == upipe_srt_handshake->socket_id) upipe_srt_handshake_restart_keepalive_timeout(upipe); if (srt_get_packet_control(buf)) { From 6542de6c0620b97ea74e52d3c1e97efeef864e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Mar 2024 10:01:50 +0100 Subject: [PATCH 113/231] srth: reject connection when already connected --- lib/upipe-srt/upipe_srt_handshake.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 578c40cff..13070312b 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1329,7 +1329,19 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (upipe_srt_handshake->upump_keepalive_timeout) { upipe_dbg(upipe, "Ignore handshake, already connected"); - return NULL; + + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + if (!uref) + return NULL; + + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); + uint8_t *out = &out_cif[-SRT_HEADER_SIZE]; + srt_set_packet_dst_socket_id(out, hs_packet.remote_socket_id); + + uref_block_unmap(uref, 0); + + return uref; } } From d1c89140849334c17bf4ba6f66f49e08a69c81e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Mar 2024 10:13:45 +0100 Subject: [PATCH 114/231] srth: sends handshake rejection when handshake fails --- lib/upipe-srt/upipe_srt_handshake.c | 50 ++++++++++++++++++----------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 13070312b..ac93b49b7 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1158,6 +1158,21 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_induction(struct upip return uref; } +static struct uref *upipe_srt_handshake_alloc_hs_reject(struct upipe *upipe, uint32_t timestamp, uint32_t dst_socket_id, uint32_t rejection_type) +{ + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + if (!uref) + return NULL; + + srt_set_handshake_type(out_cif, rejection_type); + uint8_t *out = &out_cif[-SRT_HEADER_SIZE]; + srt_set_packet_dst_socket_id(out, dst_socket_id); + + uref_block_unmap(uref, 0); + return uref; +} + static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upipe *upipe, int size, uint32_t timestamp, const struct hs_packet *hs_packet) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -1165,19 +1180,22 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->dst_socket_id != 0) { upipe_err_va(upipe, "Malformed conclusion handshake (dst_socket_id 0x%08x)", hs_packet->dst_socket_id); upipe_srt_handshake->expect_conclusion = false; - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie) { upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); upipe_srt_handshake->expect_conclusion = false; - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } /* At least HSREQ is expected */ if (hs_packet->version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { upipe_err(upipe, "Malformed conclusion handshake (size)"); upipe_srt_handshake->expect_conclusion = false; - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } upipe_srt_handshake->isn = hs_packet->isn; @@ -1319,29 +1337,21 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (conclusion) { if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } } else { if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } if (upipe_srt_handshake->upump_keepalive_timeout) { upipe_dbg(upipe, "Ignore handshake, already connected"); - uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); - if (!uref) - return NULL; - - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); - uint8_t *out = &out_cif[-SRT_HEADER_SIZE]; - srt_set_packet_dst_socket_id(out, hs_packet.remote_socket_id); - - uref_block_unmap(uref, 0); - - return uref; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } } @@ -1357,7 +1367,8 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } uref = upipe_srt_handshake_handle_hs_caller_induction(upipe, size, timestamp, &hs_packet); } @@ -1369,7 +1380,8 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin hs_packet.extension != SRT_HANDSHAKE_EXT_KMREQ || hs_packet.syn_cookie != 0 || hs_packet.dst_socket_id != 0) { upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", hs_packet.syn_cookie, hs_packet.dst_socket_id); - return NULL; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } uref = upipe_srt_handshake_handle_hs_listener_induction(upipe, size, timestamp, &hs_packet); From 7fad9cb0a3b65b6ad792258f4d37bb998e107b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Mar 2024 16:08:49 +0100 Subject: [PATCH 115/231] srth: sets version to last release (Sep 7, 2023) Future-proof --- lib/upipe-srt/upipe_srt_handshake.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index ac93b49b7..8e2c1e21c 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -408,9 +408,9 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, | SRT_HANDSHAKE_EXT_FLAG_REXMITFLG | SRT_HANDSHAKE_EXT_FLAG_TSBPDSND | SRT_HANDSHAKE_EXT_FLAG_TSBPDRCV | SRT_HANDSHAKE_EXT_FLAG_TLPKTDROP; /* made up version */ - upipe_srt_handshake->major = 2; - upipe_srt_handshake->minor = 2; - upipe_srt_handshake->patch = 2; + upipe_srt_handshake->major = 1; + upipe_srt_handshake->minor = 5; + upipe_srt_handshake->patch = 3; upipe_srt_handshake->socket_id = 0; From 213fda548169db7923d645590c4c9c7ff1ce70b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Mar 2024 10:02:20 +0000 Subject: [PATCH 116/231] srts: switch keys if the current one is absent This only happens on start if we don't provide both keys --- lib/upipe-srt/upipe_srt_sender.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index a29bb40b7..f5d6070c2 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -500,6 +500,9 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref } else { upipe_dbg(upipe, "Encryption disabled"); } + + if (!upipe_srt_sender->sek_len[!even_key] && upipe_srt_sender->sek_len[even_key]) + upipe_srt_sender->even_key = !even_key; #endif return uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF); From 2b10bf9bb6807f1346b4e27e0e38816ff8e644b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Mar 2024 10:05:59 +0000 Subject: [PATCH 117/231] srth: update keys one at a time --- lib/upipe-srt/upipe_srt_handshake.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 8e2c1e21c..798248224 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -112,7 +112,6 @@ struct upipe_srt_handshake { uint8_t sek[2][32]; uint8_t sek_len; uint8_t kk; - bool update_even; struct uref *kmreq; @@ -415,8 +414,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->socket_id = 0; upipe_srt_handshake->sek_len = 0; - upipe_srt_handshake->kk = 3; - upipe_srt_handshake->update_even = false; + upipe_srt_handshake->kk = 1; upipe_srt_handshake->kmreq = NULL; upipe_srt_handshake->password = NULL; @@ -603,7 +601,6 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, upipe_srt_handshake->sek_len = va_arg(args, int); free(upipe_srt_handshake->password); if (password) { - upipe_srt_handshake->kk = 3; upipe_srt_handshake->password = strdup(password); switch (upipe_srt_handshake->sek_len) { case 128/8: @@ -617,11 +614,11 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, if (upipe_srt_handshake->upump_keepalive_timeout) { /* already started */ #ifdef UPIPE_HAVE_GCRYPT_H // KM refresh - gcry_randomize(upipe_srt_handshake->sek[!upipe_srt_handshake->update_even], upipe_srt_handshake->sek_len, GCRY_STRONG_RANDOM); - upipe_srt_handshake->update_even = !upipe_srt_handshake->update_even; + gcry_randomize(upipe_srt_handshake->sek[upipe_srt_handshake->kk == 2], upipe_srt_handshake->sek_len, GCRY_STRONG_RANDOM); uint64_t now = uclock_now(upipe_srt_handshake->uclock); uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; + upipe_srt_handshake->kk = (upipe_srt_handshake->kk == 2) ? 1 : 2; struct uref *kmreq = upipe_srt_handshake_make_kmreq(upipe, timestamp); if (kmreq) { if (upipe_srt_handshake->kmreq) From 9000555d899c41b747fdb11e3d9733f8179ca146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Mar 2024 10:45:29 +0000 Subject: [PATCH 118/231] srts: wait 4000 packets before switching keys --- lib/upipe-srt/upipe_srt_sender.c | 49 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index f5d6070c2..6886809de 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -54,6 +54,8 @@ #define EXPECTED_FLOW_DEF "block." +#define SRT_KM_PRE_ANNOUNCEMENT_PERIOD 4000 // XXX: make configurable? + /** upipe_srt_sender structure */ struct upipe_srt_sender { /** real refcount management structure */ @@ -106,6 +108,8 @@ struct upipe_srt_sender { int even_key; + size_t packets_since_key; + uint64_t last_sent; /** public upipe structure */ @@ -489,20 +493,24 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref memcpy(upipe_srt_sender->sek[1], opaque.v, opaque.size); } - int even_key = !upipe_srt_sender->even_key; // switch key - upipe_srt_sender->even_key = even_key; - if (!upipe_srt_sender->sek_len[even_key] && upipe_srt_sender->sek_len[!even_key]) { - upipe_err_va(upipe, "Couldn't switch encryption keys: %s key is absent", - even_key ? "even" : "odd"); - upipe_srt_sender->even_key = !even_key; - } else if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { - upipe_dbg_va(upipe, "Switching to %s key", even_key ? "even" : "odd"); + int even_key = upipe_srt_sender->even_key; + if (upipe_srt_sender->sek_len[0] && upipe_srt_sender->sek_len[1]) + upipe_srt_sender->packets_since_key = 0; + else + upipe_srt_sender->packets_since_key = SRT_KM_PRE_ANNOUNCEMENT_PERIOD; + + if (!upipe_srt_sender->sek_len[!even_key] && upipe_srt_sender->sek_len[even_key]) { + upipe_err_va(upipe, "%s key is absent", even_key ? "even" : "odd"); + even_key = !even_key; + } + + if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { + upipe_dbg_va(upipe, "Using %s key", even_key ? "even" : "odd"); } else { upipe_dbg(upipe, "Encryption disabled"); } - if (!upipe_srt_sender->sek_len[!even_key] && upipe_srt_sender->sek_len[even_key]) - upipe_srt_sender->even_key = !even_key; + upipe_srt_sender->even_key = even_key; #endif return uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF); @@ -591,7 +599,8 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->sek_len[0] = 0; upipe_srt_sender->sek_len[1] = 0; - upipe_srt_sender->even_key = false; + upipe_srt_sender->even_key = true; + upipe_srt_sender->packets_since_key = 0; upipe_srt_sender->last_sent = 0; @@ -653,6 +662,24 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref srt_set_data_packet_retransmit(buf, false); #ifdef UPIPE_HAVE_GCRYPT_H + if (++upipe_srt_sender->packets_since_key == SRT_KM_PRE_ANNOUNCEMENT_PERIOD) { + int even_key = !upipe_srt_sender->even_key; + + if (!upipe_srt_sender->sek_len[!even_key] && upipe_srt_sender->sek_len[even_key]) { + upipe_err_va(upipe, "Couldn't switch encryption keys: %s key is absent", + even_key ? "even" : "odd"); + even_key = !even_key; + } + + if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { + upipe_dbg_va(upipe, "Switching to %s key", even_key ? "even" : "odd"); + } else { + upipe_dbg(upipe, "Encryption disabled"); + } + + upipe_srt_sender->even_key = even_key; + } + int key = !upipe_srt_sender->even_key; if (upipe_srt_sender->sek_len[key]) { // From 8b67f66fc7c56fc58550238228f865ead342fa7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Mar 2024 13:14:18 +0000 Subject: [PATCH 119/231] rist_tx: refresh key after 2^25 packets --- examples/rist_tx.c | 48 ++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 7793a4133..3bb898e55 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -53,6 +53,7 @@ #include "upipe/upipe.h" #include "upipe-modules/upipe_udp_source.h" #include "upipe-modules/upipe_udp_sink.h" +#include "upipe-modules/upipe_probe_uref.h" #include "upipe-srt/upipe_srt_sender.h" #include "upipe-srt/upipe_srt_handshake.h" @@ -102,6 +103,9 @@ static struct uprobe *logger; static bool restart = true; +static size_t packets = 0; +static const size_t km_refresh_period = 1 << 25; + static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) { uint16_t port = 0; @@ -143,6 +147,26 @@ static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, return uprobe_throw_next(uprobe, upipe, event, args); } +/** definition of our uprobe */ +static int catch_uref(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + case UPROBE_PROBE_UREF: + UBASE_SIGNATURE_CHECK(args, UPIPE_PROBE_UREF_SIGNATURE); + //struct uref *uref = va_arg(args, struct uref *); + + if (packets++ == km_refresh_period) { + packets = 0; + if (upipe_srt_handshake) + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + } + + return UBASE_ERR_NONE; + } + return uprobe_throw_next(uprobe, upipe, event, args); +} + /** definition of our uprobe */ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) @@ -180,6 +204,7 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, static int start(void) { + packets = 0; static unsigned z = 0; z++; @@ -227,8 +252,13 @@ static int start(void) upipe_release(upipe_srt_sender_sub); /* send to udp */ + + struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); + struct upipe *upipe = upipe_void_chain_output(upipe_srt_sender, upipe_probe_uref_mgr, + uprobe_pfx_alloc_va(uprobe_alloc(catch_uref, uprobe_use(logger)), loglevel, "probe %u", z)); + struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); - upipe_udpsink = upipe_void_chain_output(upipe_srt_sender, upipe_udpsink_mgr, + upipe_udpsink = upipe_void_chain_output(upipe, upipe_udpsink_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp sink %u", z)); upipe_release(upipe_udpsink); @@ -265,16 +295,6 @@ static int start(void) return 0; } -static void kmrefresh(struct upump *upump) -{ - if (upipe_srt_handshake) - upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); - else { - upump_stop(upump); - upump_free(upump); - } -} - static void stop(struct upump *upump) { if (upump) { @@ -373,12 +393,6 @@ int main(int argc, char *argv[]) if (ret) return ret; - if (1) { - struct upump *u = upump_alloc_timer(upump_mgr, kmrefresh, NULL, - NULL, 5*UCLOCK_FREQ, 5*UCLOCK_FREQ); - upump_start(u); - } - if (0) { restart = false; //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); From 32c59fa3a61da149303e395b63affb256c5ec0b3 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 16 Mar 2024 00:14:06 +0000 Subject: [PATCH 120/231] upipe-srt/receiver: Free late packet --- lib/upipe-srt/upipe_srt_receiver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 07ae8a76b..baff97f84 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1322,6 +1322,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, // XXX : when much too late, it could mean RTP source restart upipe_err_va(upipe, "LATE packet %u, dropped (buffered %"PRIu64" -> %"PRIu64")", seqnum, first_seq, last_seq); + uref_free(uref); } /** @This frees a upipe. From 2d0656f5bfcd480435ac704238b5825945cfb3a6 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 20 Mar 2024 00:26:30 +0000 Subject: [PATCH 121/231] srth: Rename upump_timer to upump_handshake_send Makes it easier to understand which timer does what --- lib/upipe-srt/upipe_srt_handshake.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 798248224..9d5958031 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -65,7 +65,7 @@ struct upipe_srt_handshake { struct urefcount urefcount; struct upump_mgr *upump_mgr; - struct upump *upump_timer; /* send handshakes every 250ms until connected */ + struct upump *upump_handshake_send; /* send handshakes every 250ms until connected */ struct upump *upump_handshake_timeout; /* abort connection if not successful */ struct upump *upump_keepalive_timeout; /* reset connection if no keep alive in 10s */ struct upump *upump_kmreq; /* re-send key update if not acknowledged */ @@ -140,7 +140,7 @@ UPIPE_HELPER_VOID(upipe_srt_handshake) UPIPE_HELPER_OUTPUT(upipe_srt_handshake, output, flow_def, output_state, request_list) UPIPE_HELPER_UPUMP_MGR(upipe_srt_handshake, upump_mgr) -UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_timer, upump_mgr) +UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_handshake_send, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_handshake_timeout, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_keepalive_timeout, upump_mgr) UPIPE_HELPER_UPUMP(upipe_srt_handshake, upump_kmreq, upump_mgr) @@ -216,7 +216,7 @@ static void upipe_srt_handshake_shutdown(struct upipe *upipe) uref_block_unmap(uref, 0); upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, - &upipe_srt_handshake->upump_timer); + &upipe_srt_handshake->upump_handshake_send); } @@ -341,7 +341,7 @@ static void upipe_srt_handshake_timer(struct upump *upump) uref_block_unmap(uref, 0); upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, - &upipe_srt_handshake->upump_timer); + &upipe_srt_handshake->upump_handshake_send); upipe_srt_handshake->last_hs_sent = now; } @@ -380,7 +380,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake_init_output(upipe); upipe_srt_handshake_init_upump_mgr(upipe); - upipe_srt_handshake_init_upump_timer(upipe); + upipe_srt_handshake_init_upump_handshake_send(upipe); upipe_srt_handshake_init_upump_handshake_timeout(upipe); upipe_srt_handshake_init_upump_keepalive_timeout(upipe); upipe_srt_handshake_init_upump_kmreq(upipe); @@ -455,7 +455,7 @@ static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_form return UBASE_ERR_NONE; } - if (upipe_srt_handshake->upump_mgr && !upipe_srt_handshake->upump_keepalive_timeout && !upipe_srt_handshake->upump_timer && !upipe_srt_handshake->listener) { + if (upipe_srt_handshake->upump_mgr && !upipe_srt_handshake->upump_keepalive_timeout && !upipe_srt_handshake->upump_handshake_send && !upipe_srt_handshake->listener) { upipe_srt_handshake->socket_id = mrand48(); upipe_srt_handshake->syn_cookie = 0; struct upump *upump = @@ -464,7 +464,7 @@ static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_form upipe, upipe->refcount, UCLOCK_FREQ/300, UCLOCK_FREQ/300); upump_start(upump); - upipe_srt_handshake_set_upump_timer(upipe, upump); + upipe_srt_handshake_set_upump_handshake_send(upipe, upump); } return UBASE_ERR_NONE; @@ -568,7 +568,7 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, switch (command) { case UPIPE_ATTACH_UPUMP_MGR: - upipe_srt_handshake_set_upump_timer(upipe, NULL); + upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); upipe_srt_handshake_set_upump_kmreq(upipe, NULL); @@ -1049,7 +1049,7 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_conclusion(struct upipe { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - upipe_srt_handshake_set_upump_timer(upipe, NULL); + upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); upipe_srt_handshake->remote_socket_id = hs_packet->remote_socket_id; /* At least HSREQ is expected */ @@ -1646,7 +1646,7 @@ static void upipe_srt_handshake_free(struct upipe *upipe) uref_free(upipe_srt_handshake->kmreq); upipe_srt_handshake_clean_output(upipe); - upipe_srt_handshake_clean_upump_timer(upipe); + upipe_srt_handshake_clean_upump_handshake_send(upipe); upipe_srt_handshake_clean_upump_handshake_timeout(upipe); upipe_srt_handshake_clean_upump_keepalive_timeout(upipe); upipe_srt_handshake_clean_upump_kmreq(upipe); From 0a5b9ea092312b90b53f7c278b04c91fc81377fe Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 20 Mar 2024 00:47:20 +0000 Subject: [PATCH 122/231] srth: Rename upipe_srt_handshake_timer to upipe_srt_handshake_send_timer --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 9d5958031..6794e1965 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -315,7 +315,7 @@ static void upipe_srt_handshake_timeout(struct upump *upump) upipe_srt_handshake->expect_conclusion = false; } -static void upipe_srt_handshake_timer(struct upump *upump) +static void upipe_srt_handshake_send_timer(struct upump *upump) { struct upipe *upipe = upump_get_opaque(upump, struct upipe *); struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -460,7 +460,7 @@ static int upipe_srt_handshake_check(struct upipe *upipe, struct uref *flow_form upipe_srt_handshake->syn_cookie = 0; struct upump *upump = upump_alloc_timer(upipe_srt_handshake->upump_mgr, - upipe_srt_handshake_timer, + upipe_srt_handshake_send_timer, upipe, upipe->refcount, UCLOCK_FREQ/300, UCLOCK_FREQ/300); upump_start(upump); From b0aa9c475ffd11e3556d180c735341e259e89fa4 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 20 Mar 2024 16:52:50 +0000 Subject: [PATCH 123/231] srth: Don't send a rejection if we get a duplicate induction --- lib/upipe-srt/upipe_srt_handshake.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 6794e1965..0ddab3335 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1332,10 +1332,10 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin bool conclusion = upipe_srt_handshake->expect_conclusion; if (conclusion) { + /* Don't send a rejection as it could be a duplicate Induction on a long latency link */ if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { - upipe_err_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); - return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, - hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); + upipe_dbg_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); + return NULL; } } else { if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { From 798a62b2a12460a5e26c4f36be3024704ab6be98 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 20 Mar 2024 17:06:29 +0000 Subject: [PATCH 124/231] srts: Make the establish_time more rigourous. It worked by chance last time because the first uref had a timestamp of 0 and that happened to correspond with the now being equal 0 and thus the check was skipped --- lib/upipe-srt/upipe_srt_sender.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 6886809de..701136ba0 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -203,10 +203,9 @@ static void upipe_srt_sender_input_sub(struct upipe *upipe, struct uref *uref, uref_block_unmap(uref, 0); uref_free(uref); } else { - if (type == SRT_CONTROL_TYPE_HANDSHAKE) { + if (type == SRT_CONTROL_TYPE_HANDSHAKE && upipe_srt_sender->establish_time == 0 && now > 0) { uint64_t ts = srt_get_packet_timestamp(buf); - if (ts) - upipe_srt_sender->establish_time = now - ts * UCLOCK_FREQ / 1000000; + upipe_srt_sender->establish_time = now - ts * UCLOCK_FREQ / 1000000; } uref_block_unmap(uref, 0); @@ -595,6 +594,7 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->latency = UCLOCK_FREQ; /* 1 sec */ upipe_srt_sender->socket_id = 0; upipe_srt_sender->seqnum = 0; + upipe_srt_sender->establish_time = 0; upipe_srt_sender->syn_cookie = 1; upipe_srt_sender->sek_len[0] = 0; From 8a554032d7e42da980cbc84f69fdf86090b35a5c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 20 Mar 2024 17:44:03 +0000 Subject: [PATCH 125/231] rist_tx: Add SRT stream_id --- examples/rist_tx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 3bb898e55..3c42f5ce6 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -76,6 +76,7 @@ static void usage(const char *argv0) { fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); fprintf(stdout, " -k encryption password\n"); + fprintf(stdout, " -i stream_id\n"); fprintf(stdout, " -l key length in bits\n"); exit(EXIT_FAILURE); } @@ -95,6 +96,7 @@ static char *srcpath; static char *dirpath; static char *latency; static char *password; +static char *stream_id; static int key_length = 128; static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; @@ -240,6 +242,8 @@ static int start(void) if (!ubase_check(upipe_set_option(upipe_srt_handshake, "latency", latency))) return EXIT_FAILURE; upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + if (stream_id) + upipe_set_option(upipe_srt_handshake, "stream_id", stream_id); upipe_mgr_release(upipe_srt_handshake_mgr); @@ -331,7 +335,7 @@ int main(int argc, char *argv[]) int opt; /* parse options */ - while ((opt = getopt(argc, argv, "qdk:l:")) != -1) { + while ((opt = getopt(argc, argv, "qdk:i:l:")) != -1) { switch (opt) { case 'q': loglevel++; @@ -343,6 +347,9 @@ int main(int argc, char *argv[]) case 'k': password = optarg; break; + case 'i': + stream_id = optarg; + break; case 'l': key_length = atoi(optarg); break; From 9f55d31ce71578dadb06645574d88bcb95050d90 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 20 Mar 2024 17:55:15 +0000 Subject: [PATCH 126/231] srth: When repeating the handshake, send the correct handshake packet, don't repeat an induction --- lib/upipe-srt/upipe_srt_handshake.c | 66 +++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 0ddab3335..34c2f261a 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -121,6 +121,7 @@ struct upipe_srt_handshake { uint64_t establish_time; bool expect_conclusion; + struct uref *caller_conclusion; bool listener; @@ -321,27 +322,54 @@ static void upipe_srt_handshake_send_timer(struct upump *upump) struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); uint64_t now = uclock_now(upipe_srt_handshake->uclock); + if (!upipe_srt_handshake->establish_time) + upipe_srt_handshake->establish_time = now; + uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; /* 250 ms between handshakes, just like libsrt */ if (now - upipe_srt_handshake->last_hs_sent < UCLOCK_FREQ / 4) return; - //send HS - uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, 0, &out_cif); - if (!uref) - return; + if (upipe_srt_handshake->expect_conclusion) { + if (upipe_srt_handshake->caller_conclusion) { + struct uref *uref = uref_dup(upipe_srt_handshake->caller_conclusion); + /* copy because we need to rewrite the timestamp */ + struct ubuf *ubuf = ubuf_block_copy(uref->ubuf->mgr, uref->ubuf, 0, -1); + if (!ubuf) { + upipe_err_va(upipe, "Malloc failed"); + return; + } + uref_attach_ubuf(uref, ubuf); - upipe_srt_handshake->establish_time = now; + uint8_t *out; + int output_size = -1; + if (unlikely(!ubase_check(uref_block_write(uref, 0, &output_size, &out)))) { + uref_free(uref); + upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); + return; + } + srt_set_packet_timestamp(out, timestamp); + uref_block_unmap(uref, 0); - srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); // XXX - srt_set_handshake_extension(out_cif, SRT_HANDSHAKE_EXT_KMREQ); // draft-sharabayko-srt-01#section-4.3.1.1 * Extension Field: 2 - srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, + &upipe_srt_handshake->upump_handshake_send); + } + } else { + //send HS + uint8_t *out_cif; + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + if (!uref) + return; - uref_block_unmap(uref, 0); + srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); // XXX + srt_set_handshake_extension(out_cif, SRT_HANDSHAKE_EXT_KMREQ); // draft-sharabayko-srt-01#section-4.3.1.1 * Extension Field: 2 + srt_set_handshake_type(out_cif, SRT_HANDSHAKE_TYPE_INDUCTION); - upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, - &upipe_srt_handshake->upump_handshake_send); + uref_block_unmap(uref, 0); + + upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref, + &upipe_srt_handshake->upump_handshake_send); + } upipe_srt_handshake->last_hs_sent = now; } @@ -397,6 +425,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->last_hs_sent = 0; upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake->caller_conclusion = NULL; upipe_srt_handshake->stream_id = NULL; upipe_srt_handshake->stream_id_len = 0; @@ -418,6 +447,8 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->kmreq = NULL; upipe_srt_handshake->password = NULL; + upipe_srt_handshake->establish_time = 0; + upipe_throw_ready(upipe); return upipe; } @@ -1360,6 +1391,11 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (!upipe_srt_handshake->listener) { if (conclusion) { uref = upipe_srt_handshake_handle_hs_caller_conclusion(upipe, size, timestamp, &hs_packet); + /* We don't need the cached conclusion packet any more */ + if (upipe_srt_handshake->caller_conclusion) { + uref_free(upipe_srt_handshake->caller_conclusion); + upipe_srt_handshake->caller_conclusion = NULL; + } } else { if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", @@ -1368,6 +1404,9 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } uref = upipe_srt_handshake_handle_hs_caller_induction(upipe, size, timestamp, &hs_packet); + if (upipe_srt_handshake->caller_conclusion) + uref_free(upipe_srt_handshake->caller_conclusion); + upipe_srt_handshake->caller_conclusion = uref_dup(uref); } } else { /* listener */ if (conclusion) { @@ -1645,6 +1684,9 @@ static void upipe_srt_handshake_free(struct upipe *upipe) if (upipe_srt_handshake->kmreq) uref_free(upipe_srt_handshake->kmreq); + if (upipe_srt_handshake->caller_conclusion) + uref_free(upipe_srt_handshake->caller_conclusion); + upipe_srt_handshake_clean_output(upipe); upipe_srt_handshake_clean_upump_handshake_send(upipe); upipe_srt_handshake_clean_upump_handshake_timeout(upipe); From a0a808a353aeaf4dc23bac25d5cb8b40688f913f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Mar 2024 09:22:13 +0100 Subject: [PATCH 127/231] srth: whitespace --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 34c2f261a..0fefb3e80 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -334,7 +334,7 @@ static void upipe_srt_handshake_send_timer(struct upump *upump) if (upipe_srt_handshake->caller_conclusion) { struct uref *uref = uref_dup(upipe_srt_handshake->caller_conclusion); /* copy because we need to rewrite the timestamp */ - struct ubuf *ubuf = ubuf_block_copy(uref->ubuf->mgr, uref->ubuf, 0, -1); + struct ubuf *ubuf = ubuf_block_copy(uref->ubuf->mgr, uref->ubuf, 0, -1); if (!ubuf) { upipe_err_va(upipe, "Malloc failed"); return; @@ -359,7 +359,7 @@ static void upipe_srt_handshake_send_timer(struct upump *upump) uint8_t *out_cif; struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); if (!uref) - return; + return; srt_set_handshake_version(out_cif, SRT_HANDSHAKE_VERSION_MIN); // XXX srt_set_handshake_extension(out_cif, SRT_HANDSHAKE_EXT_KMREQ); // draft-sharabayko-srt-01#section-4.3.1.1 * Extension Field: 2 From 139675702d58d514ffd31e96bfa4b697a8d1fbe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Mar 2024 15:24:53 +0100 Subject: [PATCH 128/231] srth: ignore handshakes packets when we're connected Avoid mistreating duplicate conclusion packet --- lib/upipe-srt/upipe_srt_handshake.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 0fefb3e80..8de2c7ced 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1360,6 +1360,11 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } + if (upipe_srt_handshake->upump_keepalive_timeout && hs_packet.dst_socket_id == upipe_srt_handshake->socket_id) { + upipe_dbg_va(upipe, "Already connected, ignoring hs type 0x%x", hs_type); + return NULL; + } + bool conclusion = upipe_srt_handshake->expect_conclusion; if (conclusion) { From 1f89867d4f3183cd495944b25e02e4ea187447c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 21 Mar 2024 15:25:54 +0100 Subject: [PATCH 129/231] Revert "Test my bitstream" This reverts commit 839399ae8a0c014d82f868c4b9a3bbb3b8da64f1. --- .github/workflows/test-suite.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-suite.yaml b/.github/workflows/test-suite.yaml index 53a4fe49e..dbe2466a0 100644 --- a/.github/workflows/test-suite.yaml +++ b/.github/workflows/test-suite.yaml @@ -150,7 +150,7 @@ jobs: - name: Install bitstream run: | - git clone --depth 1 https://github.com/funman/bitstream + git clone --depth 1 https://code.videolan.org/videolan/bitstream.git make -C bitstream install PREFIX="$PWD/usr-bitstream" set-env PKG_CONFIG_PATH "$PKG_CONFIG_PATH:$PWD/usr-bitstream/share/pkgconfig" if [ "${{ matrix.static }}" = "true" ]; then From 0320e3f1b434f64c7f995e53fa952d88eefe644d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 10:45:30 +0100 Subject: [PATCH 130/231] rist_tx: set flow def for srt sender This lets us handshake even if we don't have a source This fixes: debug: [srt handshake 1] [listener] got induction handshake packet debug: [srt handshake 1] Expected conclusion, ignore hs type 0x1 debug: [srt handshake 1] Expected conclusion, ignore hs type 0x1 --- examples/rist_tx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/rist_tx.c b/examples/rist_tx.c index 3c42f5ce6..b3c6c254e 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -296,6 +296,11 @@ static int start(void) upipe_srt_handshake_set_peer(upipe_srt_handshake, peer, peer_len); } + struct uref *flow_def = uref_alloc_control(uref_mgr); + uref_flow_set_def(flow_def, "block."); + upipe_set_flow_def(upipe_srt_sender, flow_def); + uref_free(flow_def); + return 0; } From 15e3534afd7686d6573114f959e29d115fabead4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 11:29:56 +0100 Subject: [PATCH 131/231] srth: no need to update flow def immediately --- lib/upipe-srt/upipe_srt_handshake.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 8de2c7ced..9ca51761d 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -525,8 +525,6 @@ static int upipe_srt_handshake_set_flow_def(struct upipe *upipe, struct uref *fl return UBASE_ERR_ALLOC; upipe_srt_handshake_store_flow_def(upipe, flow_def); - /* force sending flow definition immediately */ - upipe_srt_handshake_output(upipe, NULL, NULL); return UBASE_ERR_NONE; } @@ -798,8 +796,6 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); - /* force sending flow definition immediately */ - upipe_srt_handshake_output(upipe, NULL, NULL); } } } From dc46561589b01ff34b93f10890616fdbd1bc99be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 11:31:12 +0100 Subject: [PATCH 132/231] srts: unused syn_cookie --- lib/upipe-srt/upipe_srt_sender.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 701136ba0..2ef30fd7c 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -93,7 +93,6 @@ struct upipe_srt_sender { /** list of output requests */ struct uchain request_list; - uint32_t syn_cookie; uint32_t socket_id; uint32_t seqnum; @@ -595,7 +594,6 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->socket_id = 0; upipe_srt_sender->seqnum = 0; upipe_srt_sender->establish_time = 0; - upipe_srt_sender->syn_cookie = 1; upipe_srt_sender->sek_len[0] = 0; upipe_srt_sender->sek_len[1] = 0; From bbe7fd093be084169523a20e5cb205ca97fa08b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 11:33:18 +0100 Subject: [PATCH 133/231] srts: better debug log Do not complain about lack of encryption when doing handshake --- lib/upipe-srt/upipe_srt_sender.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 2ef30fd7c..3cdd7415d 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -505,7 +505,8 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { upipe_dbg_va(upipe, "Using %s key", even_key ? "even" : "odd"); } else { - upipe_dbg(upipe, "Encryption disabled"); + if (upipe_srt_sender->socket_id) + upipe_dbg(upipe, "No encryption key in handshake"); } upipe_srt_sender->even_key = even_key; From ce580967b1a2f7e105bf33cc74ffd9e1f0c280be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 11:40:23 +0100 Subject: [PATCH 134/231] srth: fix stream_id copy --- lib/upipe-srt/upipe_srt_handshake.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 9ca51761d..68064a376 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -546,13 +546,14 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio free(upipe_srt_handshake->stream_id); upipe_srt_handshake->stream_id = NULL; - size_t stream_id_len = (strlen(value) + 3) & ~3; // round up to 4 bytes - uint8_t *stream_id = malloc(stream_id_len); + size_t src_len = strlen(value); + size_t stream_id_len = (src_len + 3) & ~3; // round up to 4 bytes + uint8_t *stream_id = calloc(1, stream_id_len); if (!stream_id) { return UBASE_ERR_ALLOC; } - strncpy((char*)stream_id, value, stream_id_len); + strncpy((char*)stream_id, value, src_len); for (size_t i = 0; i < stream_id_len; i += 4) { uint8_t tmp = stream_id[i+0]; From 0c6c1f018da34defa10a188d20ab8e46769629da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 13:33:49 +0100 Subject: [PATCH 135/231] srtr: always advertise full buffer capacity Fix deadlock when we reach 0 packets per second --- lib/upipe-srt/upipe_srt_receiver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index baff97f84..2bbbe5783 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -515,7 +515,8 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uint64_t packets_per_sec = upipe_srt_receiver->packets * UCLOCK_FREQ / t; srt_set_ack_packets_receiving_rate(out_cif, packets_per_sec); - srt_set_ack_avail_bufsize(out_cif, packets_per_sec * upipe_srt_receiver->latency / UCLOCK_FREQ); + /* If we sent value 0, libsrt will stop sending */ + srt_set_ack_avail_bufsize(out_cif, 8192); srt_set_ack_estimated_link_capacity(out_cif, 10 * packets_per_sec); /* ? */ srt_set_ack_receiving_rate(out_cif, upipe_srt_receiver->bytes * UCLOCK_FREQ / t); From d502bd45a8b074b3972f1e1adfcce884e627b6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 15:49:40 +0100 Subject: [PATCH 136/231] upipe_srt_handshake_parse_kmreq: less verbose Only show a warning if password was not set Do not complain about malformed KMREQ in this case --- lib/upipe-srt/upipe_srt_handshake.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 68064a376..68b47da54 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -826,11 +826,16 @@ static void upipe_srt_handshake_parse_hsreq(struct upipe *upipe, const uint8_t * upipe_srt_handshake->receiver_tsbpd_delay, upipe_srt_handshake->sender_tsbpd_delay); } -static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, const uint8_t **wrap, uint8_t *wrap_len) +static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, const size_t ext_len, const uint8_t **wrap, uint8_t *wrap_len) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); + if (!srt_check_km(ext, ext_len)) { + upipe_err(upipe, "Malformed KMREQ"); + return false; + } + if (!upipe_srt_handshake->password) { - upipe_err(upipe, "Password not set"); + upipe_warn(upipe, "Received a Key Message, but passphrase was not set"); return false; } @@ -1249,8 +1254,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, SRT_HANDSHAKE_HSREQ_SIZE); } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { - if (!srt_check_km(ext, ext_len) || !upipe_srt_handshake_parse_kmreq(upipe, ext, &wrap, &wrap_len)) - upipe_err(upipe, "Malformed KMREQ"); + upipe_srt_handshake_parse_kmreq(upipe, ext, ext_len, &wrap, &wrap_len); } ext += ext_len; @@ -1465,8 +1469,7 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u const uint8_t *cif = srt_get_control_packet_cif(buf); size -= SRT_HEADER_SIZE; - if (!srt_check_km(cif, size) || !upipe_srt_handshake_parse_kmreq(upipe, cif, &wrap, &wrap_len)) { - upipe_err_va(upipe, "KM parse failed"); + if (!upipe_srt_handshake_parse_kmreq(upipe, cif, size, &wrap, &wrap_len)) { return NULL; } From 66993f963454b1fc5096cc48ed991055cb3c6292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 16:25:36 +0100 Subject: [PATCH 137/231] rist_rx: send shutdown on ^C --- examples/rist_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 4709bec14..4ae1c8dbb 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -288,8 +288,8 @@ static void stop(struct upump *upump) upump_free(upump); } - upipe_release(upipe_srtr_sub); upipe_release(upipe_udpsrc); + upipe_release(upipe_srtr_sub); if (restart) { restart = false; From bdc5bfc587eb5190cab2356c8ae42685e1e47135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 16:39:47 +0100 Subject: [PATCH 138/231] srth: no need for strncpy --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 68b47da54..aff5ccc89 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -553,7 +553,7 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio return UBASE_ERR_ALLOC; } - strncpy((char*)stream_id, value, src_len); + memcpy(stream_id, value, src_len); for (size_t i = 0; i < stream_id_len; i += 4) { uint8_t tmp = stream_id[i+0]; From 988e16c153467c845f05b4c6104133477cea23dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Mar 2024 16:49:18 +0100 Subject: [PATCH 139/231] srtr: use proper timestamps --- lib/upipe-srt/upipe_srt_receiver.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 2bbbe5783..8bc62d97c 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -149,6 +149,8 @@ struct upipe_srt_receiver { uint8_t sek[2][32]; uint8_t sek_len; + uint64_t establish_time; + /** public upipe structure */ struct upipe upipe; }; @@ -355,7 +357,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) } srt_set_packet_control(out, true); - srt_set_packet_timestamp(out, now / 27); + srt_set_packet_timestamp(out, (now - upipe_srt_receiver->establish_time) / 27); srt_set_packet_dst_socket_id(out, upipe_srt_receiver->socket_id); srt_set_control_packet_type(out, SRT_CONTROL_TYPE_KEEPALIVE); srt_set_control_packet_subtype(out, 0); @@ -440,7 +442,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) s -= SRT_HEADER_SIZE; srt_set_packet_control(buf, true); - srt_set_packet_timestamp(buf, now / 27); + srt_set_packet_timestamp(buf, (now - upipe_srt_receiver->establish_time) / 27); srt_set_packet_dst_socket_id(buf, upipe_srt_receiver->socket_id); srt_set_control_packet_type(buf, SRT_CONTROL_TYPE_NAK); srt_set_control_packet_subtype(buf, 0); @@ -497,7 +499,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) } else { uint32_t ack_num = upipe_srt_receiver->ack_num++; srt_set_packet_control(out, true); - srt_set_packet_timestamp(out, now / 27); + srt_set_packet_timestamp(out, (now - upipe_srt_receiver->establish_time) / 27); srt_set_packet_dst_socket_id(out, upipe_srt_receiver->socket_id); srt_set_control_packet_type(out, SRT_CONTROL_TYPE_ACK); srt_set_control_packet_subtype(out, 0); @@ -779,6 +781,8 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->sek_len = 0; + upipe_srt_receiver->establish_time = 0; + upipe_throw_ready(upipe); return upipe; } @@ -1179,6 +1183,12 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); } else { + + if (type == SRT_CONTROL_TYPE_HANDSHAKE && upipe_srt_receiver->establish_time == 0 && now > 0) { + uint64_t ts = srt_get_packet_timestamp(buf); + upipe_srt_receiver->establish_time = now - ts * UCLOCK_FREQ / 1000000; + } + ubase_assert(uref_block_unmap(uref, 0)); if (upipe_srt_receiver->control) { upipe_srt_receiver->last_sent = now; From e893280ec300750ad13dc89405895eed58f5c87d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 28 Mar 2024 09:28:34 +0100 Subject: [PATCH 140/231] Partially revert 15e3534afd7686d6573114f959e29d115fabead4 This broke sender in caller mode --- lib/upipe-srt/upipe_srt_handshake.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index aff5ccc89..f095595a4 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -797,6 +797,8 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); + /* force sending flow definition immediately */ + upipe_srt_handshake_output(upipe, NULL, NULL); } } } From cccf639f74854c4aa365184a825eb0a0b5978b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 28 Mar 2024 09:30:14 +0100 Subject: [PATCH 141/231] Remove left over SRT changes --- lib/upipe-modules/Makefile.am | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/upipe-modules/Makefile.am b/lib/upipe-modules/Makefile.am index 46a01a3dd..86d95e8fa 100644 --- a/lib/upipe-modules/Makefile.am +++ b/lib/upipe-modules/Makefile.am @@ -110,11 +110,6 @@ endif libupipe_modules_la_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include libupipe_modules_la_LIBADD = -lm $(top_builddir)/lib/upipe/libupipe.la -if HAVE_GCRYPT -libupipe_modules_la_CPPFLAGS += $(GCRYPT_CFLAGS) -libupipe_modules_la_LIBADD += $(GCRYPT_LIBS) -endif - libupipe_modules_la_LDFLAGS = -no-undefined pkgconfigdir = $(libdir)/pkgconfig From a413adb95206b22f94617793e9e1d03f2725cfeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 28 Mar 2024 09:30:43 +0100 Subject: [PATCH 142/231] upipe-srt does not depend on libsrt --- include/Makefile.am | 5 +++-- lib/upipe-srt/Makefile.am | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/Makefile.am b/include/Makefile.am index 72ce21d80..adffeb3e8 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,7 +2,8 @@ SUBDIRS = \ upipe \ upipe-modules \ upipe-filters \ - upipe-dveo + upipe-dveo \ + upipe-srt if HAVE_QTWEBKIT SUBDIRS += upipe-qt @@ -105,5 +106,5 @@ SUBDIRS += upipe-bearssl endif if HAVE_SRT -SUBDIRS += upump-srt upipe-srt +SUBDIRS += upump-srt endif diff --git a/lib/upipe-srt/Makefile.am b/lib/upipe-srt/Makefile.am index 2c2d653c8..fa41efe98 100644 --- a/lib/upipe-srt/Makefile.am +++ b/lib/upipe-srt/Makefile.am @@ -5,8 +5,8 @@ libupipe_srt_la_SOURCES = upipe_srt_handshake.c \ upipe_srt_receiver.c libupipe_srt_la_CPPFLAGS = -I$(top_builddir) -I$(top_builddir)/include -I$(top_srcdir)/include -libupipe_srt_la_CFLAGS = $(AM_CFLAGS) $(SRT_FLAGS) $(BITSTREAM_CFLAGS) -libupipe_srt_la_LIBADD = $(top_builddir)/lib/upipe/libupipe.la $(SRT_LIBS) +libupipe_srt_la_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) +libupipe_srt_la_LIBADD = $(top_builddir)/lib/upipe/libupipe.la libupipe_srt_la_LDFLAGS = -no-undefined if HAVE_GCRYPT From cdab6be2fc6b4c3854ff2a9fae45f474b1794e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 28 Mar 2024 10:38:42 +0100 Subject: [PATCH 143/231] srt_tx/srt_rx Revert rist_tx / rist_rx changes --- examples/Makefile.am | 19 +- examples/rist_rx.c | 573 +++++++++++++++++++++---------------------- examples/rist_tx.c | 520 +++++++++++++++++++++------------------ examples/srt_rx.c | 480 ++++++++++++++++++++++++++++++++++++ examples/srt_tx.c | 438 +++++++++++++++++++++++++++++++++ 5 files changed, 1477 insertions(+), 553 deletions(-) create mode 100644 examples/srt_rx.c create mode 100644 examples/srt_tx.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 0f82687d0..5b7839148 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -24,10 +24,13 @@ UPIPESRT_LIBS = $(top_builddir)/lib/upipe-srt/libupipe_srt.la noinst_PROGRAMS = fec_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPETS_LIBS) -rist_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) -rist_rx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) +rist_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) +srt_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) +srt_rx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) +srt_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) +srt_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) rist_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) -rist_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) +rist_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) udpmulticat_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) multicatudp_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEPTHREAD_LIBS) -lpthread hls2rtp_LDADD= $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFRAMERS_LIBS) $(UPIPETS_LIBS) $(UPIPEHLS_LIBS) $(UPIPEPTHREAD_LIBS) -lpthread @@ -65,10 +68,10 @@ frame_LDADD = $(LDADD) $(UPIPEMODULES_LIBS) $(UPUMPEV_LIBS) $(UPIPEFRAMERS_LIBS) if HAVE_GCRYPT ts_encrypt_CFLAGS += $(GCRYPT_CFLAGS) ts_encrypt_LDADD += $(GCRYPT_LIBS) -rist_rx_CFLAGS += $(GCRYPT_CFLAGS) -rist_rx_LDADD += $(GCRYPT_LIBS) -rist_tx_CFLAGS += $(GCRYPT_CFLAGS) -rist_tx_LDADD += $(GCRYPT_LIBS) +srt_tx_CFLAGS += $(GCRYPT_CFLAGS) +srt_tx_LDADD += $(GCRYPT_LIBS) +srt_rx_CFLAGS += $(GCRYPT_CFLAGS) +srt_rx_LDADD += $(GCRYPT_LIBS) endif if HAVE_EV @@ -76,7 +79,7 @@ if HAVE_WRITEV noinst_PROGRAMS += udpmulticat multicatudp noinst_PROGRAMS += decrypt if HAVE_BITSTREAM -noinst_PROGRAMS += hls2rtp fec rist_rx rist_tx +noinst_PROGRAMS += hls2rtp fec rist_rx rist_tx srt_rx srt_tx endif endif diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 4ae1c8dbb..65520f552 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -24,11 +24,8 @@ * */ -#include - #undef NDEBUG #include "upipe/uprobe.h" -#include "upipe/upipe_dump.h" #include "upipe/uprobe_stdio.h" #include "upipe/uprobe_prefix.h" #include "upipe/uprobe_uref_mgr.h" @@ -50,20 +47,19 @@ #include "upipe/uuri.h" #include "upipe/ustring.h" #include "upipe/upipe.h" +#include "upipe-modules/upipe_dup.h" #include "upipe-modules/upipe_udp_source.h" -#include #include "upipe-modules/upipe_udp_sink.h" -#include "upipe-srt/upipe_srt_handshake.h" -#include "upipe-srt/upipe_srt_receiver.h" -#include "upipe/uprobe_helper_uprobe.h" -#include "upipe/uprobe_helper_alloc.h" - +#include "upipe-modules/upipe_probe_uref.h" +#include "upipe-filters/upipe_rtp_feedback.h" + +#include +#include +#include +#include +#include #include -#ifdef UPIPE_HAVE_GCRYPT_H -#include -#endif - #define UDICT_POOL_DEPTH 10 #define UREF_POOL_DEPTH 10 #define UBUF_POOL_DEPTH 10 @@ -71,305 +67,224 @@ #define UPUMP_BLOCKER_POOL 10 #define READ_SIZE 4096 - -/* structure */ -struct uprobe_obe_log { - struct urefcount urefcount; - struct uclock *uclock; - struct uprobe uprobe; - uint64_t start; - uatomic_uint32_t loglevel; -}; - -/* helper */ -UPROBE_HELPER_UPROBE(uprobe_obe_log, uprobe) - -/* alloc */ -struct uprobe *uprobe_obe_log_alloc(struct uprobe *next); - -static int uprobe_obe_log_throw(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) -{ - struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); - if (event != UPROBE_LOG) - return uprobe_throw_next(uprobe, upipe, event, args); - - va_list args_copy; - va_copy(args_copy, args); - struct ulog *ulog = va_arg(args_copy, struct ulog *); - - uint32_t loglevel = uatomic_load(&probe_obe_log->loglevel); - if (loglevel > ulog->level) - return UBASE_ERR_NONE; - - char time_str[22]; - if (probe_obe_log->uclock) { - uint64_t t = uclock_now(probe_obe_log->uclock) - probe_obe_log->start; - snprintf(time_str, sizeof(time_str), "%.2f", (float)t / 27000.); - } else { - snprintf(time_str, sizeof(time_str), "?"); - } - struct ulog_pfx ulog_pfx = { - .tag = time_str, - }; - ulist_add(&ulog->prefixes, ulog_pfx_to_uchain(&ulog_pfx)); - - return uprobe_throw_next(uprobe, upipe, event, args); -} - -static void uprobe_obe_log_set_loglevel(struct uprobe *uprobe, int loglevel) -{ - struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); - uatomic_store(&probe_obe_log->loglevel, loglevel); -} - -static void uprobe_obe_log_set_uclock(struct uprobe *uprobe, struct uclock *uclock) -{ - struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); - uclock_release(probe_obe_log->uclock); - probe_obe_log->uclock = uclock_use(uclock); - probe_obe_log->start = uclock_now(uclock); -} - -static struct uprobe *uprobe_obe_log_init(struct uprobe_obe_log *probe_obe_log, - struct uprobe *next) -{ - struct uprobe *probe = uprobe_obe_log_to_uprobe(probe_obe_log); - probe_obe_log->uclock = NULL; - probe_obe_log->start = UINT64_MAX; - uatomic_init(&probe_obe_log->loglevel, UPROBE_LOG_DEBUG); - uprobe_init(probe, uprobe_obe_log_throw, next); - return probe; -} - -static void uprobe_obe_log_clean(struct uprobe_obe_log *probe_obe_log) -{ - uprobe_clean(uprobe_obe_log_to_uprobe(probe_obe_log)); - uclock_release(probe_obe_log->uclock); - uatomic_clean(&probe_obe_log->loglevel); -} - -#define ARGS_DECL struct uprobe *next -#define ARGS next -UPROBE_HELPER_ALLOC(uprobe_obe_log); -#undef ARGS -#undef ARGS_DECL - static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; static struct upipe_mgr *udp_sink_mgr; static struct upump_mgr *upump_mgr; +static struct upipe *upipe_rtpfb; +static struct upipe *upipe_rtpfb_sub; static struct upipe *upipe_udpsrc; -static struct upipe *upipe_udp_sink; -static struct upipe *upipe_srtr_sub; - -static struct uprobe uprobe_udp; -static struct uprobe uprobe_srt; -static struct uprobe *logger; - -static char *dirpath; -static char *srcpath; -static char *password; -static int key_length = 128; -static char *latency; +static struct upipe *upipe_udpsrc_rtcp; +static struct upipe *upipe_dup; + +struct rtcp_sink { + struct upipe *dup_sub; + struct sockaddr_storage addr; + socklen_t addr_len; + struct upump *timeout; +}; -static bool restart; +static struct rtcp_sink rtcp_sink[2]; -static struct upipe_mgr *rtpd_mgr; +static int udp_fd = -1; -static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) -{ - uint16_t port = 0; - switch(s->sa_family) { - case AF_INET: { - struct sockaddr_in *in = (struct sockaddr_in *)s; - inet_ntop(AF_INET, &in->sin_addr, uri, INET6_ADDRSTRLEN); - port = ntohs(in->sin_port); - break; - } - case AF_INET6: { - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; - inet_ntop(AF_INET6, &in6->sin6_addr, uri, INET6_ADDRSTRLEN); - port = ntohs(in6->sin6_port); - break; - } - default: - uri[0] = '\0'; - } - - size_t uri_len = strlen(uri); - sprintf(&uri[uri_len], ":%hu", port); +static void usage(const char *argv0) { + fprintf(stdout, "Usage: %s [-d] ", argv0); + fprintf(stdout, " -d: more verbose\n"); + fprintf(stdout, " -q: more quiet\n"); + exit(EXIT_FAILURE); } -static int start(void) +static void gather_stats(struct upipe *upipe, struct uref *uref) { - bool listener = srcpath && strchr(srcpath, '@'); - struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); - upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); - upipe_mgr_release(upipe_udpsrc_mgr); - - struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc); - struct upipe *upipe_srth = upipe_void_alloc_output(upipe_udpsrc, - upipe_srt_handshake_mgr, &uprobe_srt); - assert(upipe_srth); - upipe_set_option(upipe_srth, "listener", listener ? "1" : "0"); - if (!ubase_check(upipe_set_option(upipe_srth, "latency", latency))) - return EXIT_FAILURE; + uint64_t cr_sys = 0; + if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) { + upipe_err(upipe, "Couldn't read cr_sys in probe_uref"); + } - upipe_srt_handshake_set_password(upipe_srth, password, key_length / 8); - upipe_mgr_release(upipe_srt_handshake_mgr); + static uint64_t last_print; + if (unlikely(last_print == 0)) + last_print = cr_sys; - struct upipe_mgr *upipe_srt_receiver_mgr = upipe_srt_receiver_mgr_alloc(); - struct upipe *upipe_srtr = upipe_void_chain_output(upipe_srth, - upipe_srt_receiver_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr")); - assert(upipe_srtr); - if (!ubase_check(upipe_set_option(upipe_srtr, "latency", latency))) - return EXIT_FAILURE; + if ((cr_sys - last_print) < 3 * UCLOCK_FREQ) + return; - upipe_mgr_release(upipe_srt_receiver_mgr); + last_print = cr_sys; - upipe_srtr_sub = upipe_void_alloc_sub(upipe_srtr, - uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr_sub")); - assert(upipe_srtr_sub); + unsigned expected_seqnum, last_output_seqnum; + size_t buffers, nacks, repairs, loss, dups; + if (unlikely(!ubase_check(upipe_rtpfb_get_stats(upipe_rtpfb, + &expected_seqnum, &last_output_seqnum, + &buffers, &nacks, &repairs, &loss, &dups + )))) + upipe_err_va(upipe, "Couldn't get stats from rtpfb"); - upipe_udp_sink = upipe_void_alloc_output(upipe_srtr_sub, - udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, - "udpsink")); - upipe_release(upipe_udp_sink); + unsigned nack_overflow = (repairs && repairs < nacks) ? (nacks - repairs ) * 100 / repairs : 0; + upipe_notice_va(upipe, "%5u (%3zu) %5u\t%zu repairs %zu NACKS (%u%% too much)\tlost %zu\tduplicates %zu", + last_output_seqnum, buffers, expected_seqnum, repairs, nacks, nack_overflow, loss, dups); +} - if (rtpd_mgr) { - upipe_srtr = upipe_void_chain_output(upipe_srtr, rtpd_mgr, - uprobe_pfx_alloc(uprobe_use(logger), - loglevel, "rtpd")); - assert(upipe_srtr); - } +static void sink_timeout(struct upump *upump) +{ + struct rtcp_sink *sink = upump_get_opaque(upump, struct rtcp_sink *); + upump_stop(upump); + upump_free(upump); + + upipe_err_va(sink->dup_sub, "timeout"); + sink->timeout = NULL; + upipe_release(sink->dup_sub); + sink->dup_sub = NULL; +} - int udp_fd; - /* receive SRT */ - if (listener) { - if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) - return EXIT_FAILURE; - ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc, &udp_fd)); +static struct rtcp_sink *last_peer; - } else { - if (!ubase_check(upipe_set_uri(upipe_udp_sink, srcpath))) - return EXIT_FAILURE; +/** definition of our uprobe */ +static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + const char *uri; + switch (event) { + case UPROBE_UDPSRC_NEW_PEER: { + int sig = va_arg(args, int); + if (sig != UPIPE_UDPSRC_SIGNATURE) + return uprobe_throw_next(uprobe, upipe, event, args); + + const struct sockaddr *s = va_arg(args, struct sockaddr*); + const struct sockaddr_in *in = (const struct sockaddr_in*) s; + socklen_t addr_len = sizeof(*in); + const socklen_t *len = va_arg(args, socklen_t *); + + if (s->sa_family != AF_INET) { + upipe_err_va(upipe, "New UDP remote, unknown addr family %d", + s->sa_family); + return UBASE_ERR_NONE; + } - ubase_assert(upipe_udpsink_get_fd(upipe_udp_sink, &udp_fd)); - ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc, dup(udp_fd))); - } + if (*len < addr_len) { + upipe_err_va(upipe, "Too small AF_INET address"); + return UBASE_ERR_NONE; + } - struct sockaddr_storage ad; - socklen_t peer_len = sizeof(ad); - struct sockaddr *peer = (struct sockaddr*) &ad; + upipe_dbg_va(upipe, "Got new remote: %s:%hu ", + inet_ntoa(in->sin_addr), ntohs(in->sin_port)); + + const size_t n = sizeof(rtcp_sink) / sizeof(*rtcp_sink); + struct rtcp_sink *sink = NULL; + ssize_t avail = -1; /* index of the free remote */ + for (size_t i = 0; i < n; i++) { + if (!rtcp_sink[i].dup_sub) { + if (!sink) { + avail = i; + sink = &rtcp_sink[i]; + } + continue; + } + + if (memcmp(&rtcp_sink[i].addr, in, addr_len)) + continue; + + upipe_dbg_va(upipe, "Remote already existing"); + sink = &rtcp_sink[i]; + upump_stop(sink->timeout); + break; + } - if (!getsockname(udp_fd, peer, &peer_len)) { - char uri[INET6_ADDRSTRLEN+6]; - addr_to_str(peer, uri); - upipe_warn_va(upipe_srth, "Local %s", uri); // XXX: INADDR_ANY when listening - upipe_srt_handshake_set_peer(upipe_srth, peer, peer_len); - } + if (!sink) { + upipe_err_va(upipe, "Too many RTCP remotes already"); + return UBASE_ERR_NONE; + } - upipe_attach_uclock(upipe_udpsrc); - struct upipe *upipe_udp_sink_data = upipe_void_chain_output(upipe_srtr, - udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, - "udpsink data")); - upipe_set_uri(upipe_udp_sink_data, dirpath); - upipe_release(upipe_udp_sink_data); + if (last_peer) /* restart the timeout for the previous peer we got */ + upump_restart(last_peer->timeout); - return 0; -} + /* keep the timer for this remote stopped for now, + * this could be the only one we have */ + last_peer = sink; -static void stop(struct upump *upump) -{ - if (upump) { - upump_stop(upump); - upump_free(upump); - } + if (sink->dup_sub) + return UBASE_ERR_NONE; - upipe_release(upipe_udpsrc); - upipe_release(upipe_srtr_sub); + sink->dup_sub = upipe_void_alloc_sub(upipe_dup, + uprobe_pfx_alloc_va(uprobe_use(uprobe), loglevel, + "dup %zu", avail)); + assert(sink->dup_sub); - if (restart) { - restart = false; - start(); - } -} + struct upipe *rtcp_sink = upipe_void_alloc_output(sink->dup_sub, + udp_sink_mgr, uprobe_pfx_alloc_va(uprobe_use(uprobe), loglevel, + "udpsink rtpfb %zu", avail)); + ubase_assert(upipe_udpsink_set_fd(rtcp_sink, dup(udp_fd))); + upipe_release(rtcp_sink); -static void sig_cb(struct upump *upump) -{ - static int done = false; + sink->addr_len = addr_len; + memcpy(&sink->addr, in, addr_len); - if (done) - abort(); - done = true; + ubase_assert(upipe_udpsink_set_peer(rtcp_sink, + (const struct sockaddr*)&sink->addr, addr_len)); - restart = false; - stop(NULL); -} + sink->timeout = upump_alloc_timer(upump_mgr, sink_timeout, + sink, NULL, 3 * UCLOCK_FREQ, 3 * UCLOCK_FREQ); -static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) -{ - if (event == UPROBE_SOURCE_END) { - restart = true; - struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, 0, 0); - upump_start(u); return UBASE_ERR_NONE; } - - return uprobe_throw_next(uprobe, upipe, event, args); -} - -static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) -{ - if (event == UPROBE_SOURCE_END) { + case UPROBE_SOURCE_END: /* This control can not fail, and will trigger restart of upump */ - const char *uri; upipe_get_uri(upipe, &uri); return UBASE_ERR_NONE; - } - - if (event != UPROBE_UDPSRC_NEW_PEER) - return uprobe_throw_next(uprobe, upipe, event, args); - - int sig = va_arg(args, int); - if (sig != UPIPE_UDPSRC_SIGNATURE) + default: return uprobe_throw_next(uprobe, upipe, event, args); + } +} - const struct sockaddr *s = va_arg(args, struct sockaddr*); - const socklen_t *len = va_arg(args, socklen_t *); - char uri[INET6_ADDRSTRLEN+6]; - - addr_to_str(s, uri); - upipe_warn_va(upipe, "Remote %s", uri); - - int udp_fd; - ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc, &udp_fd)); - ubase_assert(upipe_udpsink_set_fd(upipe_udp_sink, dup(udp_fd))); - ubase_assert(upipe_udpsink_set_peer(upipe_udp_sink, s, *len)); - +/** definition of our uprobe */ +static int catch(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + default: + break; + case UPROBE_SOURCE_END: + if (upipe->mgr->signature == UPIPE_DUP_OUTPUT_SIGNATURE) { + const size_t n = sizeof(rtcp_sink) / sizeof(*rtcp_sink); + for (size_t i = 0; i < n; i++) { + struct rtcp_sink *sink = &rtcp_sink[i]; + if (sink->dup_sub == upipe) { + upump_stop(sink->timeout); + sink->dup_sub = NULL; + } + } + } + upipe_release(upipe); + break; + case UPROBE_PROBE_UREF: { + int sig = va_arg(args, int); + if (sig != UPIPE_PROBE_UREF_SIGNATURE) + return UBASE_ERR_INVALID; + struct uref *uref = va_arg(args, struct uref *); + va_arg(args, struct upump **); + gather_stats(upipe, uref); + break; + } + } return UBASE_ERR_NONE; } -static void usage(const char *argv0) { - fprintf(stdout, "Usage: %s [-dr] [-k password] [-l 128] ", argv0); - fprintf(stdout, " -d: more verbose\n"); - fprintf(stdout, " -q: more quiet\n"); - fprintf(stdout, " -r: rtp demux\n"); - fprintf(stdout, " -k encryption password\n"); - fprintf(stdout, " -l key length in bits\n"); - exit(EXIT_FAILURE); +static void stop(struct upump *upump) +{ + upump_stop(upump); + upump_free(upump); + + upipe_release(upipe_udpsrc_rtcp); + upipe_release(upipe_udpsrc); } int main(int argc, char *argv[]) { + char *dirpath, *latency, *srcpath; int opt; /* parse options */ - while ((opt = getopt(argc, argv, "qrdk:l:")) != -1) { + while ((opt = getopt(argc, argv, "qd")) != -1) { switch (opt) { case 'd': loglevel--; @@ -377,15 +292,6 @@ int main(int argc, char *argv[]) case 'q': loglevel++; break; - case 'k': - password = optarg; - break; - case 'l': - key_length = atoi(optarg); - break; - case 'r': - rtpd_mgr = upipe_rtpd_mgr_alloc(); - break; default: usage(argv[0]); } @@ -397,11 +303,6 @@ int main(int argc, char *argv[]) dirpath = argv[optind++]; latency = argv[optind++]; -#ifdef UPIPE_HAVE_GCRYPT_H - gcry_check_version(NULL); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -#endif - /* setup environment */ struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); @@ -411,7 +312,9 @@ int main(int argc, char *argv[]) 0); upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); - logger = uprobe_stdio_alloc(NULL, stdout, loglevel); + struct uprobe uprobe; + uprobe_init(&uprobe, catch, NULL); + struct uprobe *logger = uprobe_stdio_alloc(&uprobe, stdout, loglevel); assert(logger != NULL); struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); assert(uprobe_dejitter != NULL); @@ -430,51 +333,121 @@ int main(int argc, char *argv[]) uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); - logger = uprobe_obe_log_alloc(logger); - - uprobe_obe_log_set_loglevel(logger, loglevel); - uprobe_obe_log_set_uclock(logger, uclock); - logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); - uprobe_init(&uprobe_udp, catch_udp, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source")); - uprobe_init(&uprobe_srt, catch_srt, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srth")); + /* rtp source */ + struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); + upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "udp source")); + + /* rtcp source */ + struct uprobe uprobe_udp; + uprobe_init(&uprobe_udp, catch_udp, uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "udp rtcp source")); + upipe_udpsrc_rtcp = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); + upipe_mgr_release(upipe_udpsrc_mgr); + + struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); + struct upipe *upipe_probe_uref = upipe_void_alloc_output(upipe_udpsrc, + upipe_probe_uref_mgr, uprobe_use(logger)); + assert(upipe_probe_uref); + upipe_mgr_release(upipe_probe_uref_mgr); + upipe_release(upipe_probe_uref); + + struct upipe_mgr *upipe_rtpfb_mgr = upipe_rtpfb_mgr_alloc(); + upipe_rtpfb = upipe_void_alloc_output(upipe_probe_uref, + upipe_rtpfb_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtpfb")); + upipe_mgr_release(upipe_rtpfb_mgr); + + upipe_rtpfb_sub = upipe_void_alloc_output_sub(upipe_udpsrc_rtcp, upipe_rtpfb, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtpfb_sub")); + assert(upipe_rtpfb_sub); + + upipe_rtpfb_output_set_name(upipe_rtpfb_sub, "Upipe"); + + struct upipe_mgr *dup_mgr = upipe_dup_mgr_alloc(); + upipe_dup = upipe_void_chain_output(upipe_rtpfb_sub, dup_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "dup rtpfb_sub")); + assert(upipe_dup); + upipe_release(upipe_dup); + upipe_mgr_release(dup_mgr); + + if (!ubase_check(upipe_set_option(upipe_rtpfb, "latency", latency))) { + return EXIT_FAILURE; + } - int ret = start(); - if (ret) - return ret; + /* receive RTP */ + if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { + return EXIT_FAILURE; + } - if (0) { - //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsrc, NULL); + struct ustring u = ustring_from_str(srcpath); + struct uuri_authority authority = uuri_parse_authority(&u); + struct ustring settings = uuri_parse_path(&u); + + char port_str[6]; + snprintf(port_str, sizeof(port_str), "%.*s", (int)authority.port.len, + authority.port.at); + int port = atoi(port_str); + + if (port & 1) { + fprintf(stderr, "RTP port should be even\n"); + return EXIT_FAILURE; + } + + char uri[128]; + snprintf(uri, sizeof(uri), "%.*s@%.*s:%u%.*s", + (int)authority.userinfo.len, authority.userinfo.at, + (int)authority.host.len, authority.host.at, port + 1, + (int)settings.len, settings.at); + + if (!ubase_check(upipe_set_uri(upipe_udpsrc_rtcp, uri))) { + return EXIT_FAILURE; + } + + upipe_attach_uclock(upipe_udpsrc); + upipe_attach_uclock(upipe_udpsrc_rtcp); + + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_rtcp, &udp_fd)); + assert(udp_fd != -1); + + struct upipe *upipe_udp_sink = upipe_void_chain_output(upipe_rtpfb, + udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, + "udpsink")); + upipe_set_uri(upipe_udp_sink, dirpath); + upipe_release(upipe_udp_sink); + + if (0) { struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, UCLOCK_FREQ, 0); upump_start(u); } - struct upump *sigint_pump = - upump_alloc_signal(upump_mgr, sig_cb, - (void *)SIGINT, NULL, SIGINT); - upump_set_status(sigint_pump, false); - upump_start(sigint_pump); - /* fire loop ! */ upump_mgr_run(upump_mgr, NULL); - upump_free(sigint_pump); - - uprobe_clean(&uprobe_srt); + /* should never be here for the moment. todo: sighandler. + * release everything */ + uprobe_clean(&uprobe); uprobe_clean(&uprobe_udp); uprobe_release(logger); + const size_t n = sizeof(rtcp_sink) / sizeof(*rtcp_sink); + for (size_t i = 0; i < n; i++) { + struct rtcp_sink *sink = &rtcp_sink[i]; + if (sink->timeout) + upump_free(sink->timeout); + } + upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); udict_mgr_release(udict_mgr); umem_mgr_release(umem_mgr); uclock_release(uclock); upipe_mgr_release(udp_sink_mgr); - upipe_mgr_release(rtpd_mgr); return 0; } diff --git a/examples/rist_tx.c b/examples/rist_tx.c index b3c6c254e..af0ed000d 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -46,301 +46,238 @@ #include "upipe/uref_clock.h" #include "upipe/uref_std.h" #include "upipe/upump.h" -#include "upipe/upipe_dump.h" #include "upump-ev/upump_ev.h" #include "upipe/uuri.h" #include "upipe/ustring.h" #include "upipe/upipe.h" +#include "upipe-modules/upipe_dup.h" +#include "upipe-modules/upipe_rtcp.h" #include "upipe-modules/upipe_udp_source.h" #include "upipe-modules/upipe_udp_sink.h" #include "upipe-modules/upipe_probe_uref.h" +#include "upipe-filters/upipe_rtcp_fb_receiver.h" -#include "upipe-srt/upipe_srt_sender.h" -#include "upipe-srt/upipe_srt_handshake.h" - +#include +#include +#include #include -#include +#include -#ifdef UPIPE_HAVE_GCRYPT_H -#include -#endif +#include +#include +#include +#include #define UDICT_POOL_DEPTH 10 #define UREF_POOL_DEPTH 10 #define UBUF_POOL_DEPTH 10 #define UPUMP_POOL 10 #define UPUMP_BLOCKER_POOL 10 +#define READ_SIZE 4096 static void usage(const char *argv0) { fprintf(stdout, "Usage: %s [-d] \n", argv0); fprintf(stdout, " -d: more verbose\n"); fprintf(stdout, " -q: more quiet\n"); - fprintf(stdout, " -k encryption password\n"); - fprintf(stdout, " -i stream_id\n"); - fprintf(stdout, " -l key length in bits\n"); exit(EXIT_FAILURE); } static struct upipe *upipe_udpsink; -static struct upipe *upipe_udpsrc_srt; -static struct upipe *upipe_udpsrc; -static struct upipe *upipe_srt_sender; -static struct upipe *upipe_srt_sender_sub; +static struct upipe *upipe_udpsink_rtcp; +static struct upipe *upipe_udpsrc_sub; -static struct upipe *upipe_srt_handshake; +static uint64_t last_sr_ntp; +static uint64_t last_sr_cr; -static struct upump_mgr *upump_mgr; static struct uref_mgr *uref_mgr; -static char *srcpath; -static char *dirpath; -static char *latency; -static char *password; -static char *stream_id; -static int key_length = 128; - -static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; - -static struct uprobe *logger; - -static bool restart = true; - -static size_t packets = 0; -static const size_t km_refresh_period = 1 << 25; - -static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) -{ - uint16_t port = 0; - switch(s->sa_family) { - case AF_INET: { - struct sockaddr_in *in = (struct sockaddr_in *)s; - inet_ntop(AF_INET, &in->sin_addr, uri, INET6_ADDRSTRLEN); - port = ntohs(in->sin_port); - break; - } - case AF_INET6: { - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; - inet_ntop(AF_INET6, &in6->sin6_addr, uri, INET6_ADDRSTRLEN); - port = ntohs(in6->sin6_port); - break; - } - default: - uri[0] = '\0'; - } - - size_t uri_len = strlen(uri); - sprintf(&uri[uri_len], ":%hu", port); -} - -static void stop(struct upump *upump); - /** definition of our uprobe */ -static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, +static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { + const char *uri; + switch (event) { case UPROBE_SOURCE_END: - upipe_warn(upipe, "Remote shutdown"); - struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, - NULL, UCLOCK_FREQ, 0); - upump_start(u); + upipe_warn(upipe, "Remote end not listening, can't receive RTCP"); + /* This control can not fail, and will trigger restart of upump */ + upipe_get_uri(upipe, &uri); + return UBASE_ERR_NONE; + case UPROBE_UDPSRC_NEW_PEER: + return UBASE_ERR_NONE; + default: return uprobe_throw_next(uprobe, upipe, event, args); } - return uprobe_throw_next(uprobe, upipe, event, args); } -/** definition of our uprobe */ -static int catch_uref(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) +static void parse_rtcp(struct upipe *upipe, const uint8_t *rtp, int s, + uint64_t cr_sys, struct ubuf_mgr *ubuf_mgr) { - switch (event) { - case UPROBE_PROBE_UREF: - UBASE_SIGNATURE_CHECK(args, UPIPE_PROBE_UREF_SIGNATURE); - //struct uref *uref = va_arg(args, struct uref *); - - if (packets++ == km_refresh_period) { - packets = 0; - if (upipe_srt_handshake) - upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + while (s > 0) { + if (s < 4 || !rtp_check_hdr(rtp)) { + upipe_warn_va(upipe, "Received invalid RTP packet"); + break; } - return UBASE_ERR_NONE; - } - return uprobe_throw_next(uprobe, upipe, event, args); -} + size_t len = 4 + 4 * rtcp_get_length(rtp); + if (len > s) { + break; + } -/** definition of our uprobe */ -static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, - int event, va_list args) -{ - switch (event) { - case UPROBE_SOURCE_END: - upipe_warn(upipe, "Remote end not listening, can't receive SRT"); - struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, - NULL, UCLOCK_FREQ, 0); - upump_start(u); - return uprobe_throw_next(uprobe, upipe, event, args); - case UPROBE_UDPSRC_NEW_PEER: { - int udp_fd; - int sig = va_arg(args, int); - if (sig != UPIPE_UDPSRC_SIGNATURE) + switch (rtcp_get_pt(rtp)) { + case RTCP_PT_SR: + if (s < RTCP_SR_SIZE) + break; + uint32_t ntp_msw = rtcp_sr_get_ntp_time_msw(rtp); + uint32_t ntp_lsw = rtcp_sr_get_ntp_time_lsw(rtp); + if (cr_sys != UINT64_MAX) + last_sr_cr = cr_sys; + last_sr_ntp = ((uint64_t)ntp_msw << 32) | ntp_lsw; + upipe_verbose_va(upipe, "RTCP SR, CR %"PRIu64" NTP %"PRIu64, last_sr_cr, + last_sr_ntp); break; + case RTCP_PT_RR: + if (s < RTCP_RR_SIZE) + break; + if (rtcp_get_rc(rtp) < 1) + break; - const struct sockaddr *s = va_arg(args, struct sockaddr*); - const socklen_t *len = va_arg(args, socklen_t *); - - char uri[INET6_ADDRSTRLEN+6]; - addr_to_str(s, uri); - upipe_warn_va(upipe, "Remote %s", uri); - - ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_srt, &udp_fd)); - ubase_assert(upipe_udpsink_set_fd(upipe_udpsink, dup(udp_fd))); - - ubase_assert(upipe_udpsink_set_peer(upipe_udpsink, s, *len)); + uint32_t delay = rtcp_rr_get_delay_since_last_sr(rtp); + uint32_t last_sr = rtcp_rr_get_last_sr(rtp); + if (last_sr != ((last_sr_ntp >> 16) & 0xffffffff)) + break; - return UBASE_ERR_NONE; - } - } - return uprobe_throw_next(uprobe, upipe, event, args); -} + if (cr_sys != UINT64_MAX) { + cr_sys -= last_sr_cr; + cr_sys -= delay * UCLOCK_FREQ / 65536; + upipe_verbose_va(upipe, "RTCP RR: RTT %f", (float) cr_sys / UCLOCK_FREQ); + } + break; + case RTCP_PT_XR: + if (s < RTCP_XR_HEADER_SIZE + RTCP_XR_RRTP_SIZE) + break; -static int start(void) -{ - packets = 0; - static unsigned z = 0; - z++; + uint8_t ssrc[4]; + rtcp_xr_get_ssrc_sender(rtp, ssrc); + const uint8_t *rtp_xr = &rtp[RTCP_XR_HEADER_SIZE]; - bool listener = dirpath && strchr(dirpath, '@'); + if (rtcp_xr_get_bt(rtp_xr) != RTCP_XR_RRTP_BT) + break; + if ((rtcp_xr_get_length(rtp_xr) + 1) * 4 != RTCP_XR_RRTP_SIZE) + break; - /* rtp source */ - struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); - upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp source data %u", z)); + uint64_t ntp = rtcp_xr_rrtp_get_ntp(rtp_xr); - if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { - return EXIT_FAILURE; - } - upipe_attach_uclock(upipe_udpsrc); + struct uref *xr = uref_alloc(uref_mgr); + if (!xr) + break; - /* send through srt sender */ - struct upipe_mgr *upipe_srt_sender_mgr = upipe_srt_sender_mgr_alloc(); - upipe_srt_sender = upipe_void_alloc_output(upipe_udpsrc, upipe_srt_sender_mgr, - uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender %u", z)); - upipe_mgr_release(upipe_srt_sender_mgr); + if (cr_sys != UINT64_MAX) + uref_clock_set_cr_sys(xr, cr_sys); - if (!ubase_check(upipe_set_option(upipe_srt_sender, "latency", latency))) - return EXIT_FAILURE; + const size_t xr_len = RTCP_XR_HEADER_SIZE + RTCP_XR_DLRR_SIZE; + struct ubuf *ubuf = ubuf_block_alloc(ubuf_mgr, xr_len); + if (!ubuf) { + uref_free(xr); + break; + } - upipe_udpsrc_srt = upipe_void_alloc(upipe_udpsrc_mgr, - uprobe_pfx_alloc_va(uprobe_alloc(catch_udp, uprobe_use(logger)), loglevel, "udp source srt %u", z)); - upipe_attach_uclock(upipe_udpsrc_srt); + uref_attach_ubuf(xr, ubuf); - struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc_srt); - upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, - uprobe_pfx_alloc_va(uprobe_alloc(catch_hs, uprobe_use(logger)), loglevel, "srt handshake %u", z)); - upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); - if (!ubase_check(upipe_set_option(upipe_srt_handshake, "latency", latency))) - return EXIT_FAILURE; - upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); - if (stream_id) - upipe_set_option(upipe_srt_handshake, "stream_id", stream_id); + uint8_t *buf_xr; + int block_size = 0; + uref_block_write(xr, 0, &block_size, &buf_xr); - upipe_mgr_release(upipe_srt_handshake_mgr); + rtcp_set_rtp_version(buf_xr); + rtcp_set_pt(buf_xr, RTCP_PT_XR); + rtcp_set_length(buf_xr, xr_len / 4 - 1); - upipe_mgr_release(upipe_udpsrc_mgr); + static const uint8_t pi_ssrc[4] = { 0, 0, 0, 0 }; + rtcp_xr_set_ssrc_sender(buf_xr, pi_ssrc); - upipe_srt_sender_sub = upipe_void_chain_output_sub(upipe_srt_handshake, - upipe_srt_sender, - uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender sub %u", z)); - assert(upipe_srt_sender_sub); - upipe_release(upipe_srt_sender_sub); + buf_xr += RTCP_XR_HEADER_SIZE; + rtcp_xr_set_bt(buf_xr, RTCP_XR_DLRR_BT); + rtcp_xr_dlrr_set_reserved(buf_xr); + rtcp_xr_set_length(buf_xr, RTCP_XR_DLRR_SIZE / 4 - 1); + rtcp_xr_dlrr_set_ssrc_receiver(buf_xr, ssrc); - /* send to udp */ + ntp >>= 16; + rtcp_xr_dlrr_set_lrr(buf_xr, (uint32_t)ntp); - struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); - struct upipe *upipe = upipe_void_chain_output(upipe_srt_sender, upipe_probe_uref_mgr, - uprobe_pfx_alloc_va(uprobe_alloc(catch_uref, uprobe_use(logger)), loglevel, "probe %u", z)); + rtcp_xr_dlrr_set_dlrr(buf_xr, 0); // delay = 0, we answer immediately - struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); - upipe_udpsink = upipe_void_chain_output(upipe, upipe_udpsink_mgr, - uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp sink %u", z)); - upipe_release(upipe_udpsink); + uref_block_unmap(xr, 0); - int udp_fd = -1; - if (listener) { - if (!ubase_check(upipe_set_uri(upipe_udpsrc_srt, dirpath))) { - return EXIT_FAILURE; - } - ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_srt, &udp_fd)); - } else { - if (!ubase_check(upipe_set_uri(upipe_udpsink, dirpath))) { - return EXIT_FAILURE; + upipe_notice_va(upipe, "sending XR"); + upipe_input(upipe_udpsink_rtcp, xr, NULL); + break; + default: + break; } - ubase_assert(upipe_udpsink_get_fd(upipe_udpsink, &udp_fd)); - int flags = fcntl(udp_fd, F_GETFL); - flags |= O_NONBLOCK; - if (fcntl(udp_fd, F_SETFL, flags) < 0) - upipe_err(upipe_udpsink, "Could not set flags");; - ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc_srt, udp_fd)); + s -= len; + rtp += len; } +} - struct sockaddr_storage ad; - socklen_t peer_len = sizeof(ad); - struct sockaddr *peer = (struct sockaddr*) &ad; +/** definition of our uprobe */ +static int catch(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + struct uref *uref = NULL; - if (!getsockname(udp_fd, peer, &peer_len)) { - char uri[INET6_ADDRSTRLEN+6]; - addr_to_str(peer, uri); - upipe_warn_va(upipe_srt_handshake, "Local %s (%u)", uri, z); // XXX: INADDR_ANY when listening - upipe_srt_handshake_set_peer(upipe_srt_handshake, peer, peer_len); - } + switch (event) { + case UPROBE_SOURCE_END: + upipe_release(upipe); + break; - struct uref *flow_def = uref_alloc_control(uref_mgr); - uref_flow_set_def(flow_def, "block."); - upipe_set_flow_def(upipe_srt_sender, flow_def); - uref_free(flow_def); + case UPROBE_PROBE_UREF: { + int sig = va_arg(args, int); + if (sig != UPIPE_PROBE_UREF_SIGNATURE) + return UBASE_ERR_INVALID; + uref = va_arg(args, struct uref *); + va_arg(args, struct upump **); + va_arg(args, bool *); - return 0; -} + const uint8_t *buf; + int s = -1; + if (!ubase_check(uref_block_read(uref, 0, &s, &buf))) + return UBASE_ERR_INVALID; -static void stop(struct upump *upump) -{ - if (upump) { - upump_stop(upump); - upump_free(upump); - } + uint64_t cr_sys; + if (!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys))) + cr_sys = UINT64_MAX; - upipe_release(upipe_udpsrc_srt); - upipe_udpsrc_srt = NULL; - upipe_release(upipe_udpsrc); - upipe_udpsrc = NULL; + parse_rtcp(upipe, buf, s, cr_sys, uref->ubuf->mgr); - upipe_srt_handshake = NULL; + uref_block_unmap(uref, 0); - if (restart) - start(); + break; + } + default: + return uprobe_throw_next(uprobe, upipe, event, args); + } + return UBASE_ERR_NONE; } -static void sig_cb(struct upump *upump) +static void stop(struct upump *upump) { - static int done = false; - - if (done) - abort(); - done = true; + struct upipe *udpsrc = upump_get_opaque(upump, struct upipe*); + upump_stop(upump); + upump_free(upump); - restart = false; - stop(NULL); + upipe_release(upipe_udpsrc_sub); + upipe_release(udpsrc); } - int main(int argc, char *argv[]) { + char *srcpath, *dirpath, *latency; int opt; + enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; /* parse options */ - while ((opt = getopt(argc, argv, "qdk:i:l:")) != -1) { + while ((opt = getopt(argc, argv, "qd")) != -1) { switch (opt) { case 'q': loglevel++; @@ -348,16 +285,6 @@ int main(int argc, char *argv[]) case 'd': loglevel--; break; - break; - case 'k': - password = optarg; - break; - case 'i': - stream_id = optarg; - break; - case 'l': - key_length = atoi(optarg); - break; default: usage(argv[0]); } @@ -369,11 +296,6 @@ int main(int argc, char *argv[]) dirpath = argv[optind++]; latency = argv[optind++]; -#ifdef UPIPE_HAVE_GCRYPT_H - gcry_check_version(NULL); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -#endif - /* setup environment */ struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); @@ -381,10 +303,12 @@ int main(int argc, char *argv[]) umem_mgr, -1, -1); uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, 0); - upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, + struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); struct uclock *uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); - logger = uprobe_stdio_alloc(NULL, stdout, loglevel); + struct uprobe uprobe; + uprobe_init(&uprobe, catch, NULL); + struct uprobe *logger = uprobe_stdio_alloc(&uprobe, stdout, loglevel); assert(logger != NULL); struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); assert(uprobe_dejitter != NULL); @@ -401,30 +325,138 @@ int main(int argc, char *argv[]) logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); - int ret = start(); - if (ret) - return ret; + /* rtp source */ + struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); + struct upipe *upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source")); + + if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { + return EXIT_FAILURE; + } + upipe_attach_uclock(upipe_udpsrc); + + /* send through rtcp fb receiver */ + struct upipe_mgr *upipe_rtcpfb_mgr = upipe_rtcpfb_mgr_alloc(); + struct upipe *upipe_rtcpfb = upipe_void_alloc_output(upipe_udpsrc, upipe_rtcpfb_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtcp fb")); + upipe_mgr_release(upipe_rtcpfb_mgr); + + if (!ubase_check(upipe_set_option(upipe_rtcpfb, "latency", latency))) + return EXIT_FAILURE; + + struct uprobe uprobe_udp_rtcp; + uprobe_init(&uprobe_udp_rtcp, catch_udp, uprobe_use(logger)); + upipe_udpsrc_sub = upipe_void_alloc(upipe_udpsrc_mgr, + uprobe_pfx_alloc(&uprobe_udp_rtcp, loglevel, "udp source rtcp")); + upipe_attach_uclock(upipe_udpsrc_sub); + + upipe_mgr_release(upipe_udpsrc_mgr); + + /* catch RTCP XR/NACK messages before they're output to rtcp_fb */ + struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); + struct upipe *upipe_probe_uref = upipe_void_alloc_output(upipe_udpsrc_sub, + upipe_probe_uref_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "probe")); + assert(upipe_probe_uref); + upipe_mgr_release(upipe_probe_uref_mgr); + + struct upipe *upipe_rtcp_sub = upipe_void_chain_output_sub(upipe_probe_uref, + upipe_rtcpfb, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "rtcp fb sub")); + assert(upipe_rtcp_sub); + upipe_release(upipe_rtcp_sub); + + struct upipe_mgr *dup_mgr = upipe_dup_mgr_alloc(); + struct upipe *dup = upipe_void_chain_output(upipe_rtcpfb, dup_mgr, + uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "dup")); + upipe_mgr_release(dup_mgr); + + upipe_rtcpfb = upipe_void_alloc_sub(dup, + uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "dup 1")); + + struct upipe *rtcp_dup = upipe_void_alloc_sub(dup, + uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "dup 2")); + + upipe_release(dup); + + struct upipe_mgr *rtcp_mgr = upipe_rtcp_mgr_alloc(); + struct upipe *rtcp = upipe_void_alloc_output(rtcp_dup, rtcp_mgr, + uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "rtcp")); + upipe_mgr_release(rtcp_mgr); + + /* catch RTCP SR messages before they're output */ + upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); + rtcp = upipe_void_chain_output(rtcp, + upipe_probe_uref_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "probe2")); + assert(rtcp); + upipe_mgr_release(upipe_probe_uref_mgr); + + /* send to udp */ + struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); + upipe_udpsink = upipe_void_alloc_output(upipe_rtcpfb, upipe_udpsink_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp sink")); + upipe_release(upipe_udpsink); + + if (!ubase_check(upipe_set_uri(upipe_udpsink, dirpath))) { + return EXIT_FAILURE; + } + + /* send RTCP to udp */ + upipe_udpsink_rtcp = upipe_void_chain_output(rtcp, upipe_udpsink_mgr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp sink rtcp")); + upipe_mgr_release(upipe_udpsink_mgr); + upipe_release(upipe_udpsink_rtcp); + + struct ustring u = ustring_from_str(dirpath); + struct uuri_authority authority = uuri_parse_authority(&u); + struct ustring settings = uuri_parse_path(&u); + + char port_str[6]; + snprintf(port_str, sizeof(port_str), "%.*s", (int)authority.port.len, + authority.port.at); + int port = atoi(port_str); + + if (port & 1) { + fprintf(stderr, "RTP port should be even\n"); + return EXIT_FAILURE; + } + + char uri[128]; + snprintf(uri, sizeof(uri), "%.*s%s%.*s:%u%.*s", + (int)authority.userinfo.len, authority.userinfo.at, + ustring_is_empty(authority.userinfo) ? "" : "@", + (int)authority.host.len, authority.host.at, port + 1, + (int)settings.len, settings.at); + + if (!ubase_check(upipe_set_uri(upipe_udpsink_rtcp, uri))) { + return EXIT_FAILURE; + } + + int udp_fd = -1; + ubase_assert(upipe_udpsink_get_fd(upipe_udpsink_rtcp, &udp_fd)); + int flags = fcntl(udp_fd, F_GETFL); + flags |= O_NONBLOCK; + if (fcntl(udp_fd, F_SETFL, flags) < 0) + upipe_err(upipe_udpsink, "Could not set flags");; + ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc_sub, udp_fd)); if (0) { - restart = false; - //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, NULL, UCLOCK_FREQ, 0); upump_start(u); } - struct upump *sigint_pump = - upump_alloc_signal(upump_mgr, sig_cb, - (void *)SIGINT, NULL, SIGINT); - upump_set_status(sigint_pump, false); - upump_start(sigint_pump); - /* fire loop ! */ upump_mgr_run(upump_mgr, NULL); - upump_free(sigint_pump); - + /* should never be here for the moment. todo: sighandler. + * release everything */ uprobe_release(logger); + uprobe_clean(&uprobe); + uprobe_clean(&uprobe_udp_rtcp); upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); @@ -432,7 +464,5 @@ int main(int argc, char *argv[]) umem_mgr_release(umem_mgr); uclock_release(uclock); - printf("done\n"); - return 0; } diff --git a/examples/srt_rx.c b/examples/srt_rx.c new file mode 100644 index 000000000..4ae1c8dbb --- /dev/null +++ b/examples/srt_rx.c @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2016-2017 Open Broadcast Systems Ltd. + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include + +#undef NDEBUG +#include "upipe/uprobe.h" +#include "upipe/upipe_dump.h" +#include "upipe/uprobe_stdio.h" +#include "upipe/uprobe_prefix.h" +#include "upipe/uprobe_uref_mgr.h" +#include "upipe/uprobe_upump_mgr.h" +#include "upipe/uprobe_uclock.h" +#include "upipe/uprobe_ubuf_mem.h" +#include "upipe/uprobe_dejitter.h" +#include "upipe/uclock.h" +#include "upipe/uclock_std.h" +#include "upipe/uref_clock.h" +#include "upipe/umem.h" +#include "upipe/umem_alloc.h" +#include "upipe/udict.h" +#include "upipe/udict_inline.h" +#include "upipe/uref.h" +#include "upipe/uref_std.h" +#include "upipe/upump.h" +#include "upump-ev/upump_ev.h" +#include "upipe/uuri.h" +#include "upipe/ustring.h" +#include "upipe/upipe.h" +#include "upipe-modules/upipe_udp_source.h" +#include +#include "upipe-modules/upipe_udp_sink.h" +#include "upipe-srt/upipe_srt_handshake.h" +#include "upipe-srt/upipe_srt_receiver.h" +#include "upipe/uprobe_helper_uprobe.h" +#include "upipe/uprobe_helper_alloc.h" + +#include + +#ifdef UPIPE_HAVE_GCRYPT_H +#include +#endif + +#define UDICT_POOL_DEPTH 10 +#define UREF_POOL_DEPTH 10 +#define UBUF_POOL_DEPTH 10 +#define UPUMP_POOL 10 +#define UPUMP_BLOCKER_POOL 10 +#define READ_SIZE 4096 + + +/* structure */ +struct uprobe_obe_log { + struct urefcount urefcount; + struct uclock *uclock; + struct uprobe uprobe; + uint64_t start; + uatomic_uint32_t loglevel; +}; + +/* helper */ +UPROBE_HELPER_UPROBE(uprobe_obe_log, uprobe) + +/* alloc */ +struct uprobe *uprobe_obe_log_alloc(struct uprobe *next); + +static int uprobe_obe_log_throw(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + if (event != UPROBE_LOG) + return uprobe_throw_next(uprobe, upipe, event, args); + + va_list args_copy; + va_copy(args_copy, args); + struct ulog *ulog = va_arg(args_copy, struct ulog *); + + uint32_t loglevel = uatomic_load(&probe_obe_log->loglevel); + if (loglevel > ulog->level) + return UBASE_ERR_NONE; + + char time_str[22]; + if (probe_obe_log->uclock) { + uint64_t t = uclock_now(probe_obe_log->uclock) - probe_obe_log->start; + snprintf(time_str, sizeof(time_str), "%.2f", (float)t / 27000.); + } else { + snprintf(time_str, sizeof(time_str), "?"); + } + struct ulog_pfx ulog_pfx = { + .tag = time_str, + }; + ulist_add(&ulog->prefixes, ulog_pfx_to_uchain(&ulog_pfx)); + + return uprobe_throw_next(uprobe, upipe, event, args); +} + +static void uprobe_obe_log_set_loglevel(struct uprobe *uprobe, int loglevel) +{ + struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + uatomic_store(&probe_obe_log->loglevel, loglevel); +} + +static void uprobe_obe_log_set_uclock(struct uprobe *uprobe, struct uclock *uclock) +{ + struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + uclock_release(probe_obe_log->uclock); + probe_obe_log->uclock = uclock_use(uclock); + probe_obe_log->start = uclock_now(uclock); +} + +static struct uprobe *uprobe_obe_log_init(struct uprobe_obe_log *probe_obe_log, + struct uprobe *next) +{ + struct uprobe *probe = uprobe_obe_log_to_uprobe(probe_obe_log); + probe_obe_log->uclock = NULL; + probe_obe_log->start = UINT64_MAX; + uatomic_init(&probe_obe_log->loglevel, UPROBE_LOG_DEBUG); + uprobe_init(probe, uprobe_obe_log_throw, next); + return probe; +} + +static void uprobe_obe_log_clean(struct uprobe_obe_log *probe_obe_log) +{ + uprobe_clean(uprobe_obe_log_to_uprobe(probe_obe_log)); + uclock_release(probe_obe_log->uclock); + uatomic_clean(&probe_obe_log->loglevel); +} + +#define ARGS_DECL struct uprobe *next +#define ARGS next +UPROBE_HELPER_ALLOC(uprobe_obe_log); +#undef ARGS +#undef ARGS_DECL + +static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; + +static struct upipe_mgr *udp_sink_mgr; +static struct upump_mgr *upump_mgr; + +static struct upipe *upipe_udpsrc; +static struct upipe *upipe_udp_sink; +static struct upipe *upipe_srtr_sub; + +static struct uprobe uprobe_udp; +static struct uprobe uprobe_srt; +static struct uprobe *logger; + +static char *dirpath; +static char *srcpath; +static char *password; +static int key_length = 128; +static char *latency; + +static bool restart; + +static struct upipe_mgr *rtpd_mgr; + +static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) +{ + uint16_t port = 0; + switch(s->sa_family) { + case AF_INET: { + struct sockaddr_in *in = (struct sockaddr_in *)s; + inet_ntop(AF_INET, &in->sin_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in->sin_port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + inet_ntop(AF_INET6, &in6->sin6_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in6->sin6_port); + break; + } + default: + uri[0] = '\0'; + } + + size_t uri_len = strlen(uri); + sprintf(&uri[uri_len], ":%hu", port); +} + +static int start(void) +{ + bool listener = srcpath && strchr(srcpath, '@'); + struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); + upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, &uprobe_udp); + upipe_mgr_release(upipe_udpsrc_mgr); + + struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc); + struct upipe *upipe_srth = upipe_void_alloc_output(upipe_udpsrc, + upipe_srt_handshake_mgr, &uprobe_srt); + assert(upipe_srth); + upipe_set_option(upipe_srth, "listener", listener ? "1" : "0"); + if (!ubase_check(upipe_set_option(upipe_srth, "latency", latency))) + return EXIT_FAILURE; + + upipe_srt_handshake_set_password(upipe_srth, password, key_length / 8); + upipe_mgr_release(upipe_srt_handshake_mgr); + + struct upipe_mgr *upipe_srt_receiver_mgr = upipe_srt_receiver_mgr_alloc(); + struct upipe *upipe_srtr = upipe_void_chain_output(upipe_srth, + upipe_srt_receiver_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr")); + assert(upipe_srtr); + if (!ubase_check(upipe_set_option(upipe_srtr, "latency", latency))) + return EXIT_FAILURE; + + upipe_mgr_release(upipe_srt_receiver_mgr); + + upipe_srtr_sub = upipe_void_alloc_sub(upipe_srtr, + uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr_sub")); + assert(upipe_srtr_sub); + + upipe_udp_sink = upipe_void_alloc_output(upipe_srtr_sub, + udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, + "udpsink")); + upipe_release(upipe_udp_sink); + + if (rtpd_mgr) { + upipe_srtr = upipe_void_chain_output(upipe_srtr, rtpd_mgr, + uprobe_pfx_alloc(uprobe_use(logger), + loglevel, "rtpd")); + assert(upipe_srtr); + } + + int udp_fd; + /* receive SRT */ + if (listener) { + if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) + return EXIT_FAILURE; + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc, &udp_fd)); + + } else { + if (!ubase_check(upipe_set_uri(upipe_udp_sink, srcpath))) + return EXIT_FAILURE; + + ubase_assert(upipe_udpsink_get_fd(upipe_udp_sink, &udp_fd)); + ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc, dup(udp_fd))); + } + + struct sockaddr_storage ad; + socklen_t peer_len = sizeof(ad); + struct sockaddr *peer = (struct sockaddr*) &ad; + + if (!getsockname(udp_fd, peer, &peer_len)) { + char uri[INET6_ADDRSTRLEN+6]; + addr_to_str(peer, uri); + upipe_warn_va(upipe_srth, "Local %s", uri); // XXX: INADDR_ANY when listening + upipe_srt_handshake_set_peer(upipe_srth, peer, peer_len); + } + + upipe_attach_uclock(upipe_udpsrc); + struct upipe *upipe_udp_sink_data = upipe_void_chain_output(upipe_srtr, + udp_sink_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, + "udpsink data")); + upipe_set_uri(upipe_udp_sink_data, dirpath); + upipe_release(upipe_udp_sink_data); + + return 0; +} + +static void stop(struct upump *upump) +{ + if (upump) { + upump_stop(upump); + upump_free(upump); + } + + upipe_release(upipe_udpsrc); + upipe_release(upipe_srtr_sub); + + if (restart) { + restart = false; + start(); + } +} + +static void sig_cb(struct upump *upump) +{ + static int done = false; + + if (done) + abort(); + done = true; + + restart = false; + stop(NULL); +} + +static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + if (event == UPROBE_SOURCE_END) { + restart = true; + struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, 0, 0); + upump_start(u); + return UBASE_ERR_NONE; + } + + return uprobe_throw_next(uprobe, upipe, event, args); +} + +static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + if (event == UPROBE_SOURCE_END) { + /* This control can not fail, and will trigger restart of upump */ + const char *uri; + upipe_get_uri(upipe, &uri); + return UBASE_ERR_NONE; + } + + if (event != UPROBE_UDPSRC_NEW_PEER) + return uprobe_throw_next(uprobe, upipe, event, args); + + int sig = va_arg(args, int); + if (sig != UPIPE_UDPSRC_SIGNATURE) + return uprobe_throw_next(uprobe, upipe, event, args); + + const struct sockaddr *s = va_arg(args, struct sockaddr*); + const socklen_t *len = va_arg(args, socklen_t *); + char uri[INET6_ADDRSTRLEN+6]; + + addr_to_str(s, uri); + upipe_warn_va(upipe, "Remote %s", uri); + + int udp_fd; + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc, &udp_fd)); + ubase_assert(upipe_udpsink_set_fd(upipe_udp_sink, dup(udp_fd))); + ubase_assert(upipe_udpsink_set_peer(upipe_udp_sink, s, *len)); + + return UBASE_ERR_NONE; +} + +static void usage(const char *argv0) { + fprintf(stdout, "Usage: %s [-dr] [-k password] [-l 128] ", argv0); + fprintf(stdout, " -d: more verbose\n"); + fprintf(stdout, " -q: more quiet\n"); + fprintf(stdout, " -r: rtp demux\n"); + fprintf(stdout, " -k encryption password\n"); + fprintf(stdout, " -l key length in bits\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int opt; + + /* parse options */ + while ((opt = getopt(argc, argv, "qrdk:l:")) != -1) { + switch (opt) { + case 'd': + loglevel--; + break; + case 'q': + loglevel++; + break; + case 'k': + password = optarg; + break; + case 'l': + key_length = atoi(optarg); + break; + case 'r': + rtpd_mgr = upipe_rtpd_mgr_alloc(); + break; + default: + usage(argv[0]); + } + } + if (argc - optind < 3) { + usage(argv[0]); + } + srcpath = argv[optind++]; + dirpath = argv[optind++]; + latency = argv[optind++]; + +#ifdef UPIPE_HAVE_GCRYPT_H + gcry_check_version(NULL); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +#endif + + /* setup environment */ + + struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); + struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH, + umem_mgr, -1, -1); + struct uref_mgr *uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, + 0); + upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, + UPUMP_BLOCKER_POOL); + logger = uprobe_stdio_alloc(NULL, stdout, loglevel); + assert(logger != NULL); + struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); + assert(uprobe_dejitter != NULL); + + logger = uprobe_uref_mgr_alloc(uprobe_dejitter, uref_mgr); + + assert(logger != NULL); + logger = uprobe_upump_mgr_alloc(logger, upump_mgr); + assert(logger != NULL); + logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH, + UBUF_POOL_DEPTH); + assert(logger != NULL); + struct uclock *uclock = NULL; + + udp_sink_mgr = upipe_udpsink_mgr_alloc(); + + uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + + logger = uprobe_obe_log_alloc(logger); + + uprobe_obe_log_set_loglevel(logger, loglevel); + uprobe_obe_log_set_uclock(logger, uclock); + + logger = uprobe_uclock_alloc(logger, uclock); + assert(logger != NULL); + + uprobe_init(&uprobe_udp, catch_udp, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "udp source")); + uprobe_init(&uprobe_srt, catch_srt, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srth")); + + int ret = start(); + if (ret) + return ret; + + if (0) { + //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsrc, NULL); + + struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, + UCLOCK_FREQ, 0); + upump_start(u); + } + + struct upump *sigint_pump = + upump_alloc_signal(upump_mgr, sig_cb, + (void *)SIGINT, NULL, SIGINT); + upump_set_status(sigint_pump, false); + upump_start(sigint_pump); + + /* fire loop ! */ + upump_mgr_run(upump_mgr, NULL); + + upump_free(sigint_pump); + + uprobe_clean(&uprobe_srt); + uprobe_clean(&uprobe_udp); + uprobe_release(logger); + + upump_mgr_release(upump_mgr); + uref_mgr_release(uref_mgr); + udict_mgr_release(udict_mgr); + umem_mgr_release(umem_mgr); + uclock_release(uclock); + upipe_mgr_release(udp_sink_mgr); + upipe_mgr_release(rtpd_mgr); + + return 0; +} diff --git a/examples/srt_tx.c b/examples/srt_tx.c new file mode 100644 index 000000000..b3c6c254e --- /dev/null +++ b/examples/srt_tx.c @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2016-2017 Open Broadcast Systems Ltd. + * + * Authors: Rafaël Carré + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#undef NDEBUG +#include "upipe/uprobe.h" +#include "upipe/uprobe_stdio.h" +#include "upipe/uprobe_prefix.h" +#include "upipe/uprobe_uref_mgr.h" +#include "upipe/uprobe_upump_mgr.h" +#include "upipe/uprobe_uclock.h" +#include "upipe/uprobe_ubuf_mem.h" +#include "upipe/uprobe_dejitter.h" +#include "upipe/uclock.h" +#include "upipe/uclock_std.h" +#include "upipe/umem.h" +#include "upipe/umem_alloc.h" +#include "upipe/udict.h" +#include "upipe/udict_inline.h" +#include "upipe/ubuf.h" +#include "upipe/ubuf_block.h" +#include "upipe/uref.h" +#include "upipe/uref_block.h" +#include "upipe/uref_clock.h" +#include "upipe/uref_std.h" +#include "upipe/upump.h" +#include "upipe/upipe_dump.h" +#include "upump-ev/upump_ev.h" +#include "upipe/uuri.h" +#include "upipe/ustring.h" +#include "upipe/upipe.h" +#include "upipe-modules/upipe_udp_source.h" +#include "upipe-modules/upipe_udp_sink.h" +#include "upipe-modules/upipe_probe_uref.h" + +#include "upipe-srt/upipe_srt_sender.h" +#include "upipe-srt/upipe_srt_handshake.h" + +#include +#include + +#ifdef UPIPE_HAVE_GCRYPT_H +#include +#endif + +#define UDICT_POOL_DEPTH 10 +#define UREF_POOL_DEPTH 10 +#define UBUF_POOL_DEPTH 10 +#define UPUMP_POOL 10 +#define UPUMP_BLOCKER_POOL 10 + +static void usage(const char *argv0) { + fprintf(stdout, "Usage: %s [-d] \n", argv0); + fprintf(stdout, " -d: more verbose\n"); + fprintf(stdout, " -q: more quiet\n"); + fprintf(stdout, " -k encryption password\n"); + fprintf(stdout, " -i stream_id\n"); + fprintf(stdout, " -l key length in bits\n"); + exit(EXIT_FAILURE); +} + +static struct upipe *upipe_udpsink; +static struct upipe *upipe_udpsrc_srt; +static struct upipe *upipe_udpsrc; +static struct upipe *upipe_srt_sender; +static struct upipe *upipe_srt_sender_sub; + +static struct upipe *upipe_srt_handshake; + +static struct upump_mgr *upump_mgr; +static struct uref_mgr *uref_mgr; + +static char *srcpath; +static char *dirpath; +static char *latency; +static char *password; +static char *stream_id; +static int key_length = 128; + +static enum uprobe_log_level loglevel = UPROBE_LOG_DEBUG; + +static struct uprobe *logger; + +static bool restart = true; + +static size_t packets = 0; +static const size_t km_refresh_period = 1 << 25; + +static void addr_to_str(const struct sockaddr *s, char uri[INET6_ADDRSTRLEN+6]) +{ + uint16_t port = 0; + switch(s->sa_family) { + case AF_INET: { + struct sockaddr_in *in = (struct sockaddr_in *)s; + inet_ntop(AF_INET, &in->sin_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in->sin_port); + break; + } + case AF_INET6: { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + inet_ntop(AF_INET6, &in6->sin6_addr, uri, INET6_ADDRSTRLEN); + port = ntohs(in6->sin6_port); + break; + } + default: + uri[0] = '\0'; + } + + size_t uri_len = strlen(uri); + sprintf(&uri[uri_len], ":%hu", port); +} + +static void stop(struct upump *upump); + +/** definition of our uprobe */ +static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + case UPROBE_SOURCE_END: + upipe_warn(upipe, "Remote shutdown"); + struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, + NULL, UCLOCK_FREQ, 0); + upump_start(u); + return uprobe_throw_next(uprobe, upipe, event, args); + } + return uprobe_throw_next(uprobe, upipe, event, args); +} + +/** definition of our uprobe */ +static int catch_uref(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + case UPROBE_PROBE_UREF: + UBASE_SIGNATURE_CHECK(args, UPIPE_PROBE_UREF_SIGNATURE); + //struct uref *uref = va_arg(args, struct uref *); + + if (packets++ == km_refresh_period) { + packets = 0; + if (upipe_srt_handshake) + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + } + + return UBASE_ERR_NONE; + } + return uprobe_throw_next(uprobe, upipe, event, args); +} + +/** definition of our uprobe */ +static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + case UPROBE_SOURCE_END: + upipe_warn(upipe, "Remote end not listening, can't receive SRT"); + struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, + NULL, UCLOCK_FREQ, 0); + upump_start(u); + return uprobe_throw_next(uprobe, upipe, event, args); + case UPROBE_UDPSRC_NEW_PEER: { + int udp_fd; + int sig = va_arg(args, int); + if (sig != UPIPE_UDPSRC_SIGNATURE) + break; + + const struct sockaddr *s = va_arg(args, struct sockaddr*); + const socklen_t *len = va_arg(args, socklen_t *); + + char uri[INET6_ADDRSTRLEN+6]; + addr_to_str(s, uri); + upipe_warn_va(upipe, "Remote %s", uri); + + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_srt, &udp_fd)); + ubase_assert(upipe_udpsink_set_fd(upipe_udpsink, dup(udp_fd))); + + ubase_assert(upipe_udpsink_set_peer(upipe_udpsink, s, *len)); + + return UBASE_ERR_NONE; + } + } + return uprobe_throw_next(uprobe, upipe, event, args); +} + +static int start(void) +{ + packets = 0; + static unsigned z = 0; + z++; + + bool listener = dirpath && strchr(dirpath, '@'); + + /* rtp source */ + struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); + upipe_udpsrc = upipe_void_alloc(upipe_udpsrc_mgr, + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp source data %u", z)); + + if (!ubase_check(upipe_set_uri(upipe_udpsrc, srcpath))) { + return EXIT_FAILURE; + } + upipe_attach_uclock(upipe_udpsrc); + + /* send through srt sender */ + struct upipe_mgr *upipe_srt_sender_mgr = upipe_srt_sender_mgr_alloc(); + upipe_srt_sender = upipe_void_alloc_output(upipe_udpsrc, upipe_srt_sender_mgr, + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender %u", z)); + upipe_mgr_release(upipe_srt_sender_mgr); + + if (!ubase_check(upipe_set_option(upipe_srt_sender, "latency", latency))) + return EXIT_FAILURE; + + upipe_udpsrc_srt = upipe_void_alloc(upipe_udpsrc_mgr, + uprobe_pfx_alloc_va(uprobe_alloc(catch_udp, uprobe_use(logger)), loglevel, "udp source srt %u", z)); + upipe_attach_uclock(upipe_udpsrc_srt); + + struct upipe_mgr *upipe_srt_handshake_mgr = upipe_srt_handshake_mgr_alloc((long)&upipe_udpsrc_srt); + upipe_srt_handshake = upipe_void_alloc_output(upipe_udpsrc_srt, upipe_srt_handshake_mgr, + uprobe_pfx_alloc_va(uprobe_alloc(catch_hs, uprobe_use(logger)), loglevel, "srt handshake %u", z)); + upipe_set_option(upipe_srt_handshake, "listener", listener ? "1" : "0"); + if (!ubase_check(upipe_set_option(upipe_srt_handshake, "latency", latency))) + return EXIT_FAILURE; + upipe_srt_handshake_set_password(upipe_srt_handshake, password, key_length / 8); + if (stream_id) + upipe_set_option(upipe_srt_handshake, "stream_id", stream_id); + + upipe_mgr_release(upipe_srt_handshake_mgr); + + upipe_mgr_release(upipe_udpsrc_mgr); + + upipe_srt_sender_sub = upipe_void_chain_output_sub(upipe_srt_handshake, + upipe_srt_sender, + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "srt sender sub %u", z)); + assert(upipe_srt_sender_sub); + upipe_release(upipe_srt_sender_sub); + + /* send to udp */ + + struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); + struct upipe *upipe = upipe_void_chain_output(upipe_srt_sender, upipe_probe_uref_mgr, + uprobe_pfx_alloc_va(uprobe_alloc(catch_uref, uprobe_use(logger)), loglevel, "probe %u", z)); + + struct upipe_mgr *upipe_udpsink_mgr = upipe_udpsink_mgr_alloc(); + upipe_udpsink = upipe_void_chain_output(upipe, upipe_udpsink_mgr, + uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "udp sink %u", z)); + upipe_release(upipe_udpsink); + + int udp_fd = -1; + if (listener) { + if (!ubase_check(upipe_set_uri(upipe_udpsrc_srt, dirpath))) { + return EXIT_FAILURE; + } + ubase_assert(upipe_udpsrc_get_fd(upipe_udpsrc_srt, &udp_fd)); + } else { + if (!ubase_check(upipe_set_uri(upipe_udpsink, dirpath))) { + return EXIT_FAILURE; + } + + ubase_assert(upipe_udpsink_get_fd(upipe_udpsink, &udp_fd)); + int flags = fcntl(udp_fd, F_GETFL); + flags |= O_NONBLOCK; + if (fcntl(udp_fd, F_SETFL, flags) < 0) + upipe_err(upipe_udpsink, "Could not set flags");; + ubase_assert(upipe_udpsrc_set_fd(upipe_udpsrc_srt, udp_fd)); + } + + struct sockaddr_storage ad; + socklen_t peer_len = sizeof(ad); + struct sockaddr *peer = (struct sockaddr*) &ad; + + if (!getsockname(udp_fd, peer, &peer_len)) { + char uri[INET6_ADDRSTRLEN+6]; + addr_to_str(peer, uri); + upipe_warn_va(upipe_srt_handshake, "Local %s (%u)", uri, z); // XXX: INADDR_ANY when listening + upipe_srt_handshake_set_peer(upipe_srt_handshake, peer, peer_len); + } + + struct uref *flow_def = uref_alloc_control(uref_mgr); + uref_flow_set_def(flow_def, "block."); + upipe_set_flow_def(upipe_srt_sender, flow_def); + uref_free(flow_def); + + return 0; +} + +static void stop(struct upump *upump) +{ + if (upump) { + upump_stop(upump); + upump_free(upump); + } + + upipe_release(upipe_udpsrc_srt); + upipe_udpsrc_srt = NULL; + upipe_release(upipe_udpsrc); + upipe_udpsrc = NULL; + + upipe_srt_handshake = NULL; + + if (restart) + start(); +} + +static void sig_cb(struct upump *upump) +{ + static int done = false; + + if (done) + abort(); + done = true; + + restart = false; + stop(NULL); +} + + +int main(int argc, char *argv[]) +{ + int opt; + + /* parse options */ + while ((opt = getopt(argc, argv, "qdk:i:l:")) != -1) { + switch (opt) { + case 'q': + loglevel++; + break; + case 'd': + loglevel--; + break; + break; + case 'k': + password = optarg; + break; + case 'i': + stream_id = optarg; + break; + case 'l': + key_length = atoi(optarg); + break; + default: + usage(argv[0]); + } + } + if (argc - optind < 3) { + usage(argv[0]); + } + srcpath = argv[optind++]; + dirpath = argv[optind++]; + latency = argv[optind++]; + +#ifdef UPIPE_HAVE_GCRYPT_H + gcry_check_version(NULL); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +#endif + + /* setup environment */ + + struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); + struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH, + umem_mgr, -1, -1); + uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, + 0); + upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, + UPUMP_BLOCKER_POOL); + struct uclock *uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + logger = uprobe_stdio_alloc(NULL, stdout, loglevel); + assert(logger != NULL); + struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); + assert(uprobe_dejitter != NULL); + + logger = uprobe_uref_mgr_alloc(uprobe_dejitter, uref_mgr); + + assert(logger != NULL); + logger = uprobe_upump_mgr_alloc(logger, upump_mgr); + assert(logger != NULL); + logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH, + UBUF_POOL_DEPTH); + assert(logger != NULL); + + logger = uprobe_uclock_alloc(logger, uclock); + assert(logger != NULL); + + int ret = start(); + if (ret) + return ret; + + if (0) { + restart = false; + //upipe_dump_open(NULL, NULL, "dump.dot", NULL, upipe_udpsink, upipe_udpsrc, upipe_udpsrc_srt, NULL); + struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, + NULL, UCLOCK_FREQ, 0); + upump_start(u); + } + + struct upump *sigint_pump = + upump_alloc_signal(upump_mgr, sig_cb, + (void *)SIGINT, NULL, SIGINT); + upump_set_status(sigint_pump, false); + upump_start(sigint_pump); + + /* fire loop ! */ + upump_mgr_run(upump_mgr, NULL); + + upump_free(sigint_pump); + + uprobe_release(logger); + + upump_mgr_release(upump_mgr); + uref_mgr_release(uref_mgr); + udict_mgr_release(udict_mgr); + umem_mgr_release(umem_mgr); + uclock_release(uclock); + + printf("done\n"); + + return 0; +} From 1c39c1f6ffdf03f989c4a335fe2cc8028e7a935e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 28 Mar 2024 16:16:36 +0100 Subject: [PATCH 144/231] srtr: do not assume buffer exhausted is a discontinuity also lower severity from warning to debug --- lib/upipe-srt/upipe_srt_receiver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 8bc62d97c..cf74c804d 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -618,9 +618,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) } if (--upipe_srt_receiver->buffered == 0) { - upipe_warn_va(upipe, "Exhausted buffer"); - upipe_srt_receiver->expected_seqnum = UINT64_MAX; - upipe_srt_receiver->last_output_seqnum = UINT64_MAX; + upipe_dbg_va(upipe, "Exhausted buffer"); } } } From c8990150daa2b3c6bb6bf2f1d0ec8677b2bd82a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 4 Apr 2024 14:40:26 +0200 Subject: [PATCH 145/231] srt: remove unneeded flags spotted by nto --- examples/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index 5b7839148..0c03cc9f6 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -25,10 +25,10 @@ noinst_PROGRAMS = fec_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPETS_LIBS) rist_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) -srt_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) -srt_rx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) -srt_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) $(UPIPESRT_LIBS) -srt_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) +srt_rx_CFLAGS = $(AM_CFLAGS) +srt_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPESRT_LIBS) +srt_tx_CFLAGS = $(AM_CFLAGS) +srt_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPESRT_LIBS) rist_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) rist_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) udpmulticat_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) From 8ef44cd348f9681f6add314dff3f214b87200b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 4 Apr 2024 14:40:58 +0200 Subject: [PATCH 146/231] srt_* : update copyright --- examples/srt_rx.c | 2 +- examples/srt_tx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/srt_rx.c b/examples/srt_rx.c index 4ae1c8dbb..fe9dffd69 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Open Broadcast Systems Ltd. + * Copyright (C) 2016-2024 Open Broadcast Systems Ltd. * * Authors: Rafaël Carré * diff --git a/examples/srt_tx.c b/examples/srt_tx.c index b3c6c254e..b30e15629 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Open Broadcast Systems Ltd. + * Copyright (C) 2016-2024 Open Broadcast Systems Ltd. * * Authors: Rafaël Carré * From 2dfe54997f14a697347d287d5809f84408d155e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 5 Apr 2024 14:11:17 +0200 Subject: [PATCH 147/231] srth: send rtt_0 downstream --- lib/upipe-srt/upipe_srt_handshake.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f095595a4..f6301179a 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -130,6 +130,8 @@ struct upipe_srt_handshake { uint64_t last_hs_sent; + uint64_t rtt_0; + /** public upipe structure */ struct upipe upipe; }; @@ -795,6 +797,8 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) upipe_err(upipe, "damn"); } + uref_clock_set_latency(flow_def, upipe_srt_handshake->rtt_0); + uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); /* force sending flow definition immediately */ @@ -1405,6 +1409,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_srt_handshake->caller_conclusion = NULL; } } else { + upipe_srt_handshake->rtt_0 = now - upipe_srt_handshake->last_hs_sent; if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); @@ -1418,6 +1423,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } } else { /* listener */ if (conclusion) { + upipe_srt_handshake->rtt_0 = now - upipe_srt_handshake->establish_time; uref = upipe_srt_handshake_handle_hs_listener_conclusion(upipe, size, timestamp, &hs_packet); } else { if (hs_packet.version != SRT_HANDSHAKE_VERSION_MIN || hs_packet.encryption != SRT_HANDSHAKE_CIPHER_NONE || From e67ae1340d9edda1aeff00befba6c350b13199cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 5 Apr 2024 14:18:35 +0200 Subject: [PATCH 148/231] srtr: get rtt from handshake Error if too big (> latency) --- lib/upipe-srt/upipe_srt_receiver.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index cf74c804d..9c1c77e9e 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -321,10 +321,6 @@ static uint64_t upipe_srt_receiver_get_rtt(struct upipe *upipe) { struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); - /* VSF TR-06 doesn't give a mean to retrieve RTT, but defaults to 7 - * retransmissions requests per packet. - * XXX: make it configurable ? */ - uint64_t rtt = upipe_srt_receiver->rtt; if (!rtt) rtt = upipe_srt_receiver->latency / 7; @@ -804,10 +800,13 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma } if (flow_format != NULL) { - uint64_t latency; - if (!ubase_check(uref_clock_get_latency(flow_format, &latency))) - latency = 0; - uref_clock_set_latency(flow_format, latency + upipe_srt_receiver->latency); + // FIXME + uint64_t rtt; + if (!ubase_check(uref_clock_get_latency(flow_format, &rtt))) + rtt = 0; + else + upipe_srt_receiver->rtt = rtt; + uref_clock_set_latency(flow_format, rtt + upipe_srt_receiver->latency); upipe_srt_receiver_store_flow_def(upipe, flow_format); } @@ -886,6 +885,16 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo return UBASE_ERR_INVALID; } + uint64_t rtt; + if (!ubase_check(uref_clock_get_latency(flow_def, &rtt))) + rtt = 0; + else + upipe_srt_receiver->rtt = rtt; + upipe_warn_va(upipe, "RTT %.2f us", (double)rtt / 27); + if (rtt > upipe_srt_receiver->latency) { + upipe_err_va(upipe, "Latency (%.2f us) is too small", (double)upipe_srt_receiver->latency / 27); + } + uint64_t id; if (ubase_check(uref_flow_get_id(flow_def, &id))) { if (upipe_srt_receiver->socket_id != id) From c686ac33a8dbfc725aa21a843cae36050e427686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 11 Apr 2024 14:18:32 +0000 Subject: [PATCH 149/231] srth: move upipe_srt_handshake_finalize() to upipe_srt_handshake_handle_hs_listener_conclusion() upipe_srt_handshake_handle_hs_caller_conclusion() is already calling finalize() That way we call it only on successful handshake --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index f6301179a..7d55d9761 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1329,6 +1329,8 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi #endif } + upipe_srt_handshake_finalize(upipe); + uref_block_unmap(uref, 0); return uref; } @@ -1454,8 +1456,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upump_start(upump); upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); } - } else { - upipe_srt_handshake_finalize(upipe); } } From 6506a023928b7158ed31aa679733305ef540d942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 11 Apr 2024 16:26:29 +0200 Subject: [PATCH 150/231] srth: reject handshake if we can't decipher key material --- lib/upipe-srt/upipe_srt_handshake.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 7d55d9761..72075e7ef 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1267,6 +1267,13 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi size -= ext_len; } + if (upipe_srt_handshake->password && upipe_srt_handshake->sek_len == 0) { + upipe_err(upipe, "Password specified but could not get streaming key"); + upipe_srt_handshake->expect_conclusion = false; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_BADSECRET); + } + int extension = 0; size = 0; if (hs_packet->version == SRT_HANDSHAKE_VERSION) { From 22b31816c23022c582a65504cf831fd856e97af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 11 Apr 2024 16:26:50 +0200 Subject: [PATCH 151/231] srth: reset syn_cookie when caller gets rejected --- lib/upipe-srt/upipe_srt_handshake.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 72075e7ef..2aded4612 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1372,6 +1372,8 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin uint32_t hs_type = srt_get_handshake_type(cif); if (hs_type >= SRT_HANDSHAKE_TYPE_REJ_UNKNOWN && hs_type <= SRT_HANDSHAKE_TYPE_REJ_GROUP) { upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); + if (!upipe_srt_handshake->listener) + upipe_srt_handshake->syn_cookie = 0; upipe_srt_handshake->expect_conclusion = false; return NULL; } From b1bb56ce477b2fb2797f9d09986bcee764d29bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 12 Apr 2024 16:18:41 +0200 Subject: [PATCH 152/231] srth: reject handshake with no password Ignore v4 handshake for now --- lib/upipe-srt/upipe_srt_handshake.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 2aded4612..2b2979a7f 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1241,6 +1241,8 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi const uint8_t *wrap; uint8_t wrap_len = 0; + bool got_key = false; + while (size >= SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE) { uint16_t ext_type = srt_get_handshake_extension_type(ext); uint16_t ext_len = 4 * srt_get_handshake_extension_len(ext); @@ -1260,14 +1262,14 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, SRT_HANDSHAKE_HSREQ_SIZE); } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { - upipe_srt_handshake_parse_kmreq(upipe, ext, ext_len, &wrap, &wrap_len); + got_key = upipe_srt_handshake_parse_kmreq(upipe, ext, ext_len, &wrap, &wrap_len); } ext += ext_len; size -= ext_len; } - if (upipe_srt_handshake->password && upipe_srt_handshake->sek_len == 0) { + if (upipe_srt_handshake->password && !got_key) { upipe_err(upipe, "Password specified but could not get streaming key"); upipe_srt_handshake->expect_conclusion = false; return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, From 4790a1776b8743a760a5cdcef818c86c3f06356b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Mon, 15 Apr 2024 17:59:15 +0200 Subject: [PATCH 153/231] srt: fix pc description --- lib/upipe-srt/libupipe_srt.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/libupipe_srt.pc.in b/lib/upipe-srt/libupipe_srt.pc.in index acc884a6b..5acea2e39 100644 --- a/lib/upipe-srt/libupipe_srt.pc.in +++ b/lib/upipe-srt/libupipe_srt.pc.in @@ -3,7 +3,7 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libupipe_srt -Description: Upipe multimedia framework, libsrt interface module +Description: Upipe multimedia framework, SRT modules Version: @VERSION@ Requires: libupipe Requires.private: libgcrypt From f98bb48bfdd049bec04e8fc42a2eb5d41997e55a Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 8 Apr 2024 20:06:35 +0100 Subject: [PATCH 154/231] srt_handshake: Send a socket_id of zero for a handshake rejection (cherry picked from commit 0d1cec2f0e3a3067dee1e74c00e53a1e079e82f8) (cherry picked from commit 839f1e55deb8d03372bd14bc0d7bcdaaae68029e) --- lib/upipe-srt/upipe_srt_handshake.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 2b2979a7f..14b555123 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -223,7 +223,7 @@ static void upipe_srt_handshake_shutdown(struct upipe *upipe) } -static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_size, uint32_t timestamp, uint8_t **cif) +static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_size, uint32_t timestamp, uint8_t **cif, bool reject) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -261,7 +261,7 @@ static struct uref *upipe_srt_handshake_alloc_hs(struct upipe *upipe, int ext_si srt_set_handshake_syn_cookie(out_cif, upipe_srt_handshake->syn_cookie); srt_set_handshake_mtu(out_cif, upipe_srt_handshake->mtu); srt_set_handshake_mfw(out_cif, upipe_srt_handshake->mfw); - srt_set_handshake_socket_id(out_cif, upipe_srt_handshake->socket_id); + srt_set_handshake_socket_id(out_cif, reject ? 0 : upipe_srt_handshake->socket_id); srt_set_handshake_isn(out_cif, upipe_srt_handshake->isn); srt_set_handshake_ip(out_cif, (const struct sockaddr*)&upipe_srt_handshake->addr); @@ -359,7 +359,7 @@ static void upipe_srt_handshake_send_timer(struct upump *upump) } else { //send HS uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif, false); if (!uref) return; @@ -1163,7 +1163,7 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_induction(struct upipe } uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif, false); if (!uref) return NULL; @@ -1183,7 +1183,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_induction(struct upip upipe_srt_handshake->syn_cookie = mrand48(); uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif, false); if (!uref) return NULL; @@ -1197,7 +1197,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_induction(struct upip static struct uref *upipe_srt_handshake_alloc_hs_reject(struct upipe *upipe, uint32_t timestamp, uint32_t dst_socket_id, uint32_t rejection_type) { uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif); + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, 0, timestamp, &out_cif, true); if (!uref) return NULL; @@ -1292,7 +1292,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi } uint8_t *out_cif; - struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif); + struct uref *uref = upipe_srt_handshake_alloc_hs(upipe, size, timestamp, &out_cif, false); if (!uref) return NULL; From b637feb75e073cbdfccb0279775f4c7428b2792a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 6 Jun 2024 11:04:21 +0200 Subject: [PATCH 155/231] Revert "srtr: get rtt from handshake" This reverts commit e67ae1340d9edda1aeff00befba6c350b13199cc. --- lib/upipe-srt/upipe_srt_receiver.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 9c1c77e9e..cf74c804d 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -321,6 +321,10 @@ static uint64_t upipe_srt_receiver_get_rtt(struct upipe *upipe) { struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); + /* VSF TR-06 doesn't give a mean to retrieve RTT, but defaults to 7 + * retransmissions requests per packet. + * XXX: make it configurable ? */ + uint64_t rtt = upipe_srt_receiver->rtt; if (!rtt) rtt = upipe_srt_receiver->latency / 7; @@ -800,13 +804,10 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma } if (flow_format != NULL) { - // FIXME - uint64_t rtt; - if (!ubase_check(uref_clock_get_latency(flow_format, &rtt))) - rtt = 0; - else - upipe_srt_receiver->rtt = rtt; - uref_clock_set_latency(flow_format, rtt + upipe_srt_receiver->latency); + uint64_t latency; + if (!ubase_check(uref_clock_get_latency(flow_format, &latency))) + latency = 0; + uref_clock_set_latency(flow_format, latency + upipe_srt_receiver->latency); upipe_srt_receiver_store_flow_def(upipe, flow_format); } @@ -885,16 +886,6 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo return UBASE_ERR_INVALID; } - uint64_t rtt; - if (!ubase_check(uref_clock_get_latency(flow_def, &rtt))) - rtt = 0; - else - upipe_srt_receiver->rtt = rtt; - upipe_warn_va(upipe, "RTT %.2f us", (double)rtt / 27); - if (rtt > upipe_srt_receiver->latency) { - upipe_err_va(upipe, "Latency (%.2f us) is too small", (double)upipe_srt_receiver->latency / 27); - } - uint64_t id; if (ubase_check(uref_flow_get_id(flow_def, &id))) { if (upipe_srt_receiver->socket_id != id) From 37f991d049dbe1b99e105649b6da4c97ec904503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 6 Jun 2024 11:04:24 +0200 Subject: [PATCH 156/231] Revert "srth: send rtt_0 downstream" This reverts commit 2dfe54997f14a697347d287d5809f84408d155e2. --- lib/upipe-srt/upipe_srt_handshake.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 14b555123..3821a9a53 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -130,8 +130,6 @@ struct upipe_srt_handshake { uint64_t last_hs_sent; - uint64_t rtt_0; - /** public upipe structure */ struct upipe upipe; }; @@ -797,8 +795,6 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) upipe_err(upipe, "damn"); } - uref_clock_set_latency(flow_def, upipe_srt_handshake->rtt_0); - uref_pic_set_number(flow_def, upipe_srt_handshake->isn); upipe_srt_handshake_store_flow_def(upipe, flow_def); /* force sending flow definition immediately */ @@ -1422,7 +1418,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_srt_handshake->caller_conclusion = NULL; } } else { - upipe_srt_handshake->rtt_0 = now - upipe_srt_handshake->last_hs_sent; if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); @@ -1436,7 +1431,6 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } } else { /* listener */ if (conclusion) { - upipe_srt_handshake->rtt_0 = now - upipe_srt_handshake->establish_time; uref = upipe_srt_handshake_handle_hs_listener_conclusion(upipe, size, timestamp, &hs_packet); } else { if (hs_packet.version != SRT_HANDSHAKE_VERSION_MIN || hs_packet.encryption != SRT_HANDSHAKE_CIPHER_NONE || From 2ea11fa71484415dcdec68a3a4124c05b3e350a1 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 6 Jun 2024 11:07:05 +0200 Subject: [PATCH 157/231] srt_tx: Reject new peer if one is already connected --- examples/srt_tx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/srt_tx.c b/examples/srt_tx.c index b30e15629..e48a7d305 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -186,6 +186,12 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, if (sig != UPIPE_UDPSRC_SIGNATURE) break; + ubase_assert(upipe_udpsink_get_fd(upipe_udpsink, &udp_fd)); + if (udp_fd >= 0) { + upipe_err(upipe, "Already connected, ignoring"); + return UBASE_ERR_UNKNOWN; + } + const struct sockaddr *s = va_arg(args, struct sockaddr*); const socklen_t *len = va_arg(args, socklen_t *); From 299154198f046e5690757c35b7581d3d12e8c823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 7 Jun 2024 13:57:14 +0200 Subject: [PATCH 158/231] srth: latency is the bigger of the two --- lib/upipe-srt/upipe_srt_handshake.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 3821a9a53..b73996986 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -822,10 +822,17 @@ static void upipe_srt_handshake_parse_hsreq(struct upipe *upipe, const uint8_t * (flags & SRT_HANDSHAKE_EXT_FLAG_PACKET_FILTER) ? "PACKET_FILTER " : ""); upipe_srt_handshake->flags = flags; + uint16_t receiver_tsbpd = upipe_srt_handshake->receiver_tsbpd_delay; + upipe_srt_handshake->receiver_tsbpd_delay = srt_get_handshake_extension_receiver_tsbpd_delay(ext); upipe_srt_handshake->sender_tsbpd_delay = srt_get_handshake_extension_sender_tsbpd_delay(ext); - upipe_dbg_va(upipe, "tsbpd delays: receiver %u, sender %u", - upipe_srt_handshake->receiver_tsbpd_delay, upipe_srt_handshake->sender_tsbpd_delay); + if (upipe_srt_handshake->receiver_tsbpd_delay < upipe_srt_handshake->sender_tsbpd_delay) + upipe_srt_handshake->receiver_tsbpd_delay = upipe_srt_handshake->sender_tsbpd_delay; + + if (upipe_srt_handshake->receiver_tsbpd_delay < receiver_tsbpd) + upipe_srt_handshake->receiver_tsbpd_delay = receiver_tsbpd; + + upipe_dbg_va(upipe, "latency receiver %u", upipe_srt_handshake->receiver_tsbpd_delay); } static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, const size_t ext_len, const uint8_t **wrap, uint8_t *wrap_len) From 25bdb37cf599a92fb1672031d769446bc81843dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 7 Jun 2024 14:44:17 +0200 Subject: [PATCH 159/231] srtr: allow latency to be set later and even changed --- lib/upipe-srt/upipe_srt_receiver.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index cf74c804d..8a68cb59d 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -798,11 +798,6 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma upipe_srt_receiver_check_upump_mgr(upipe); - if (upipe_srt_receiver->latency == 0) { - upipe_err(upipe, "Latency unset"); - return UBASE_ERR_UNKNOWN; - } - if (flow_format != NULL) { uint64_t latency; if (!ubase_check(uref_clock_get_latency(flow_format, &latency))) @@ -961,10 +956,6 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, return UBASE_ERR_INVALID; struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); - if (upipe_srt_receiver->latency) { - upipe_err(upipe, "Latency already set"); - return UBASE_ERR_UNHANDLED; - } unsigned latency_ms = atoi(v); upipe_srt_receiver->latency = latency_ms * UCLOCK_FREQ / 1000; upipe_dbg_va(upipe, "Set latency to %u msecs", latency_ms); From ca25e60efaca366ea5bfe42213514313cdbedd06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 7 Jun 2024 14:44:39 +0200 Subject: [PATCH 160/231] srth: sender latency defaults to 0 --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index b73996986..a038403da 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -571,7 +571,7 @@ static int upipe_srt_handshake_set_option(struct upipe *upipe, const char *optio if (!strcmp(option, "latency")) { upipe_srt_handshake->receiver_tsbpd_delay = atoi(value); - upipe_srt_handshake->sender_tsbpd_delay = atoi(value); + upipe_srt_handshake->sender_tsbpd_delay = 0; return UBASE_ERR_NONE; } From 365e8802d4fc768e2e97646b121c172d2d051031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 7 Jun 2024 14:45:03 +0200 Subject: [PATCH 161/231] srth: control to get negotiated latency --- include/upipe-srt/upipe_srt_handshake.h | 14 ++++++++++++++ lib/upipe-srt/upipe_srt_handshake.c | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h index a8e072d4f..389096e64 100644 --- a/include/upipe-srt/upipe_srt_handshake.h +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -50,6 +50,9 @@ enum upipe_srt_handshake_command { /** set the encryption password (const char *, int) */ UPIPE_SRT_HANDSHAKE_SET_PASSWORD, + + /** gets negociated latency (int *) */ + UPIPE_SRT_HANDSHAKE_GET_LATENCY, }; /** @This sets the peer address @@ -80,6 +83,17 @@ static inline int upipe_srt_handshake_set_password(struct upipe *upipe, password, key_len); } +/** @This sets the encryption key + * + * @param upipe description structure of the pipe + * @param latency_ms pointer to latency in ms + * @return false in case of error + */ +static inline int upipe_srt_handshake_get_latency(struct upipe *upipe, uint16_t *latency_ms) +{ + return upipe_control(upipe, UPIPE_SRT_HANDSHAKE_GET_LATENCY, UPIPE_SRT_HANDSHAKE_SIGNATURE, latency_ms); +} + /** @This returns the management structure for all srt handshakes sources. * * @return pointer to manager diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index a038403da..fc18000ff 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -671,6 +671,13 @@ static int _upipe_srt_handshake_control(struct upipe *upipe, return UBASE_ERR_NONE; } + case UPIPE_SRT_HANDSHAKE_GET_LATENCY: { + UBASE_SIGNATURE_CHECK(args, UPIPE_SRT_HANDSHAKE_SIGNATURE) + uint16_t *latency_ms = va_arg(args, uint16_t *); + *latency_ms = upipe_srt_handshake->receiver_tsbpd_delay; + return UBASE_ERR_NONE; + } + default: return UBASE_ERR_UNHANDLED; } From d9b7612713af2ec954ae6ec98e4c2dc560eee777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 7 Jun 2024 14:46:08 +0200 Subject: [PATCH 162/231] srt_rx: sets proper latency after handshake --- examples/srt_rx.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/srt_rx.c b/examples/srt_rx.c index fe9dffd69..e5754d6b4 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -162,6 +162,7 @@ static struct upump_mgr *upump_mgr; static struct upipe *upipe_udpsrc; static struct upipe *upipe_udp_sink; +static struct upipe *upipe_srtr; static struct upipe *upipe_srtr_sub; static struct uprobe uprobe_udp; @@ -221,11 +222,9 @@ static int start(void) upipe_mgr_release(upipe_srt_handshake_mgr); struct upipe_mgr *upipe_srt_receiver_mgr = upipe_srt_receiver_mgr_alloc(); - struct upipe *upipe_srtr = upipe_void_chain_output(upipe_srth, + upipe_srtr = upipe_void_chain_output(upipe_srth, upipe_srt_receiver_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "srtr")); assert(upipe_srtr); - if (!ubase_check(upipe_set_option(upipe_srtr, "latency", latency))) - return EXIT_FAILURE; upipe_mgr_release(upipe_srt_receiver_mgr); @@ -290,6 +289,7 @@ static void stop(struct upump *upump) upipe_release(upipe_udpsrc); upipe_release(upipe_srtr_sub); + upipe_srtr = NULL; if (restart) { restart = false; @@ -319,6 +319,19 @@ static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, return UBASE_ERR_NONE; } + if (event == UPROBE_NEW_FLOW_DEF && upipe_srtr) { + uint16_t latency_ms; + if (!ubase_check(upipe_srt_handshake_get_latency(upipe, &latency_ms))) + upipe_err(upipe, "Couldn't get latency"); + else { + upipe_notice_va(upipe, "Latency %hu ms", latency_ms); + char latency_ms_str[16]; + snprintf(latency_ms_str, sizeof(latency_ms_str), "%hu", latency_ms); + if (!ubase_check(upipe_set_option(upipe_srtr, "latency", latency_ms_str))) + upipe_err(upipe, "Couldn't set receiver latency"); + } + } + return uprobe_throw_next(uprobe, upipe, event, args); } From ff8f006948474b68ae52423407d92d831e1bb790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 7 Jun 2024 12:54:36 +0000 Subject: [PATCH 163/231] srt_tx: sets proper latency after handshake --- examples/srt_tx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/srt_tx.c b/examples/srt_tx.c index e48a7d305..5a8729699 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -138,6 +138,8 @@ static void stop(struct upump *upump); static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { + uint16_t latency_ms; + switch (event) { case UPROBE_SOURCE_END: upipe_warn(upipe, "Remote shutdown"); @@ -145,6 +147,16 @@ static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, NULL, UCLOCK_FREQ, 0); upump_start(u); return uprobe_throw_next(uprobe, upipe, event, args); + case UPROBE_NEW_FLOW_DEF: + if (!ubase_check(upipe_srt_handshake_get_latency(upipe, &latency_ms))) + upipe_err(upipe, "Couldn't get latency"); + else { + upipe_notice_va(upipe, "Latency %hu ms", latency_ms); + char latency_ms_str[16]; + snprintf(latency_ms_str, sizeof(latency_ms_str), "%hu", latency_ms); + if (!ubase_check(upipe_set_option(upipe_srt_sender, "latency", latency_ms_str))) + upipe_err(upipe, "Couldn't set sender latency"); + } } return uprobe_throw_next(uprobe, upipe, event, args); } From a34c94c915de9bd3f999bf1d87b52009e4b0c823 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 10 Jun 2024 14:43:58 +0100 Subject: [PATCH 164/231] srth: Add comments to clarify latency negotiation logic --- lib/upipe-srt/upipe_srt_handshake.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index fc18000ff..d0e5aed54 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -102,7 +102,7 @@ struct upipe_srt_handshake { uint32_t mfw; - uint16_t receiver_tsbpd_delay; + uint16_t receiver_tsbpd_delay; /* stores negotiated latency */ uint16_t sender_tsbpd_delay; uint32_t flags; uint16_t major; @@ -829,6 +829,7 @@ static void upipe_srt_handshake_parse_hsreq(struct upipe *upipe, const uint8_t * (flags & SRT_HANDSHAKE_EXT_FLAG_PACKET_FILTER) ? "PACKET_FILTER " : ""); upipe_srt_handshake->flags = flags; + /* Latency is MAX(sender_tsbpd_delay, receiver_tsbpd_delay). Arbitrarily use receiver_tsbpd_delay variable as the latency */ uint16_t receiver_tsbpd = upipe_srt_handshake->receiver_tsbpd_delay; upipe_srt_handshake->receiver_tsbpd_delay = srt_get_handshake_extension_receiver_tsbpd_delay(ext); @@ -839,7 +840,7 @@ static void upipe_srt_handshake_parse_hsreq(struct upipe *upipe, const uint8_t * if (upipe_srt_handshake->receiver_tsbpd_delay < receiver_tsbpd) upipe_srt_handshake->receiver_tsbpd_delay = receiver_tsbpd; - upipe_dbg_va(upipe, "latency receiver %u", upipe_srt_handshake->receiver_tsbpd_delay); + upipe_dbg_va(upipe, "Negotiated latency %u ms", upipe_srt_handshake->receiver_tsbpd_delay); } static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t *ext, const size_t ext_len, const uint8_t **wrap, uint8_t *wrap_len) From 4d86f59cc64b21ecf776ce0c9f0480994d56e4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 13 Jun 2024 11:09:32 +0200 Subject: [PATCH 165/231] srth: send correct key in kmreq --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index d0e5aed54..da9d29d7f 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -982,8 +982,8 @@ static bool upipe_srt_handshake_wrap_key(struct upipe *upipe, uint8_t *wrap) } uint8_t clear_wrap[2*256/8]; - memcpy(&clear_wrap[0],upipe_srt_handshake->sek[0], klen); - memcpy(&clear_wrap[klen],upipe_srt_handshake->sek[1], klen); + memcpy(&clear_wrap[0], upipe_srt_handshake->sek[(upipe_srt_handshake->kk == 2) ? 1 : 0], klen); + memcpy(&clear_wrap[klen], upipe_srt_handshake->sek[1], klen); err = gcry_cipher_encrypt(aes, wrap, wrap_len, clear_wrap, wrap_len - 8); if (err) { From d069633236a12d892b897ea12ffe799ed4c91dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 13 Jun 2024 14:54:42 +0200 Subject: [PATCH 166/231] srts: delete old key from memory --- lib/upipe-srt/upipe_srt_sender.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 3cdd7415d..e479a170d 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -672,6 +672,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { upipe_dbg_va(upipe, "Switching to %s key", even_key ? "even" : "odd"); + memset(upipe_srt_sender->sek[even_key], 0, sizeof(upipe_srt_sender->sek[0])); } else { upipe_dbg(upipe, "Encryption disabled"); } From dde433d1f71c88718c6823b6c73a5e54a97adaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 14 Jun 2024 08:28:56 +0000 Subject: [PATCH 167/231] srts: delete key only after the required period has elapsed --- lib/upipe-srt/upipe_srt_sender.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index e479a170d..8d3f59fcd 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -672,12 +672,13 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { upipe_dbg_va(upipe, "Switching to %s key", even_key ? "even" : "odd"); - memset(upipe_srt_sender->sek[even_key], 0, sizeof(upipe_srt_sender->sek[0])); } else { upipe_dbg(upipe, "Encryption disabled"); } upipe_srt_sender->even_key = even_key; + } else if (upipe_srt_sender->packets_since_key == 2 * SRT_KM_PRE_ANNOUNCEMENT_PERIOD) { + memset(upipe_srt_sender->sek[upipe_srt_sender->even_key], 0, sizeof(upipe_srt_sender->sek[0])); } int key = !upipe_srt_sender->even_key; From 1a2dd3832bf4b6663efeb393951ce6ae98950835 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 14 Jun 2024 14:26:12 +0100 Subject: [PATCH 168/231] srts: Add some comments --- lib/upipe-srt/upipe_srt_sender.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 8d3f59fcd..f337c647f 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -596,6 +596,10 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->seqnum = 0; upipe_srt_sender->establish_time = 0; + /* Note: 0 is the even key and 1 is the odd key. + When upipe_srt_sender->even_key = true + upipe_srt_sender->sek[!upipe_srt_sender->even_key] is the even key + */ upipe_srt_sender->sek_len[0] = 0; upipe_srt_sender->sek_len[1] = 0; upipe_srt_sender->even_key = true; @@ -662,6 +666,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref #ifdef UPIPE_HAVE_GCRYPT_H if (++upipe_srt_sender->packets_since_key == SRT_KM_PRE_ANNOUNCEMENT_PERIOD) { + /* invert the boolean to get the right index */ int even_key = !upipe_srt_sender->even_key; if (!upipe_srt_sender->sek_len[!even_key] && upipe_srt_sender->sek_len[even_key]) { @@ -681,6 +686,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref memset(upipe_srt_sender->sek[upipe_srt_sender->even_key], 0, sizeof(upipe_srt_sender->sek[0])); } + /* invert the boolean to get the right index */ int key = !upipe_srt_sender->even_key; if (upipe_srt_sender->sek_len[key]) { // From 7bcc47c392ff16ef96ae9edf2ec29ddd5d5da457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 27 Jun 2024 12:23:16 +0000 Subject: [PATCH 169/231] srt_tx: only count data packets for key refresh They are the only ones being encrypted --- examples/srt_tx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/srt_tx.c b/examples/srt_tx.c index 5a8729699..d2a0ccff3 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -61,6 +61,8 @@ #include #include +#include + #ifdef UPIPE_HAVE_GCRYPT_H #include #endif @@ -168,7 +170,17 @@ static int catch_uref(struct uprobe *uprobe, struct upipe *upipe, switch (event) { case UPROBE_PROBE_UREF: UBASE_SIGNATURE_CHECK(args, UPIPE_PROBE_UREF_SIGNATURE); - //struct uref *uref = va_arg(args, struct uref *); + struct uref *uref = va_arg(args, struct uref *); + + const uint8_t *buf; + int s = -1; + if (!ubase_check(uref_block_read(uref, 0, &s, &buf))) + return UBASE_ERR_INVALID; + bool ctrl = srt_get_packet_control(buf); + uref_block_unmap(uref, 0); + + if (ctrl) + return UBASE_ERR_NONE; if (packets++ == km_refresh_period) { packets = 0; From a27440127e6aa5e1e837ba245ada94ab77ede1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 14 Mar 2024 16:22:21 +0100 Subject: [PATCH 170/231] dejitter: get rid of initial "max jitter reached" message --- lib/upipe/uprobe_dejitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index 1a236268d..798c189cf 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -101,7 +101,7 @@ static int uprobe_dejitter_clock_ref(struct uprobe *uprobe, struct upipe *upipe, double offset = (double)((int64_t)cr_sys - (int64_t)cr_prog); if (unlikely(discontinuity)) upipe_warn(upipe, "[dejitter] discontinuity"); - else if (unlikely(fabs(offset - uprobe_dejitter->offset) > + else if (unlikely(uprobe_dejitter->offset && fabs(offset - uprobe_dejitter->offset) > MAX_JITTER + 3 * uprobe_dejitter->deviation)) { upipe_warn_va(upipe, "[dejitter] max jitter reached (%f ms)", (offset - uprobe_dejitter->offset) * 1000 / UCLOCK_FREQ); From d3f84d255a0b9a6011e0e4141120d0e2d43f8a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 14 Mar 2024 16:22:41 +0100 Subject: [PATCH 171/231] dejitter: start with initial deviation, not sqrt(2)/2 --- lib/upipe/uprobe_dejitter.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index 798c189cf..3d130b7df 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -121,10 +121,11 @@ static int uprobe_dejitter_clock_ref(struct uprobe *uprobe, struct upipe *upipe, uprobe_dejitter->offset_count++; double deviation = offset - uprobe_dejitter->offset; - uprobe_dejitter->deviation = - sqrt((uprobe_dejitter->deviation * uprobe_dejitter->deviation * - uprobe_dejitter->deviation_count + deviation * deviation) / - (uprobe_dejitter->deviation_count + 1)); + if (uprobe_dejitter->deviation_count) + uprobe_dejitter->deviation = + sqrt((uprobe_dejitter->deviation * uprobe_dejitter->deviation * + uprobe_dejitter->deviation_count + deviation * deviation) / + (uprobe_dejitter->deviation_count + 1)); if (uprobe_dejitter->deviation_count < uprobe_dejitter->deviation_divider) uprobe_dejitter->deviation_count++; @@ -282,7 +283,7 @@ void uprobe_dejitter_set(struct uprobe *uprobe, bool enabled, uprobe_dejitter->offset_divider = enabled ? OFFSET_DIVIDER : 0; uprobe_dejitter->deviation_divider = enabled ? DEVIATION_DIVIDER : 0; uprobe_dejitter->offset_count = 0; - uprobe_dejitter->deviation_count = 1; + uprobe_dejitter->deviation_count = 0; uprobe_dejitter->offset = 0; if (deviation) uprobe_dejitter->deviation = deviation; From b12aaeea37af2cbac0c57e21f4c7013a811ecb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 14 Mar 2024 16:24:10 +0100 Subject: [PATCH 172/231] dejitter: print debug in milliseconds --- lib/upipe/uprobe_dejitter.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index 3d130b7df..aa7147dca 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -195,16 +195,19 @@ static int uprobe_dejitter_clock_ref(struct uprobe *uprobe, struct upipe *upipe, if (cr_sys > uprobe_dejitter->last_print + PRINT_PERIODICITY) { upipe_dbg_va(upipe, - "dejitter drift %f error %"PRId64" deviation %g", + "dejitter drift %f error %g ms deviation %g ms", (double)uprobe_dejitter->drift_rate.num / uprobe_dejitter->drift_rate.den, - error_offset, uprobe_dejitter->deviation); + (double)error_offset * 1000 / UCLOCK_FREQ, + uprobe_dejitter->deviation * 1000 / UCLOCK_FREQ); uprobe_dejitter->last_print = cr_sys; } upipe_verbose_va(upipe, - "new ref offset %"PRId64" error %"PRId64" deviation %g", - real_offset, error_offset, uprobe_dejitter->deviation); + "new ref offset %.2g ms error %.2g ms deviation %g ms", + (double)real_offset * 1000. / UCLOCK_FREQ, + (double)error_offset * 1000. / UCLOCK_FREQ, + uprobe_dejitter->deviation * 1000. / UCLOCK_FREQ); return UBASE_ERR_NONE; } From 4956480d644664d755a19ade9b005b1abd4b0fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 5 Apr 2024 15:04:50 +0200 Subject: [PATCH 173/231] dejitter: maximum_deviation --- include/upipe/uprobe_dejitter.h | 10 ++++++++++ lib/upipe/uprobe_dejitter.c | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/upipe/uprobe_dejitter.h b/include/upipe/uprobe_dejitter.h index f2bf8a376..332f1a6bd 100644 --- a/include/upipe/uprobe_dejitter.h +++ b/include/upipe/uprobe_dejitter.h @@ -58,6 +58,8 @@ struct uprobe_dejitter { double deviation; /** minimum deviation */ double minimum_deviation; + /** maximum deviation */ + double maximum_deviation; /** cr_prog of last clock ref */ uint64_t last_cr_prog; @@ -120,6 +122,14 @@ void uprobe_dejitter_set(struct uprobe *uprobe, bool enabled, void uprobe_dejitter_set_minimum_deviation(struct uprobe *uprobe, double deviation); +/** @This sets the maximum deviation of the dejittering probe. + * + * @param uprobe pointer to probe + * @param deviation maximum deviation to set + */ +void uprobe_dejitter_set_maximum_deviation(struct uprobe *uprobe, + double deviation); + #ifdef __cplusplus } #endif diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index aa7147dca..fd56ac931 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -131,6 +131,8 @@ static int uprobe_dejitter_clock_ref(struct uprobe *uprobe, struct upipe *upipe, if (uprobe_dejitter->deviation < uprobe_dejitter->minimum_deviation) uprobe_dejitter->deviation = uprobe_dejitter->minimum_deviation; + if (uprobe_dejitter->deviation > uprobe_dejitter->maximum_deviation) + uprobe_dejitter->deviation = uprobe_dejitter->maximum_deviation; int64_t wanted_offset = uprobe_dejitter->offset + 3 * uprobe_dejitter->deviation; @@ -295,6 +297,8 @@ void uprobe_dejitter_set(struct uprobe *uprobe, bool enabled, if (uprobe_dejitter->deviation < uprobe_dejitter->minimum_deviation) uprobe_dejitter->deviation = uprobe_dejitter->minimum_deviation; + if (uprobe_dejitter->deviation > uprobe_dejitter->maximum_deviation) + uprobe_dejitter->deviation = uprobe_dejitter->maximum_deviation; } /** @This sets the minimum deviation of the dejittering probe. @@ -312,6 +316,21 @@ void uprobe_dejitter_set_minimum_deviation(struct uprobe *uprobe, uprobe_dejitter->deviation = deviation; } +/** @This sets the maximum deviation of the dejittering probe. + * + * @param uprobe pointer to probe + * @param deviation maximum deviation to set + */ +void uprobe_dejitter_set_maximum_deviation(struct uprobe *uprobe, + double deviation) +{ + struct uprobe_dejitter *uprobe_dejitter = + uprobe_dejitter_from_uprobe(uprobe); + uprobe_dejitter->maximum_deviation = deviation; + if (uprobe_dejitter->deviation < deviation) + uprobe_dejitter->deviation = deviation; +} + /** @This initializes an already allocated uprobe_dejitter structure. * * @param uprobe_pfx pointer to the already allocated structure From c5ea27df794e6d07021aaa31752bdc277b4bb1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 27 Jun 2024 16:28:20 +0200 Subject: [PATCH 174/231] srt_tx: use minimum and maximum deviation for dejitter --- examples/srt_rx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/srt_rx.c b/examples/srt_rx.c index e5754d6b4..2280d156c 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -426,7 +426,10 @@ int main(int argc, char *argv[]) UPUMP_BLOCKER_POOL); logger = uprobe_stdio_alloc(NULL, stdout, loglevel); assert(logger != NULL); - struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); + const uint64_t deviation = UCLOCK_FREQ / 30; // actual delay is 3 * this + struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true /* enabled */, deviation); + uprobe_dejitter_set_minimum_deviation(uprobe_dejitter, deviation); + uprobe_dejitter_set_maximum_deviation(uprobe_dejitter, deviation); assert(uprobe_dejitter != NULL); logger = uprobe_uref_mgr_alloc(uprobe_dejitter, uref_mgr); From 91833538708e152b5d4bdef70edc4c58e7bf93c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 27 Jun 2024 16:34:55 +0200 Subject: [PATCH 175/231] srtr: throw clock events sets cr_prog properly and handle wraparound --- lib/upipe-srt/upipe_srt_receiver.c | 38 +++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 8a68cb59d..8a44d10d1 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -151,6 +151,8 @@ struct upipe_srt_receiver { uint64_t establish_time; + uint64_t previous_ts; + /** public upipe structure */ struct upipe upipe; }; @@ -781,6 +783,8 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->establish_time = 0; + upipe_srt_receiver->previous_ts = 0; + upipe_throw_ready(upipe); return upipe; } @@ -920,6 +924,8 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo if (!flow_def) return UBASE_ERR_ALLOC; + uref_clock_set_wrap(flow_def, UINT64_C(4294967296) * UCLOCK_FREQ / 1000000); + upipe_srt_receiver_store_flow_def(upipe, flow_def); return UBASE_ERR_NONE; @@ -1208,12 +1214,29 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ total_size -= SRT_HEADER_SIZE; + uref_clock_set_cr_prog(uref, ts * UCLOCK_FREQ / 1000000); + +#define MAX_CLOCK_REF_INTERVAL UCLOCK_FREQ // FIXME + + static const uint64_t wrap = UINT64_C(4294967296); + uint64_t delta = (wrap + ts - (upipe_srt_receiver->previous_ts % wrap)) % wrap; + int32_t d32 = delta; + bool discontinuity = false; + if (d32 <= MAX_CLOCK_REF_INTERVAL || -d32 <= MAX_CLOCK_REF_INTERVAL) { + if (d32 <= MAX_CLOCK_REF_INTERVAL) + upipe_srt_receiver->previous_ts += delta; + else if (!retransmit) + discontinuity = true; + } else { + upipe_warn_va(upipe, "clock ref discontinuity %"PRIu64, delta); + upipe_srt_receiver->previous_ts = ts; + discontinuity = true; + } + upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); (void)order; (void)num; - (void)retransmit; // stats? - (void)ts; // TODO (µs) /* store seqnum in uref */ uref_attr_set_priv(uref, seqnum); @@ -1309,12 +1332,21 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, } upipe_srt_receiver->expected_seqnum = (seqnum + 1) & ~(1 << 31); + + if (!retransmit) { + upipe_throw_clock_ref(upipe, uref, + upipe_srt_receiver->previous_ts * UCLOCK_FREQ / 1000000, discontinuity); + } + + upipe_throw_clock_ts(upipe, uref); return; } /* packet is from the past, reordered or retransmitted */ - if (upipe_srt_receiver_insert(upipe, uref, seqnum)) + if (upipe_srt_receiver_insert(upipe, uref, seqnum)) { + upipe_throw_clock_ts(upipe, uref); return; + } uint64_t first_seq = 0, last_seq = 0; uref_attr_get_priv(uref_from_uchain(upipe_srt_receiver->queue.next), &first_seq); From 7aedf37648782b41dca846dc450bf66636597206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 28 Jun 2024 11:26:48 +0200 Subject: [PATCH 176/231] srtr: handle now < cr_sys --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 8a44d10d1..fd97ce94b 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -584,7 +584,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) upipe_warn_va(upipe, "Couldn't read cr_sys in %s()", __func__); - if (now - cr_sys <= upipe_srt_receiver->latency - rtt) + if (now <= cr_sys + upipe_srt_receiver->latency - rtt) break; upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); From 7fe4a08de478c5264bc7957a3a9a89d3ecc53db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 28 Jun 2024 13:12:14 +0200 Subject: [PATCH 177/231] srt/rist: use monotonic clock --- examples/rist_rx.c | 2 +- examples/rist_tx.c | 2 +- examples/srt_rx.c | 2 +- examples/srt_tx.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/rist_rx.c b/examples/rist_rx.c index 65520f552..8040c6339 100644 --- a/examples/rist_rx.c +++ b/examples/rist_rx.c @@ -331,7 +331,7 @@ int main(int argc, char *argv[]) udp_sink_mgr = upipe_udpsink_mgr_alloc(); - uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + uclock = uclock_std_alloc(0); logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); diff --git a/examples/rist_tx.c b/examples/rist_tx.c index af0ed000d..018f22707 100644 --- a/examples/rist_tx.c +++ b/examples/rist_tx.c @@ -305,7 +305,7 @@ int main(int argc, char *argv[]) 0); struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); - struct uclock *uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + struct uclock *uclock = uclock_std_alloc(0); struct uprobe uprobe; uprobe_init(&uprobe, catch, NULL); struct uprobe *logger = uprobe_stdio_alloc(&uprobe, stdout, loglevel); diff --git a/examples/srt_rx.c b/examples/srt_rx.c index 2280d156c..0940041b2 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -444,7 +444,7 @@ int main(int argc, char *argv[]) udp_sink_mgr = upipe_udpsink_mgr_alloc(); - uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + uclock = uclock_std_alloc(0); logger = uprobe_obe_log_alloc(logger); diff --git a/examples/srt_tx.c b/examples/srt_tx.c index d2a0ccff3..4c1b30419 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -413,7 +413,7 @@ int main(int argc, char *argv[]) 0); upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); - struct uclock *uclock = uclock_std_alloc(UCLOCK_FLAG_REALTIME); + struct uclock *uclock = uclock_std_alloc(0); logger = uprobe_stdio_alloc(NULL, stdout, loglevel); assert(logger != NULL); struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true, 0); From 025aac505b2afb82d13181426d425a5bb4309cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 5 Jul 2024 14:05:53 +0200 Subject: [PATCH 178/231] srtr: handle ts wraparound when setting cr_prog --- lib/upipe-srt/upipe_srt_receiver.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index fd97ce94b..d0fbaff21 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -153,6 +153,8 @@ struct upipe_srt_receiver { uint64_t previous_ts; + uint64_t ts_wraparounds; + /** public upipe structure */ struct upipe upipe; }; @@ -785,6 +787,8 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->previous_ts = 0; + upipe_srt_receiver->ts_wraparounds = 0; + upipe_throw_ready(upipe); return upipe; } @@ -1214,8 +1218,6 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ total_size -= SRT_HEADER_SIZE; - uref_clock_set_cr_prog(uref, ts * UCLOCK_FREQ / 1000000); - #define MAX_CLOCK_REF_INTERVAL UCLOCK_FREQ // FIXME static const uint64_t wrap = UINT64_C(4294967296); @@ -1223,16 +1225,24 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, int32_t d32 = delta; bool discontinuity = false; if (d32 <= MAX_CLOCK_REF_INTERVAL || -d32 <= MAX_CLOCK_REF_INTERVAL) { - if (d32 <= MAX_CLOCK_REF_INTERVAL) + if (d32 <= MAX_CLOCK_REF_INTERVAL) { + if (ts < upipe_srt_receiver->previous_ts) + upipe_srt_receiver->ts_wraparounds++; upipe_srt_receiver->previous_ts += delta; - else if (!retransmit) + } else if (!retransmit) { + upipe_srt_receiver->previous_ts = ts; + upipe_srt_receiver->ts_wraparounds = 0; discontinuity = true; + } } else { upipe_warn_va(upipe, "clock ref discontinuity %"PRIu64, delta); upipe_srt_receiver->previous_ts = ts; + upipe_srt_receiver->ts_wraparounds = 0; discontinuity = true; } + uref_clock_set_cr_prog(uref, (upipe_srt_receiver->ts_wraparounds * wrap + ts) * UCLOCK_FREQ / 1000000); + upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); (void)order; From dc53e42cbd43fb1147926221a40fafff43588f66 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 30 Mar 2024 23:35:36 +0000 Subject: [PATCH 179/231] srt_receiver: Remove old and wrong use of RTT in calculation --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index d0fbaff21..ea73027ba 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -586,7 +586,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) upipe_warn_va(upipe, "Couldn't read cr_sys in %s()", __func__); - if (now <= cr_sys + upipe_srt_receiver->latency - rtt) + if (now <= cr_sys + upipe_srt_receiver->latency) break; upipe_verbose_va(upipe, "Output seq %"PRIu64" after %"PRIu64" clocks", seqnum, now - cr_sys); From 6cab5704460a0b9ec15e37db30f6894265a8761d Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Aug 2024 09:10:06 +0100 Subject: [PATCH 180/231] srt_receiver: Calculate wraparound correctly --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index ea73027ba..e65040980 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1226,7 +1226,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, bool discontinuity = false; if (d32 <= MAX_CLOCK_REF_INTERVAL || -d32 <= MAX_CLOCK_REF_INTERVAL) { if (d32 <= MAX_CLOCK_REF_INTERVAL) { - if (ts < upipe_srt_receiver->previous_ts) + if (ts < (upipe_srt_receiver->previous_ts % wrap)) upipe_srt_receiver->ts_wraparounds++; upipe_srt_receiver->previous_ts += delta; } else if (!retransmit) { From 2e7c035ba14c2488dfc9b8b8b66802ec566d945c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Aug 2024 09:13:27 +0100 Subject: [PATCH 181/231] srt_receiver: Add FIXME --- lib/upipe-srt/upipe_srt_receiver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index e65040980..88259409e 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1241,6 +1241,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, discontinuity = true; } + // FIXME handle retransmission from pre-wraparound uref_clock_set_cr_prog(uref, (upipe_srt_receiver->ts_wraparounds * wrap + ts) * UCLOCK_FREQ / 1000000); upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); From 4b96441eee5ae72d0f4615087459bf7885c72e16 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Aug 2024 14:39:48 +0100 Subject: [PATCH 182/231] upipe_srt_receiver: Increase timer frequency. Reduces IAT at high bitrates --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 88259409e..6cb635ba7 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -839,7 +839,7 @@ static int upipe_srt_receiver_check(struct upipe *upipe, struct uref *flow_forma upump_alloc_timer(upipe_srt_receiver->upump_mgr, upipe_srt_receiver_timer, upipe, upipe->refcount, - UCLOCK_FREQ/300, UCLOCK_FREQ/300); + UCLOCK_FREQ/1000, UCLOCK_FREQ/1000); upump_start(upump); upipe_srt_receiver_set_upump_timer(upipe, upump); From 812127c17d710ea71c1e4cfa0c061ea48e0e1456 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Aug 2024 19:31:57 +0100 Subject: [PATCH 183/231] upipe_srt_receiver: Set retransmitted cr_prog correctly --- lib/upipe-srt/upipe_srt_receiver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 6cb635ba7..97634f71f 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1245,6 +1245,10 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uref_clock_set_cr_prog(uref, (upipe_srt_receiver->ts_wraparounds * wrap + ts) * UCLOCK_FREQ / 1000000); upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); + if (d32 < 0) + uref_clock_set_cr_prog(uref, (upipe_srt_receiver->previous_ts + d32) * UCLOCK_FREQ / 1000000); + else + uref_clock_set_cr_prog(uref, (upipe_srt_receiver->previous_ts) * UCLOCK_FREQ / 1000000); (void)order; (void)num; From ac1cb867da419b75d8e8400e8c9d309848c92705 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Aug 2024 19:32:20 +0100 Subject: [PATCH 184/231] upipe_srt_receiver: Clarify type promotion --- lib/upipe-srt/upipe_srt_receiver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 97634f71f..91b753b20 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1224,6 +1224,8 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uint64_t delta = (wrap + ts - (upipe_srt_receiver->previous_ts % wrap)) % wrap; int32_t d32 = delta; bool discontinuity = false; + + /* Note: d32 is converted to unsigned implictly */ if (d32 <= MAX_CLOCK_REF_INTERVAL || -d32 <= MAX_CLOCK_REF_INTERVAL) { if (d32 <= MAX_CLOCK_REF_INTERVAL) { if (ts < (upipe_srt_receiver->previous_ts % wrap)) From 92ad5c0d1886ba5af44c6725d52c033c242ed1b5 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 16 Aug 2024 14:32:03 +0100 Subject: [PATCH 185/231] upipe_srt_receiver: Use latency for validity window --- lib/upipe-srt/upipe_srt_receiver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 91b753b20..fddfdf6bc 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1218,15 +1218,13 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ total_size -= SRT_HEADER_SIZE; -#define MAX_CLOCK_REF_INTERVAL UCLOCK_FREQ // FIXME - static const uint64_t wrap = UINT64_C(4294967296); uint64_t delta = (wrap + ts - (upipe_srt_receiver->previous_ts % wrap)) % wrap; int32_t d32 = delta; bool discontinuity = false; /* Note: d32 is converted to unsigned implictly */ - if (d32 <= MAX_CLOCK_REF_INTERVAL || -d32 <= MAX_CLOCK_REF_INTERVAL) { + if (d32 <= upipe_srt_receiver->latency || -d32 <= upipe_srt_receiver->latency) { if (d32 <= MAX_CLOCK_REF_INTERVAL) { if (ts < (upipe_srt_receiver->previous_ts % wrap)) upipe_srt_receiver->ts_wraparounds++; From 33f5e8963cfcb5affbb581b71616ad65b76efd6f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 16 Aug 2024 18:07:09 +0100 Subject: [PATCH 186/231] upipe_srt_receiver: Remove FIXME --- lib/upipe-srt/upipe_srt_receiver.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index fddfdf6bc..3b913f2bd 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1241,9 +1241,6 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, discontinuity = true; } - // FIXME handle retransmission from pre-wraparound - uref_clock_set_cr_prog(uref, (upipe_srt_receiver->ts_wraparounds * wrap + ts) * UCLOCK_FREQ / 1000000); - upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); if (d32 < 0) uref_clock_set_cr_prog(uref, (upipe_srt_receiver->previous_ts + d32) * UCLOCK_FREQ / 1000000); From a2a7a5960880a136fe1c562164b63513554bb0e2 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 16 Aug 2024 18:25:58 +0100 Subject: [PATCH 187/231] upipe_srt_receiver: Fix typo --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 3b913f2bd..d99ba8e22 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1225,7 +1225,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, /* Note: d32 is converted to unsigned implictly */ if (d32 <= upipe_srt_receiver->latency || -d32 <= upipe_srt_receiver->latency) { - if (d32 <= MAX_CLOCK_REF_INTERVAL) { + if (d32 <= upipe_srt_receiver->latency) { if (ts < (upipe_srt_receiver->previous_ts % wrap)) upipe_srt_receiver->ts_wraparounds++; upipe_srt_receiver->previous_ts += delta; From 049d88679f485ac0ef10c5a813899197f7ca3b44 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 20 Aug 2024 12:23:30 +0100 Subject: [PATCH 188/231] dejitter: Fix typo --- lib/upipe/uprobe_dejitter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index fd56ac931..161055b86 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -327,7 +327,7 @@ void uprobe_dejitter_set_maximum_deviation(struct uprobe *uprobe, struct uprobe_dejitter *uprobe_dejitter = uprobe_dejitter_from_uprobe(uprobe); uprobe_dejitter->maximum_deviation = deviation; - if (uprobe_dejitter->deviation < deviation) + if (uprobe_dejitter->deviation > deviation) uprobe_dejitter->deviation = deviation; } From 2987cd21ae10b5bee86c1c8737e9310fa9f8564d Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 20 Aug 2024 12:31:50 +0100 Subject: [PATCH 189/231] dejitter: Add missing initaliser --- lib/upipe/uprobe_dejitter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index 161055b86..9f3e28d7b 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -348,6 +348,7 @@ struct uprobe *uprobe_dejitter_init(struct uprobe_dejitter *uprobe_dejitter, uprobe_dejitter->drift_rate.num = uprobe_dejitter->drift_rate.den = 1; uprobe_dejitter->last_print = 0; uprobe_dejitter->minimum_deviation = 0; + uprobe_dejitter->maximum_deviation = 0; uprobe_dejitter_set(uprobe, enabled, deviation); uprobe_init(uprobe, uprobe_dejitter_throw, next); return uprobe; From 2942f16df79ac5fda39228625dc5c10e68b273f7 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Aug 2024 11:01:34 +0100 Subject: [PATCH 190/231] srt_receiver: Remove unused ts_wraparounds field --- lib/upipe-srt/upipe_srt_receiver.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index d99ba8e22..8a2dd33ac 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -153,8 +153,6 @@ struct upipe_srt_receiver { uint64_t previous_ts; - uint64_t ts_wraparounds; - /** public upipe structure */ struct upipe upipe; }; @@ -787,8 +785,6 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->previous_ts = 0; - upipe_srt_receiver->ts_wraparounds = 0; - upipe_throw_ready(upipe); return upipe; } @@ -1226,18 +1222,14 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, /* Note: d32 is converted to unsigned implictly */ if (d32 <= upipe_srt_receiver->latency || -d32 <= upipe_srt_receiver->latency) { if (d32 <= upipe_srt_receiver->latency) { - if (ts < (upipe_srt_receiver->previous_ts % wrap)) - upipe_srt_receiver->ts_wraparounds++; upipe_srt_receiver->previous_ts += delta; } else if (!retransmit) { upipe_srt_receiver->previous_ts = ts; - upipe_srt_receiver->ts_wraparounds = 0; discontinuity = true; } } else { upipe_warn_va(upipe, "clock ref discontinuity %"PRIu64, delta); upipe_srt_receiver->previous_ts = ts; - upipe_srt_receiver->ts_wraparounds = 0; discontinuity = true; } From 645517c87b119c1196106b01706ec2f3f2c63324 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Aug 2024 11:10:04 +0100 Subject: [PATCH 191/231] upipe_srt_receiver: Don't flag non-retransmission out of order packets as a discontinuity --- lib/upipe-srt/upipe_srt_receiver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 8a2dd33ac..e3a55c216 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1223,9 +1223,9 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, if (d32 <= upipe_srt_receiver->latency || -d32 <= upipe_srt_receiver->latency) { if (d32 <= upipe_srt_receiver->latency) { upipe_srt_receiver->previous_ts += delta; - } else if (!retransmit) { - upipe_srt_receiver->previous_ts = ts; - discontinuity = true; + assert(d32 >= 0); + } else { + /* out of order but not too old or new */ } } else { upipe_warn_va(upipe, "clock ref discontinuity %"PRIu64, delta); From 5e63b4188003e01b29eb87e85e2fd3e67a66f2ea Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Aug 2024 11:15:36 +0100 Subject: [PATCH 192/231] upipe_srt_receiver: Throw the correct clock_ref cr_prog value and make sure it's not from the past --- lib/upipe-srt/upipe_srt_receiver.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index e3a55c216..bf1fea742 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1335,13 +1335,18 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, upipe_srt_receiver->last_nack[seq & 0xffff] = fake_last_nack; } - upipe_srt_receiver->expected_seqnum = (seqnum + 1) & ~(1 << 31); + if (!retransmit && diff == 0) { + uint64_t cr_prog; + if (unlikely(!ubase_check(uref_clock_get_cr_prog(uref, &cr_prog)))) { + upipe_warn(upipe, "[srtr] no cr_prog in packet"); + return; + } - if (!retransmit) { - upipe_throw_clock_ref(upipe, uref, - upipe_srt_receiver->previous_ts * UCLOCK_FREQ / 1000000, discontinuity); + upipe_throw_clock_ref(upipe, uref, cr_prog, discontinuity); } + upipe_srt_receiver->expected_seqnum = (seqnum + 1) & ~(1 << 31); + upipe_throw_clock_ts(upipe, uref); return; } From f1c7a4e0b1acfe84308439f9caf0d980e3270a08 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Aug 2024 11:28:38 +0100 Subject: [PATCH 193/231] upipe_srt_receiver: Use the correct units for latency check --- lib/upipe-srt/upipe_srt_receiver.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index bf1fea742..6eff5c6cd 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1219,9 +1219,10 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, int32_t d32 = delta; bool discontinuity = false; + uint64_t latency_us = upipe_srt_receiver->latency * (1000000 / UCLOCK_FREQ); /* Note: d32 is converted to unsigned implictly */ - if (d32 <= upipe_srt_receiver->latency || -d32 <= upipe_srt_receiver->latency) { - if (d32 <= upipe_srt_receiver->latency) { + if (d32 <= latency_us|| -d32 <= latency_us) { + if (d32 <= latency_us) { upipe_srt_receiver->previous_ts += delta; assert(d32 >= 0); } else { From 613de79e3f5ae44b1327c4141b97a5261a528868 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Aug 2024 11:30:36 +0100 Subject: [PATCH 194/231] upipe_srt_receiver: Fix typo --- lib/upipe-srt/upipe_srt_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 6eff5c6cd..b53832639 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1219,7 +1219,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, int32_t d32 = delta; bool discontinuity = false; - uint64_t latency_us = upipe_srt_receiver->latency * (1000000 / UCLOCK_FREQ); + uint64_t latency_us = (upipe_srt_receiver->latency * 1000000) / UCLOCK_FREQ; /* Note: d32 is converted to unsigned implictly */ if (d32 <= latency_us|| -d32 <= latency_us) { if (d32 <= latency_us) { From 298bf66a1e712a087a771daec3236e390dc3ec21 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 28 Aug 2024 22:45:38 +0100 Subject: [PATCH 195/231] upipe_srt_receiver: Treat the first timestamp as a discontinuity This avoids a large delta value being incorrectly treated as negative. (e.g when first timestamp is large) --- lib/upipe-srt/upipe_srt_receiver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index b53832639..78729465f 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -1217,11 +1217,11 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, static const uint64_t wrap = UINT64_C(4294967296); uint64_t delta = (wrap + ts - (upipe_srt_receiver->previous_ts % wrap)) % wrap; int32_t d32 = delta; - bool discontinuity = false; + bool discontinuity = upipe_srt_receiver->previous_ts == 0; uint64_t latency_us = (upipe_srt_receiver->latency * 1000000) / UCLOCK_FREQ; /* Note: d32 is converted to unsigned implictly */ - if (d32 <= latency_us|| -d32 <= latency_us) { + if (!discontinuity && (d32 <= latency_us || -d32 <= latency_us)) { if (d32 <= latency_us) { upipe_srt_receiver->previous_ts += delta; assert(d32 >= 0); @@ -1235,7 +1235,7 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, } upipe_verbose_va(upipe, "Data seq %u (retx %u)", seqnum, retransmit); - if (d32 < 0) + if (d32 < 0 && !discontinuity) uref_clock_set_cr_prog(uref, (upipe_srt_receiver->previous_ts + d32) * UCLOCK_FREQ / 1000000); else uref_clock_set_cr_prog(uref, (upipe_srt_receiver->previous_ts) * UCLOCK_FREQ / 1000000); From 41d61690ffbb5dc8e1f0726598db8986548e552c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 30 Aug 2024 14:55:52 +0100 Subject: [PATCH 196/231] uprobe_dejitter: Add function to set maximum jitter --- include/upipe/uprobe_dejitter.h | 11 +++++++++++ lib/upipe/uprobe_dejitter.c | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/upipe/uprobe_dejitter.h b/include/upipe/uprobe_dejitter.h index 332f1a6bd..206e304e9 100644 --- a/include/upipe/uprobe_dejitter.h +++ b/include/upipe/uprobe_dejitter.h @@ -61,6 +61,9 @@ struct uprobe_dejitter { /** maximum deviation */ double maximum_deviation; + /** maximum jitter */ + uint64_t maximum_jitter; + /** cr_prog of last clock ref */ uint64_t last_cr_prog; /** cr_sys of last clock ref */ @@ -130,6 +133,14 @@ void uprobe_dejitter_set_minimum_deviation(struct uprobe *uprobe, void uprobe_dejitter_set_maximum_deviation(struct uprobe *uprobe, double deviation); +/** @This sets the maximum jitter of the dejittering probe. + * + * @param uprobe pointer to probe + * @param jitter maximum jitter to set + */ +void uprobe_dejitter_set_maximum_jitter(struct uprobe *uprobe, + uint64_t jitter); + #ifdef __cplusplus } #endif diff --git a/lib/upipe/uprobe_dejitter.c b/lib/upipe/uprobe_dejitter.c index 9f3e28d7b..f2a077918 100644 --- a/lib/upipe/uprobe_dejitter.c +++ b/lib/upipe/uprobe_dejitter.c @@ -102,7 +102,7 @@ static int uprobe_dejitter_clock_ref(struct uprobe *uprobe, struct upipe *upipe, if (unlikely(discontinuity)) upipe_warn(upipe, "[dejitter] discontinuity"); else if (unlikely(uprobe_dejitter->offset && fabs(offset - uprobe_dejitter->offset) > - MAX_JITTER + 3 * uprobe_dejitter->deviation)) { + uprobe_dejitter->maximum_jitter + 3 * uprobe_dejitter->deviation)) { upipe_warn_va(upipe, "[dejitter] max jitter reached (%f ms)", (offset - uprobe_dejitter->offset) * 1000 / UCLOCK_FREQ); discontinuity = 1; @@ -331,6 +331,19 @@ void uprobe_dejitter_set_maximum_deviation(struct uprobe *uprobe, uprobe_dejitter->deviation = deviation; } +/** @This sets the maximum jitter of the dejittering probe. + * + * @param uprobe pointer to probe + * @param jitter maximum jitter to set + */ +void uprobe_dejitter_set_maximum_jitter(struct uprobe *uprobe, + uint64_t jitter) +{ + struct uprobe_dejitter *uprobe_dejitter = + uprobe_dejitter_from_uprobe(uprobe); + uprobe_dejitter->maximum_jitter = jitter; +} + /** @This initializes an already allocated uprobe_dejitter structure. * * @param uprobe_pfx pointer to the already allocated structure @@ -349,6 +362,7 @@ struct uprobe *uprobe_dejitter_init(struct uprobe_dejitter *uprobe_dejitter, uprobe_dejitter->last_print = 0; uprobe_dejitter->minimum_deviation = 0; uprobe_dejitter->maximum_deviation = 0; + uprobe_dejitter->maximum_jitter = MAX_JITTER; uprobe_dejitter_set(uprobe, enabled, deviation); uprobe_init(uprobe, uprobe_dejitter_throw, next); return uprobe; From 41a5994f432cb0f30c32af4ace10a0d2e0b60b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 5 Sep 2024 14:43:43 +0200 Subject: [PATCH 197/231] srtr: remove unused variable --- lib/upipe-srt/upipe_srt_receiver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 78729465f..234a41c3e 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -570,7 +570,6 @@ static void upipe_srt_receiver_timer(struct upump *upump) struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); uint64_t now = uclock_now(upipe_srt_receiver->uclock); - uint64_t rtt = upipe_srt_receiver_get_rtt(upipe); struct uchain *uchain, *uchain_tmp; ulist_delete_foreach(&upipe_srt_receiver->queue, uchain, uchain_tmp) { From 1bb69a6f197b7ea8ca40843149012272782c6304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 5 Sep 2024 14:53:21 +0200 Subject: [PATCH 198/231] srt_tx: depends on bitstream --- examples/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index 0c03cc9f6..f5aec7add 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -27,7 +27,7 @@ fec_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPETS_LIBS) rist_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) srt_rx_CFLAGS = $(AM_CFLAGS) srt_rx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPESRT_LIBS) -srt_tx_CFLAGS = $(AM_CFLAGS) +srt_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) srt_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPESRT_LIBS) rist_tx_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS) rist_tx_LDADD = $(LDADD) $(UPUMPEV_LIBS) $(UPIPEMODULES_LIBS) $(UPIPEFILTERS_LIBS) From c9b9d436a6c3e28bbe7898fa0d29d65de6e8e7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 6 Sep 2024 13:47:04 +0200 Subject: [PATCH 199/231] srth: handle AES_GCM cipher when proposed --- lib/upipe-srt/upipe_srt_handshake.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index da9d29d7f..ef6e73ff2 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -112,6 +112,7 @@ struct upipe_srt_handshake { uint8_t sek[2][32]; uint8_t sek_len; uint8_t kk; + uint8_t cipher; struct uref *kmreq; @@ -444,6 +445,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->sek_len = 0; upipe_srt_handshake->kk = 1; + upipe_srt_handshake->cipher = SRT_KMREQ_CIPHER_NONE; upipe_srt_handshake->kmreq = NULL; upipe_srt_handshake->password = NULL; @@ -860,11 +862,17 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * upipe_srt_handshake->kk = srt_km_get_kk(ext); uint8_t cipher = srt_km_get_cipher(ext); - if (cipher != SRT_KMREQ_CIPHER_AES) { + if (cipher != SRT_KMREQ_CIPHER_AES_CTR && cipher != SRT_KMREQ_CIPHER_AES_GCM) { upipe_err_va(upipe, "Unsupported cipher %u", cipher); return false; } + uint8_t auth = srt_km_get_auth(ext); + if (cipher == SRT_KMREQ_CIPHER_AES_GCM && auth != SRT_KMREQ_AUTH_AES_GCM) { + upipe_err_va(upipe, "Unsupported auth %u with AES-GCM cipher", auth); + return false; + } + uint8_t klen = 4 * srt_km_get_klen(ext); if (upipe_srt_handshake->sek_len != klen) upipe_warn_va(upipe, "Requested key length %u, got %u. Proceeding.", @@ -918,6 +926,8 @@ static bool upipe_srt_handshake_parse_kmreq(struct upipe *upipe, const uint8_t * memcpy(upipe_srt_handshake->sek[(upipe_srt_handshake->kk & (1<<0)) ? 0 : 1], osek, klen); } + upipe_srt_handshake->cipher = cipher; + return true; key_error: @@ -942,10 +952,14 @@ static void make_km_msg(struct upipe *upipe, uint8_t *out_ext, const uint8_t *wr out_ext[0] = 0x12; // S V PT out_ext[1] = 0x20; out_ext[2] = 0x29; // Sign srt_km_set_kk(out_ext, upipe_srt_handshake->kk); - srt_km_set_cipher(out_ext, SRT_KMREQ_CIPHER_AES); out_ext[10] = 2; // SE out_ext[14] = 4; // slen; + uint8_t cipher = upipe_srt_handshake->cipher; + srt_km_set_cipher(out_ext, cipher); + if (cipher == SRT_KMREQ_CIPHER_AES_GCM) + srt_km_set_auth(out_ext, SRT_KMREQ_AUTH_AES_GCM); + srt_km_set_klen(out_ext, klen / 4); memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE-16], upipe_srt_handshake->salt, 16); memcpy(&out_ext[SRT_KMREQ_COMMON_SIZE], wrap, wrap_len); From 73e7770846cffd4e4bcc3a33994d4102c377f3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 6 Sep 2024 14:42:36 +0200 Subject: [PATCH 200/231] srth: AES_CTR uses only 14 bytes from the salt, AES_GCM uses 12 We'll use this fact to differentiate the cipher used in subpipe --- lib/upipe-srt/upipe_srt_handshake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index ef6e73ff2..fe5476cb2 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -784,7 +784,7 @@ static void upipe_srt_handshake_finalize(struct upipe *upipe) uref_flow_set_id(flow_def, upipe_srt_handshake->remote_socket_id); struct udict_opaque opaque; opaque.v = upipe_srt_handshake->salt; - opaque.size = 16; + opaque.size = (upipe_srt_handshake->cipher == SRT_KMREQ_CIPHER_AES_GCM) ? 12 : 14; if (!ubase_check(uref_attr_set_opaque(flow_def, opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) upipe_err(upipe, "damn"); From e96e1bf1130924b0476fffdeca34952b616925c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 6 Sep 2024 14:56:56 +0200 Subject: [PATCH 201/231] srtr: AES GCM --- lib/upipe-srt/upipe_srt_receiver.c | 78 ++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 234a41c3e..b40b115f3 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -145,7 +145,8 @@ struct upipe_srt_receiver { uint64_t rtt; uint64_t rtt_variance; - uint8_t salt[16]; + uint8_t salt[14]; + uint8_t salt_len; uint8_t sek[2][32]; uint8_t sek_len; @@ -779,6 +780,7 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver->bytes = 0; upipe_srt_receiver->sek_len = 0; + upipe_srt_receiver->salt_len = 0; upipe_srt_receiver->establish_time = 0; @@ -898,9 +900,10 @@ static int upipe_srt_receiver_set_flow_def(struct upipe *upipe, struct uref *flo struct udict_opaque opaque; if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) { - if (opaque.size > 16) - opaque.size = 16; - memcpy(upipe_srt_receiver->salt, opaque.v, opaque.size); + upipe_srt_receiver->salt_len = opaque.size; + if (upipe_srt_receiver->salt_len > sizeof(upipe_srt_receiver->salt)) + upipe_srt_receiver->salt_len = sizeof(upipe_srt_receiver->salt); + memcpy(upipe_srt_receiver->salt, opaque.v, upipe_srt_receiver->salt_len); } #ifdef UPIPE_HAVE_GCRYPT_H @@ -1209,6 +1212,11 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uint32_t ts = srt_get_packet_timestamp(buf); uint8_t kk = srt_get_data_packet_encryption(buf); + uint8_t aad[16]; + bool gcm = encryption && upipe_srt_receiver->salt_len == 12; + if (gcm) + memcpy(aad, buf, 16); + ubase_assert(uref_block_unmap(uref, 0)); uref_block_resize(uref, SRT_HEADER_SIZE, -1); /* skip SRT header */ total_size -= SRT_HEADER_SIZE; @@ -1263,11 +1271,12 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, uint8_t iv[16]; memset(&iv, 0, 16); - iv[10] = (seqnum >> 24) & 0xff; - iv[11] = (seqnum >> 16) & 0xff; - iv[12] = (seqnum >> 8) & 0xff; - iv[13] = seqnum & 0xff; - for (int i = 0; i < 112/8; i++) + uint8_t seq_idx = upipe_srt_receiver->salt_len - 4; + iv[seq_idx++] = (seqnum >> 24) & 0xff; + iv[seq_idx++] = (seqnum >> 16) & 0xff; + iv[seq_idx++] = (seqnum >> 8) & 0xff; + iv[seq_idx++] = seqnum & 0xff; + for (int i = 0; i < upipe_srt_receiver->salt_len; i++) iv[i] ^= salt[i]; uint8_t *buf; @@ -1278,7 +1287,8 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, gcry_cipher_hd_t aes; gpg_error_t err; - err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, 0); + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, + gcm ? GCRY_CIPHER_MODE_GCM : GCRY_CIPHER_MODE_CTR, 0); if (err) { upipe_err_va(upipe, "Cipher open failed (0x%x)", err); goto error; @@ -1290,16 +1300,46 @@ static void upipe_srt_receiver_input(struct upipe *upipe, struct uref *uref, goto error_close; } - err = gcry_cipher_setctr(aes, iv, 16); - if (err) { - upipe_err_va(upipe, "Couldn't set ctr (0x%x)", err); - goto error_close; - } + if (gcm) { + err = gcry_cipher_setiv(aes, iv, upipe_srt_receiver->salt_len); + if (err) { + upipe_err_va(upipe, "Couldn't set iv (0x%x)", err); + goto error_close; + } - err = gcry_cipher_encrypt(aes, buf, size, NULL, 0); - if (err) { - upipe_err_va(upipe, "Couldn't decrypt packet (0x%x)", err); - goto error_close; + err = gcry_cipher_authenticate(aes, aad, 16); + if (err) { + upipe_err_va(upipe, "Couldn't set aad (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_decrypt(aes, buf, size - 16, NULL, 0); + if (err) { + upipe_err_va(upipe, "Couldn't decrypt packet (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_checktag(aes, &buf[size - 16], 16); + if (err) { + upipe_err_va(upipe, "Couldn't check tag (0x%x)", err); + goto error_close; + } + + // remove tag + if (unlikely(!ubase_check(uref_block_resize(uref, 0, size - 16)))) + upipe_err(upipe, "cannot resize"); + } else { + err = gcry_cipher_setctr(aes, iv, 16); + if (err) { + upipe_err_va(upipe, "Couldn't set ctr (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_encrypt(aes, buf, size, NULL, 0); + if (err) { + upipe_err_va(upipe, "Couldn't decrypt packet (0x%x)", err); + goto error_close; + } } error_close: From 8e0b360a582206a4eb49b03611bea459d36ad369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 6 Sep 2024 16:24:27 +0200 Subject: [PATCH 202/231] srts: AES GCM --- lib/upipe-srt/upipe_srt_sender.c | 109 ++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 22 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index f337c647f..52f8ef6c1 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -101,7 +101,8 @@ struct upipe_srt_sender { /** buffer latency */ uint64_t latency; - uint8_t salt[16]; + uint8_t salt[14]; + uint8_t salt_len; uint8_t sek[2][32]; uint8_t sek_len[2]; @@ -471,9 +472,10 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref struct udict_opaque opaque; if (ubase_check(uref_attr_get_opaque(flow_def, &opaque, UDICT_TYPE_OPAQUE, "enc.salt"))) { - if (opaque.size > 16) - opaque.size = 16; - memcpy(upipe_srt_sender->salt, opaque.v, opaque.size); + upipe_srt_sender->salt_len = opaque.size; + if (upipe_srt_sender->salt_len > sizeof(upipe_srt_sender->salt)) + upipe_srt_sender->salt_len = sizeof(upipe_srt_sender->salt); + memcpy(upipe_srt_sender->salt, opaque.v, upipe_srt_sender->salt_len); } #ifdef UPIPE_HAVE_GCRYPT_H @@ -602,6 +604,7 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, */ upipe_srt_sender->sek_len[0] = 0; upipe_srt_sender->sek_len[1] = 0; + upipe_srt_sender->salt_len = 0; upipe_srt_sender->even_key = true; upipe_srt_sender->packets_since_key = 0; @@ -634,6 +637,10 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref return; } + size_t total_size; + ubase_assert(uref_block_size(uref, &total_size)); + + struct ubuf *tag = NULL; struct ubuf *insert = ubuf_block_alloc(upipe_srt_sender->ubuf_mgr, SRT_HEADER_SIZE); if (!insert) { upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); @@ -689,7 +696,10 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref /* invert the boolean to get the right index */ int key = !upipe_srt_sender->even_key; if (upipe_srt_sender->sek_len[key]) { - // + srt_set_data_packet_encryption(buf, key ? SRT_DATA_ENCRYPTION_ODD : SRT_DATA_ENCRYPTION_EVEN); + + bool gcm = upipe_srt_sender->salt_len == 12; + uint8_t *data; int s = -1; if (ubase_check(uref_block_write(uref, 0, &s, &data))) { @@ -699,16 +709,18 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref uint8_t iv[16]; memset(&iv, 0, 16); - iv[10] = (seqnum >> 24) & 0xff; - iv[11] = (seqnum >> 16) & 0xff; - iv[12] = (seqnum >> 8) & 0xff; - iv[13] = seqnum & 0xff; - for (int i = 0; i < 112/8; i++) + uint8_t seq_idx = upipe_srt_sender->salt_len - 4; + iv[seq_idx++] = (seqnum >> 24) & 0xff; + iv[seq_idx++] = (seqnum >> 16) & 0xff; + iv[seq_idx++] = (seqnum >> 8) & 0xff; + iv[seq_idx++] = seqnum & 0xff; + for (int i = 0; i < upipe_srt_sender->salt_len; i++) iv[i] ^= salt[i]; gcry_cipher_hd_t aes; gpg_error_t err; - err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, 0); + err = gcry_cipher_open(&aes, GCRY_CIPHER_AES, + gcm ? GCRY_CIPHER_MODE_GCM : GCRY_CIPHER_MODE_CTR, 0); if (err) { upipe_err_va(upipe, "Cipher open failed (0x%x)", err); goto error; @@ -720,16 +732,56 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref goto error_close; } - err = gcry_cipher_setctr(aes, iv, 16); - if (err) { - upipe_err_va(upipe, "Couldn't set encryption ctr (0x%x)", err); - goto error_close; - } - - err = gcry_cipher_encrypt(aes, data, s, NULL, 0); - if (err) { - upipe_err_va(upipe, "Couldn't encrypt packet (0x%x)", err); - goto error_close; + if (gcm) { + err = gcry_cipher_setiv(aes, iv, upipe_srt_sender->salt_len); + if (err) { + upipe_err_va(upipe, "Couldn't set iv (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_authenticate(aes, buf, 16); + if (err) { + upipe_err_va(upipe, "Couldn't set aad (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_encrypt(aes, data, s, NULL, 0); + if (err) { + upipe_err_va(upipe, "Couldn't decrypt packet (0x%x)", err); + goto error_close; + } + + tag = ubuf_block_alloc(upipe_srt_sender->ubuf_mgr, 16); + if (!tag) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + goto error_close; + } + + uint8_t *buf_tag; + int s_tag = -1; + if (unlikely(!ubase_check(ubuf_block_write(tag, 0, &s_tag, &buf_tag)))) { + upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); + goto error_close; + } + + err = gcry_cipher_gettag(aes, buf_tag, 16); + ubuf_block_unmap(tag, 0); + if (err) { + upipe_err_va(upipe, "Couldn't get tag (0x%x)", err); + goto error_close; + } + } else { + err = gcry_cipher_setctr(aes, iv, 16); + if (err) { + upipe_err_va(upipe, "Couldn't set encryption ctr (0x%x)", err); + goto error_close; + } + + err = gcry_cipher_encrypt(aes, data, s, NULL, 0); + if (err) { + upipe_err_va(upipe, "Couldn't encrypt packet (0x%x)", err); + goto error_close; + } } error_close: @@ -742,12 +794,13 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref ubuf_block_unmap(insert, 0); ubuf_free(insert); uref_free(uref); + if (tag) + ubuf_free(tag); return; } } // - srt_set_data_packet_encryption(buf, key ? SRT_DATA_ENCRYPTION_ODD : SRT_DATA_ENCRYPTION_EVEN); } else #endif srt_set_data_packet_encryption(buf, SRT_DATA_ENCRYPTION_CLEAR); @@ -757,9 +810,21 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN); ubuf_free(insert); uref_free(uref); + if (tag) + ubuf_free(tag); return; } + if (tag ) { + int ret = uref_block_append(uref, tag); + if (!ubase_check(ret)) { + upipe_throw_fatal(upipe, ret); + uref_free(uref); + ubuf_free(tag); + return; + } + } + uref_attr_set_priv(uref, seqnum); /* Output packet immediately */ From b50a8309e0ce0fa51c5c47047e008419e5a32946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 6 Sep 2024 16:26:26 +0200 Subject: [PATCH 203/231] srth: default to AES CTR for now --- lib/upipe-srt/upipe_srt_handshake.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index fe5476cb2..aedeffc8e 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -956,6 +956,8 @@ static void make_km_msg(struct upipe *upipe, uint8_t *out_ext, const uint8_t *wr out_ext[14] = 4; // slen; uint8_t cipher = upipe_srt_handshake->cipher; + if (cipher == SRT_KMREQ_CIPHER_NONE) + cipher = SRT_KMREQ_CIPHER_AES_CTR; // TODO : favor GCM? srt_km_set_cipher(out_ext, cipher); if (cipher == SRT_KMREQ_CIPHER_AES_GCM) srt_km_set_auth(out_ext, SRT_KMREQ_AUTH_AES_GCM); From 5d48d60e2f3bdc90d38fc02f1fadcbd31947f40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 12 Sep 2024 14:55:33 +0200 Subject: [PATCH 204/231] srt_rx: rename uprobe_obe_log --- examples/srt_rx.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/srt_rx.c b/examples/srt_rx.c index 0940041b2..4eee21fca 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -73,7 +73,7 @@ /* structure */ -struct uprobe_obe_log { +struct uprobe_log { struct urefcount urefcount; struct uclock *uclock; struct uprobe uprobe; @@ -82,15 +82,15 @@ struct uprobe_obe_log { }; /* helper */ -UPROBE_HELPER_UPROBE(uprobe_obe_log, uprobe) +UPROBE_HELPER_UPROBE(uprobe_log, uprobe) /* alloc */ -struct uprobe *uprobe_obe_log_alloc(struct uprobe *next); +struct uprobe *uprobe_log_alloc(struct uprobe *next); -static int uprobe_obe_log_throw(struct uprobe *uprobe, struct upipe *upipe, +static int uprobe_log_throw(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { - struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + struct uprobe_log *probe_obe_log = uprobe_log_from_uprobe(uprobe); if (event != UPROBE_LOG) return uprobe_throw_next(uprobe, upipe, event, args); @@ -117,41 +117,41 @@ static int uprobe_obe_log_throw(struct uprobe *uprobe, struct upipe *upipe, return uprobe_throw_next(uprobe, upipe, event, args); } -static void uprobe_obe_log_set_loglevel(struct uprobe *uprobe, int loglevel) +static void uprobe_log_set_loglevel(struct uprobe *uprobe, int loglevel) { - struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + struct uprobe_log *probe_obe_log = uprobe_log_from_uprobe(uprobe); uatomic_store(&probe_obe_log->loglevel, loglevel); } -static void uprobe_obe_log_set_uclock(struct uprobe *uprobe, struct uclock *uclock) +static void uprobe_log_set_uclock(struct uprobe *uprobe, struct uclock *uclock) { - struct uprobe_obe_log *probe_obe_log = uprobe_obe_log_from_uprobe(uprobe); + struct uprobe_log *probe_obe_log = uprobe_log_from_uprobe(uprobe); uclock_release(probe_obe_log->uclock); probe_obe_log->uclock = uclock_use(uclock); probe_obe_log->start = uclock_now(uclock); } -static struct uprobe *uprobe_obe_log_init(struct uprobe_obe_log *probe_obe_log, +static struct uprobe *uprobe_log_init(struct uprobe_log *probe_obe_log, struct uprobe *next) { - struct uprobe *probe = uprobe_obe_log_to_uprobe(probe_obe_log); + struct uprobe *probe = uprobe_log_to_uprobe(probe_obe_log); probe_obe_log->uclock = NULL; probe_obe_log->start = UINT64_MAX; uatomic_init(&probe_obe_log->loglevel, UPROBE_LOG_DEBUG); - uprobe_init(probe, uprobe_obe_log_throw, next); + uprobe_init(probe, uprobe_log_throw, next); return probe; } -static void uprobe_obe_log_clean(struct uprobe_obe_log *probe_obe_log) +static void uprobe_log_clean(struct uprobe_log *probe_obe_log) { - uprobe_clean(uprobe_obe_log_to_uprobe(probe_obe_log)); + uprobe_clean(uprobe_log_to_uprobe(probe_obe_log)); uclock_release(probe_obe_log->uclock); uatomic_clean(&probe_obe_log->loglevel); } #define ARGS_DECL struct uprobe *next #define ARGS next -UPROBE_HELPER_ALLOC(uprobe_obe_log); +UPROBE_HELPER_ALLOC(uprobe_log); #undef ARGS #undef ARGS_DECL @@ -446,10 +446,10 @@ int main(int argc, char *argv[]) uclock = uclock_std_alloc(0); - logger = uprobe_obe_log_alloc(logger); + logger = uprobe_log_alloc(logger); - uprobe_obe_log_set_loglevel(logger, loglevel); - uprobe_obe_log_set_uclock(logger, uclock); + uprobe_log_set_loglevel(logger, loglevel); + uprobe_log_set_uclock(logger, uclock); logger = uprobe_uclock_alloc(logger, uclock); assert(logger != NULL); From f3683fe9c238d4584fab1fa879d156b4814929e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 12 Sep 2024 15:13:27 +0200 Subject: [PATCH 205/231] SRT: better comments --- include/upipe-srt/upipe_srt_receiver.h | 2 +- lib/upipe-srt/upipe_srt_handshake.c | 13 ++++++++++--- lib/upipe-srt/upipe_srt_receiver.c | 2 +- lib/upipe-srt/upipe_srt_sender.c | 8 +++----- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/upipe-srt/upipe_srt_receiver.h b/include/upipe-srt/upipe_srt_receiver.h index 77e490f3c..81bace532 100644 --- a/include/upipe-srt/upipe_srt_receiver.h +++ b/include/upipe-srt/upipe_srt_receiver.h @@ -24,7 +24,7 @@ */ /** @file - * @short Upipe module for SRT handshakes + * @short Upipe module receiving SRT */ #ifndef _UPIPE_SRT_UPIPE_SRT_RECEIVER_H_ diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index aedeffc8e..e1926bcab 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -33,7 +33,7 @@ #include "upipe/uref.h" #include "upipe/uref_block.h" #include "upipe/uref_block_flow.h" -#include "upipe/uref_pic.h" // XXX +#include "upipe/uref_pic.h" // XXX are we abusing picture number? #include "upipe/uref_clock.h" #include "upipe/uref_attr.h" #include "upipe/upipe.h" @@ -197,7 +197,14 @@ static void upipe_srt_handshake_shutdown(struct upipe *upipe) uint32_t timestamp = (now - upipe_srt_handshake->establish_time) / 27; struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* wtf */); + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE \ + /* + libsrt will not handle this packet if we don't add an undocumented 4 bytes. + libsrt source code has this to say: + "control info field should be none but "writev" does not allow this" + */ + + 4 + ); if (!uref) return; uint8_t *out; @@ -1567,7 +1574,7 @@ static struct uref *upipe_srt_handshake_handle_ack(struct upipe *upipe, const ui return NULL; struct uref *uref = uref_block_alloc(upipe_srt_handshake->uref_mgr, - upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + upipe_srt_handshake->ubuf_mgr, SRT_HEADER_SIZE + 4 /* undocumented extra padding */); if (!uref) return NULL; uint8_t *out; diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index b40b115f3..e15a6f1ca 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -350,7 +350,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) if (now - upipe_srt_receiver->last_sent > UCLOCK_FREQ) { struct uref *uref = uref_block_alloc(upipe_srt_receiver->uref_mgr, - upipe_srt_receiver->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + upipe_srt_receiver->ubuf_mgr, SRT_HEADER_SIZE + 4 /* undocumented extra padding */); if (uref) { uint8_t *out; int output_size = -1; diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 52f8ef6c1..0d9461397 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -31,7 +31,7 @@ #include "upipe/upipe.h" #include "upipe/uref_block.h" #include "upipe/uref_block_flow.h" -#include "upipe/uref_pic.h" // XXX +#include "upipe/uref_pic.h" // XXX are we abusing picture number? #include "upipe/uref_flow.h" #include "upipe/upipe_helper_upipe.h" #include "upipe/upipe_helper_subpipe.h" @@ -262,7 +262,7 @@ static void upipe_srt_sender_lost_sub_n(struct upipe *upipe, uint32_t seq, uint3 return; } - /* XXX: Is it needed? */ + /* XXX: Do we really need to send DROPREQ ? */ int s = SRT_HEADER_SIZE + SRT_DROPREQ_CIF_SIZE; struct uref *uref = uref_block_alloc(upipe_srt_sender->uref_mgr, @@ -356,7 +356,7 @@ static void upipe_srt_sender_timer(struct upump *upump) if (now - upipe_srt_sender->last_sent > UCLOCK_FREQ) { struct uref *uref = uref_block_alloc(upipe_srt_sender->uref_mgr, - upipe_srt_sender->ubuf_mgr, SRT_HEADER_SIZE + 4 /* WTF */); + upipe_srt_sender->ubuf_mgr, SRT_HEADER_SIZE + 4 /* undocumented extra padding */); if (uref) { uint8_t *out; int output_size = -1; @@ -799,8 +799,6 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref return; } } - - // } else #endif srt_set_data_packet_encryption(buf, SRT_DATA_ENCRYPTION_CLEAR); From 5310a6d3b0d0b67f72a7a821f31577cebfbaebed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 12 Sep 2024 15:15:31 +0200 Subject: [PATCH 206/231] srts: rename confusing variable --- lib/upipe-srt/upipe_srt_sender.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 0d9461397..08123c81d 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -106,7 +106,7 @@ struct upipe_srt_sender { uint8_t sek[2][32]; uint8_t sek_len[2]; - int even_key; + int key_index; size_t packets_since_key; @@ -493,7 +493,7 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref memcpy(upipe_srt_sender->sek[1], opaque.v, opaque.size); } - int even_key = upipe_srt_sender->even_key; + int even_key = upipe_srt_sender->key_index; if (upipe_srt_sender->sek_len[0] && upipe_srt_sender->sek_len[1]) upipe_srt_sender->packets_since_key = 0; else @@ -511,7 +511,7 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref upipe_dbg(upipe, "No encryption key in handshake"); } - upipe_srt_sender->even_key = even_key; + upipe_srt_sender->key_index = even_key; #endif return uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF); @@ -599,13 +599,13 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender->establish_time = 0; /* Note: 0 is the even key and 1 is the odd key. - When upipe_srt_sender->even_key = true - upipe_srt_sender->sek[!upipe_srt_sender->even_key] is the even key + When upipe_srt_sender->key_index = true + upipe_srt_sender->sek[!upipe_srt_sender->key_index] is the even key */ upipe_srt_sender->sek_len[0] = 0; upipe_srt_sender->sek_len[1] = 0; upipe_srt_sender->salt_len = 0; - upipe_srt_sender->even_key = true; + upipe_srt_sender->key_index = true; upipe_srt_sender->packets_since_key = 0; upipe_srt_sender->last_sent = 0; @@ -674,7 +674,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref #ifdef UPIPE_HAVE_GCRYPT_H if (++upipe_srt_sender->packets_since_key == SRT_KM_PRE_ANNOUNCEMENT_PERIOD) { /* invert the boolean to get the right index */ - int even_key = !upipe_srt_sender->even_key; + int even_key = !upipe_srt_sender->key_index; if (!upipe_srt_sender->sek_len[!even_key] && upipe_srt_sender->sek_len[even_key]) { upipe_err_va(upipe, "Couldn't switch encryption keys: %s key is absent", @@ -688,13 +688,13 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref upipe_dbg(upipe, "Encryption disabled"); } - upipe_srt_sender->even_key = even_key; + upipe_srt_sender->key_index = even_key; } else if (upipe_srt_sender->packets_since_key == 2 * SRT_KM_PRE_ANNOUNCEMENT_PERIOD) { - memset(upipe_srt_sender->sek[upipe_srt_sender->even_key], 0, sizeof(upipe_srt_sender->sek[0])); + memset(upipe_srt_sender->sek[upipe_srt_sender->key_index], 0, sizeof(upipe_srt_sender->sek[0])); } /* invert the boolean to get the right index */ - int key = !upipe_srt_sender->even_key; + int key = !upipe_srt_sender->key_index; if (upipe_srt_sender->sek_len[key]) { srt_set_data_packet_encryption(buf, key ? SRT_DATA_ENCRYPTION_ODD : SRT_DATA_ENCRYPTION_EVEN); From 8912b8c97f115b0eb3ce82f6b747bc6aa2665dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 20 Sep 2024 11:56:33 +0200 Subject: [PATCH 207/231] srtr: delete cr_prog before outputting uref This can break up scheduling for some reason We needed it for dejitter, we don't need it anymore --- lib/upipe-srt/upipe_srt_receiver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index e15a6f1ca..23f791fd2 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -608,6 +608,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) upipe_srt_receiver->bytes -= size; uref_clock_set_cr_sys(uref, cr_sys + upipe_srt_receiver->latency); + uref_clock_delete_date_prog(uref); upipe_srt_receiver_output(upipe, uref, NULL); // XXX: use timer upump ? static uint64_t old; From 60b193886c52378e38714cb5675abf802f4c28a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 26 Sep 2024 14:25:31 +0200 Subject: [PATCH 208/231] srth: debug induction type --- lib/upipe-srt/upipe_srt_handshake.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index e1926bcab..eed3aa365 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1378,6 +1378,19 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi return uref; } +static const char *get_hs_type(uint32_t type) +{ + switch (type) { + case SRT_HANDSHAKE_TYPE_DONE: return "done"; + case SRT_HANDSHAKE_TYPE_AGREEMENT: return "agreement"; + case SRT_HANDSHAKE_TYPE_CONCLUSION: return "conclusion"; + case SRT_HANDSHAKE_TYPE_WAVEHAND: return "wavehand"; + case SRT_HANDSHAKE_TYPE_INDUCTION: return "induction"; + /* rejections */ + } + return "?"; +} + static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uint8_t *buf, int size, uint64_t now) { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); @@ -1424,12 +1437,12 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (conclusion) { /* Don't send a rejection as it could be a duplicate Induction on a long latency link */ if (hs_type != SRT_HANDSHAKE_TYPE_CONCLUSION) { - upipe_dbg_va(upipe, "Expected conclusion, ignore hs type 0x%x", hs_type); + upipe_dbg_va(upipe, "Expected conclusion, ignore hs type %s", get_hs_type(hs_type)); return NULL; } } else { if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { - upipe_err_va(upipe, "Expected induction, ignore hs type 0x%x", hs_type); + upipe_err_va(upipe, "Expected induction, ignore hs type %s", get_hs_type(hs_type)); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } From 8df26c70d524a1efde351eb97abf36fc1d439c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 26 Sep 2024 14:29:39 +0200 Subject: [PATCH 209/231] srth: terminate pipeline on handshake failure Make upipe_srt_handshake_handle_hs_listener_conclusion() throw source end in case of failure Most notable error case is a wrong password Throwing source end will let application restart pipeline and not leave a half-connected state. --- lib/upipe-srt/upipe_srt_handshake.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index eed3aa365..79e333d7b 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1250,12 +1250,14 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->dst_socket_id != 0) { upipe_err_va(upipe, "Malformed conclusion handshake (dst_socket_id 0x%08x)", hs_packet->dst_socket_id); upipe_srt_handshake->expect_conclusion = false; + upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie) { upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); upipe_srt_handshake->expect_conclusion = false; + upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1264,6 +1266,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { upipe_err(upipe, "Malformed conclusion handshake (size)"); upipe_srt_handshake->expect_conclusion = false; + upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1305,6 +1308,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (upipe_srt_handshake->password && !got_key) { upipe_err(upipe, "Password specified but could not get streaming key"); + upipe_throw_source_end(upipe); upipe_srt_handshake->expect_conclusion = false; return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_BADSECRET); From 2fa20a0c24ab400f03c8b628e25ede6d90dc5523 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 30 Sep 2024 10:27:50 +0100 Subject: [PATCH 210/231] srtr: Delete drift_rate before outputting uref (cherry picked from commit d6ae88b610a5e2c131fe6bfc4a3f6ee10ad3d8c8) --- lib/upipe-srt/upipe_srt_receiver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 23f791fd2..23be6fa3c 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -609,6 +609,7 @@ static void upipe_srt_receiver_timer(struct upump *upump) uref_clock_set_cr_sys(uref, cr_sys + upipe_srt_receiver->latency); uref_clock_delete_date_prog(uref); + uref_clock_delete_rate(uref); upipe_srt_receiver_output(upipe, uref, NULL); // XXX: use timer upump ? static uint64_t old; From 89e709e116e7c8f31d4168a0e5a0c70b78bbbdb7 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 23 Oct 2024 16:44:25 +0100 Subject: [PATCH 211/231] upipe_srt_handshake: Throw source end if socket id is wrong. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes getting stuck with old caller (cherry picked from commit 453f3958e0982043b4c4b9508b8cbcae9ffe8986) Signed-off-by: Rafaël Carré --- lib/upipe-srt/upipe_srt_handshake.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 79e333d7b..b191c962b 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1708,6 +1708,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, upipe_srt_handshake->socket_id); ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); + upipe_throw_source_end(upipe); return; } From 3658720d371095ff8aea5f0bf49f9f2ce279fff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 10:59:36 +0100 Subject: [PATCH 212/231] srth: reject unset socket_id if packet is not a handshake --- lib/upipe-srt/upipe_srt_handshake.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index b191c962b..a0e355123 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1702,7 +1702,20 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, return; } + bool control = srt_get_packet_control(buf); uint32_t dst_socket_id = srt_get_packet_dst_socket_id(buf); + + if (dst_socket_id == 0) { + uint16_t type = srt_get_control_packet_type(buf); + if (!control || type != SRT_CONTROL_TYPE_HANDSHAKE) { + upipe_dbg(upipe, "dst socket id unset"); + ubase_assert(uref_block_unmap(uref, 0)); + uref_free(uref); + upipe_throw_source_end(upipe); + return; + } + } + if (dst_socket_id && dst_socket_id != upipe_srt_handshake->socket_id) { upipe_dbg_va(upipe, "0x%08x != 0x%08x", dst_socket_id, upipe_srt_handshake->socket_id); @@ -1716,7 +1729,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, if (upipe_srt_handshake->upump_keepalive_timeout && dst_socket_id == upipe_srt_handshake->socket_id) upipe_srt_handshake_restart_keepalive_timeout(upipe); - if (srt_get_packet_control(buf)) { + if (control) { bool handled = false; struct uref *reply = upipe_srt_handshake_input_control(upipe, buf, size, &handled); ubase_assert(uref_block_unmap(uref, 0)); From 5bebb60f66668bd432e6d1398969c9f1fc60baac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 11:40:55 +0100 Subject: [PATCH 213/231] srt_tx: do not modify args --- examples/srt_tx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/srt_tx.c b/examples/srt_tx.c index 4c1b30419..f63e5e246 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -205,11 +205,11 @@ static int catch_udp(struct uprobe *uprobe, struct upipe *upipe, upump_start(u); return uprobe_throw_next(uprobe, upipe, event, args); case UPROBE_UDPSRC_NEW_PEER: { - int udp_fd; - int sig = va_arg(args, int); - if (sig != UPIPE_UDPSRC_SIGNATURE) + if (ubase_get_signature(args) != UPIPE_UDPSRC_SIGNATURE) break; + va_arg(args, unsigned int); // signature + int udp_fd; ubase_assert(upipe_udpsink_get_fd(upipe_udpsink, &udp_fd)); if (udp_fd >= 0) { upipe_err(upipe, "Already connected, ignoring"); From 7f53feb172c7284252cc142f05e91c3a9775e609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 11:49:38 +0100 Subject: [PATCH 214/231] srth: throw an event when we get connected or disconnected srt_tx: use this event to "disconnect" from remote peer --- examples/srt_tx.c | 10 ++++++++++ include/upipe-srt/upipe_srt_handshake.h | 8 ++++++++ lib/upipe-srt/upipe_srt_handshake.c | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/examples/srt_tx.c b/examples/srt_tx.c index f63e5e246..dbd114cd2 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -143,6 +143,16 @@ static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, uint16_t latency_ms; switch (event) { + case UPROBE_SRT_HANDSHAKE_CONNECTED: + if (ubase_get_signature(args) != UPIPE_SRT_HANDSHAKE_SIGNATURE) { + return uprobe_throw_next(uprobe, upipe, event, args); + } + va_arg(args, unsigned int); // signature + bool connected = va_arg(args, int ); + upipe_notice_va(upipe, "%sCONNECTED", connected ? "" : "DIS"); + if (!connected) + ubase_assert(upipe_set_uri(upipe_udpsink, NULL)); + return UBASE_ERR_NONE; case UPROBE_SOURCE_END: upipe_warn(upipe, "Remote shutdown"); struct upump *u = upump_alloc_timer(upump_mgr, stop, upipe_udpsrc, diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h index 389096e64..b6ea502eb 100644 --- a/include/upipe-srt/upipe_srt_handshake.h +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -55,6 +55,14 @@ enum upipe_srt_handshake_command { UPIPE_SRT_HANDSHAKE_GET_LATENCY, }; +/** @This extends uprobe_throw with specific events. */ +enum uprobe_srt_handshake_event { + UPROBE_SRT_HANDSHAKE_SENTINEL = UPROBE_LOCAL, + + /** connection status changed (bool) */ + UPROBE_SRT_HANDSHAKE_CONNECTED, +}; + /** @This sets the peer address * * @param upipe description structure of the pipe diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index a0e355123..4dc065704 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -309,6 +309,7 @@ static void upipe_srt_handshake_keepalive_timeout(struct upump *upump) struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_err(upipe, "No data in 10s"); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); upipe_srt_handshake->expect_conclusion = false; @@ -1158,6 +1159,8 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_conclusion(struct upipe size -= ext_len; } + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, true); + upipe_srt_handshake_finalize(upipe); return NULL; } @@ -1250,6 +1253,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->dst_socket_id != 0) { upipe_err_va(upipe, "Malformed conclusion handshake (dst_socket_id 0x%08x)", hs_packet->dst_socket_id); upipe_srt_handshake->expect_conclusion = false; + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); @@ -1257,6 +1261,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie) { upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); upipe_srt_handshake->expect_conclusion = false; + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); @@ -1266,6 +1271,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { upipe_err(upipe, "Malformed conclusion handshake (size)"); upipe_srt_handshake->expect_conclusion = false; + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); @@ -1308,6 +1314,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (upipe_srt_handshake->password && !got_key) { upipe_err(upipe, "Password specified but could not get streaming key"); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); upipe_srt_handshake->expect_conclusion = false; return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, @@ -1376,6 +1383,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi #endif } + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, true); upipe_srt_handshake_finalize(upipe); uref_block_unmap(uref, 0); @@ -1427,6 +1435,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); if (!upipe_srt_handshake->listener) upipe_srt_handshake->syn_cookie = 0; + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_srt_handshake->expect_conclusion = false; return NULL; } @@ -1447,6 +1456,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin } else { if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { upipe_err_va(upipe, "Expected induction, ignore hs type %s", get_hs_type(hs_type)); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1476,6 +1486,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1492,6 +1503,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin hs_packet.extension != SRT_HANDSHAKE_EXT_KMREQ || hs_packet.syn_cookie != 0 || hs_packet.dst_socket_id != 0) { upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", hs_packet.syn_cookie, hs_packet.dst_socket_id); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1646,6 +1658,7 @@ static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const case SRT_CONTROL_TYPE_SHUTDOWN: upipe_err_va(upipe, "shutdown requested"); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); break; @@ -1711,6 +1724,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, upipe_dbg(upipe, "dst socket id unset"); ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); return; } @@ -1721,6 +1735,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, upipe_srt_handshake->socket_id); ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_throw_source_end(upipe); return; } From ff46a4496e7c81790def096e2c6a1e357aa5e9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 15:59:39 +0100 Subject: [PATCH 215/231] srth: remove extraneous check We already check for dst_socket_id in upipe_srt_handshake_input() --- lib/upipe-srt/upipe_srt_handshake.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 4dc065704..bdb16c0a9 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1250,14 +1250,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi { struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - if (hs_packet->dst_socket_id != 0) { - upipe_err_va(upipe, "Malformed conclusion handshake (dst_socket_id 0x%08x)", hs_packet->dst_socket_id); - upipe_srt_handshake->expect_conclusion = false; - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); - return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, - hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); - } if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie) { upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); upipe_srt_handshake->expect_conclusion = false; From 6932c5fdb8223af85b130f30dd15e48c0725228b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 16:23:17 +0100 Subject: [PATCH 216/231] srt_tx: only unset sink uri if we are listener if we are caller the uri never changes --- examples/srt_tx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/srt_tx.c b/examples/srt_tx.c index dbd114cd2..1d131bf4f 100644 --- a/examples/srt_tx.c +++ b/examples/srt_tx.c @@ -150,7 +150,9 @@ static int catch_hs(struct uprobe *uprobe, struct upipe *upipe, va_arg(args, unsigned int); // signature bool connected = va_arg(args, int ); upipe_notice_va(upipe, "%sCONNECTED", connected ? "" : "DIS"); - if (!connected) + + bool listener = dirpath && strchr(dirpath, '@'); + if (!connected && listener) ubase_assert(upipe_set_uri(upipe_udpsink, NULL)); return UBASE_ERR_NONE; case UPROBE_SOURCE_END: From bc51c13d69393f6342b1f306cfa834a1824c6c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 16:24:46 +0100 Subject: [PATCH 217/231] srth: throw source end if remote rejects us --- lib/upipe-srt/upipe_srt_handshake.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index bdb16c0a9..2df6a1e88 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1428,6 +1428,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (!upipe_srt_handshake->listener) upipe_srt_handshake->syn_cookie = 0; upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); + upipe_throw_source_end(upipe); upipe_srt_handshake->expect_conclusion = false; return NULL; } From 11fed1d73b5d7555e38c07e147cd87c427d27b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 7 Nov 2024 16:31:51 +0100 Subject: [PATCH 218/231] srth: rework unexpected handshake packets handling Ignore handshakes with different socket id when we're already connected. Do not send a reply, as it would reach the wrong remote. keepalive will trigger and restart after 10s if needed Second case: if we do not received the expected induction type, trigger disconnection. Since we sent a rejection message we expect a new socket anyway. --- lib/upipe-srt/upipe_srt_handshake.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 2df6a1e88..546874842 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1447,16 +1447,17 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin return NULL; } } else { - if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { - upipe_err_va(upipe, "Expected induction, ignore hs type %s", get_hs_type(hs_type)); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, - hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); - } - + /* We do not expect a conclusion, this means we're either connected, + * or still expecting first packet */ if (upipe_srt_handshake->upump_keepalive_timeout) { + /* We're already connected but received a new socket id */ upipe_dbg(upipe, "Ignore handshake, already connected"); + return NULL; + } + if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { + upipe_err_va(upipe, "Expected induction, ignore hs type %s", get_hs_type(hs_type)); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } From c4641980e1df3aa07beb1e9b8e17b1afe28a6107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Nov 2024 10:41:45 +0000 Subject: [PATCH 219/231] srth: do not throw source end if we're not connected yet --- lib/upipe-srt/upipe_srt_handshake.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 546874842..590545e74 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1254,7 +1254,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); upipe_srt_handshake->expect_conclusion = false; upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1264,7 +1263,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi upipe_err(upipe, "Malformed conclusion handshake (size)"); upipe_srt_handshake->expect_conclusion = false; upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1307,7 +1305,6 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (upipe_srt_handshake->password && !got_key) { upipe_err(upipe, "Password specified but could not get streaming key"); upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); upipe_srt_handshake->expect_conclusion = false; return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_BADSECRET); From 43df7a022ef20c82e57d9b1eab662f9c4c1ba0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 8 Nov 2024 11:11:09 +0100 Subject: [PATCH 220/231] udpsink: set fd to -1 if URI is NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 18904c40d2591d82b30f06a319fc3f8e9766767c) Signed-off-by: Rafaël Carré --- lib/upipe-modules/upipe_udp_sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/upipe-modules/upipe_udp_sink.c b/lib/upipe-modules/upipe_udp_sink.c index d9ab6ff9b..e88e34f4e 100644 --- a/lib/upipe-modules/upipe_udp_sink.c +++ b/lib/upipe-modules/upipe_udp_sink.c @@ -408,7 +408,7 @@ static int _upipe_udpsink_set_uri(struct upipe *upipe, const char *uri) if (unlikely(upipe_udpsink->fd != -1)) { if (likely(upipe_udpsink->uri != NULL)) upipe_notice_va(upipe, "closing socket %s", upipe_udpsink->uri); - close(upipe_udpsink->fd); + ubase_clean_fd(&upipe_udpsink->fd); } ubase_clean_str(&upipe_udpsink->uri); upipe_udpsink_set_upump(upipe, NULL); From d566fb343e5071fc7fb0a82023bd3b40a4b074f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vasseur?= Date: Tue, 13 Feb 2024 17:19:24 +0100 Subject: [PATCH 221/231] ci: use actions upload artifact v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 5cac22d1ef1599b03c54ea378403442b2f68de27) Signed-off-by: Rafaël Carré --- .github/workflows/test-suite.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-suite.yaml b/.github/workflows/test-suite.yaml index dbe2466a0..8ef6d70e5 100644 --- a/.github/workflows/test-suite.yaml +++ b/.github/workflows/test-suite.yaml @@ -189,7 +189,7 @@ jobs: - name: Archive config log if: always() - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.name }}_config.log path: config.log From a3bd5c99b8df11e03eba2870021c1efc5438d7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 16:03:46 +0100 Subject: [PATCH 222/231] srt_rx: handle handshake disconnect This makes sure for example that keepalives coming from srt receiver do not leave to an old remote If handshake did not succeed we do not restart the pipeline, so udp sink would still have a destination set Since srt receiver pipe is still running it keeps sending keepalives --- examples/srt_rx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/examples/srt_rx.c b/examples/srt_rx.c index 4eee21fca..4a1c44926 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -312,6 +312,20 @@ static void sig_cb(struct upump *upump) static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { + if (event == UPROBE_SRT_HANDSHAKE_CONNECTED) { + if (ubase_get_signature(args) != UPIPE_SRT_HANDSHAKE_SIGNATURE) { + return uprobe_throw_next(uprobe, upipe, event, args); + } + va_arg(args, unsigned int); // signature + bool connected = va_arg(args, int ); + bool listener = srcpath && strchr(srcpath, '@'); + upipe_notice_va(upipe, "%sCONNECTED", connected ? "" : "DIS"); + if (!connected && listener) + ubase_assert(upipe_set_uri(upipe_udp_sink, NULL)); + return UBASE_ERR_NONE; + + } + if (event == UPROBE_SOURCE_END) { restart = true; struct upump *u = upump_alloc_timer(upump_mgr, stop, NULL, NULL, 0, 0); From 3423bce9b6ec6acf581c922dd5a83d9fdaae2a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 16:09:28 +0100 Subject: [PATCH 223/231] srth: send disconnection event on timeout --- lib/upipe-srt/upipe_srt_handshake.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 590545e74..167afe63a 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -321,6 +321,7 @@ static void upipe_srt_handshake_timeout(struct upump *upump) struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_err(upipe, "Connection timed out"); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); upipe_srt_handshake->expect_conclusion = false; } From fa774fb5b4532c82f82aaad38ec50e50f43d5b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 16:16:47 +0100 Subject: [PATCH 224/231] srth: do not keep sending handshakes if we timed out --- lib/upipe-srt/upipe_srt_handshake.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 167afe63a..b7ac0b479 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -323,6 +323,7 @@ static void upipe_srt_handshake_timeout(struct upump *upump) upipe_err(upipe, "Connection timed out"); upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); + upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); upipe_srt_handshake->expect_conclusion = false; } From bec697428701bb2c1fbc85edba9702f326704437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 16:23:20 +0100 Subject: [PATCH 225/231] srtr: do not send keepalives until we are connected --- lib/upipe-srt/upipe_srt_receiver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 23be6fa3c..9dcfc8b2e 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -103,7 +103,7 @@ struct upipe_srt_receiver { /** list of output requests */ struct uchain request_list; - uint32_t socket_id; + uint64_t socket_id; struct upipe *control; @@ -348,7 +348,7 @@ static void upipe_srt_receiver_timer_lost(struct upump *upump) uint64_t now = uclock_now(upipe_srt_receiver->uclock); - if (now - upipe_srt_receiver->last_sent > UCLOCK_FREQ) { + if (upipe_srt_receiver->socket_id != UINT64_MAX && now - upipe_srt_receiver->last_sent > UCLOCK_FREQ) { struct uref *uref = uref_block_alloc(upipe_srt_receiver->uref_mgr, upipe_srt_receiver->ubuf_mgr, SRT_HEADER_SIZE + 4 /* undocumented extra padding */); if (uref) { @@ -751,7 +751,7 @@ static struct upipe *upipe_srt_receiver_alloc(struct upipe_mgr *mgr, upipe_srt_receiver_require_uclock(upipe); // FIXME - upipe_srt_receiver->socket_id = 0; + upipe_srt_receiver->socket_id = UINT64_MAX; upipe_srt_receiver->control = NULL; ulist_init(&upipe_srt_receiver->queue); From a53abeccb2860222fea973ac574f8adf1fce4f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 16:30:22 +0100 Subject: [PATCH 226/231] srts: do not send keepalives until we are connected --- lib/upipe-srt/upipe_srt_sender.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index 08123c81d..f8745c90f 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -93,7 +93,7 @@ struct upipe_srt_sender { /** list of output requests */ struct uchain request_list; - uint32_t socket_id; + uint64_t socket_id; uint32_t seqnum; uint64_t establish_time; @@ -354,7 +354,7 @@ static void upipe_srt_sender_timer(struct upump *upump) uint64_t now = uclock_now(upipe_srt_sender->uclock); - if (now - upipe_srt_sender->last_sent > UCLOCK_FREQ) { + if (upipe_srt_sender->socket_id != UINT64_MAX && now - upipe_srt_sender->last_sent > UCLOCK_FREQ) { struct uref *uref = uref_block_alloc(upipe_srt_sender->uref_mgr, upipe_srt_sender->ubuf_mgr, SRT_HEADER_SIZE + 4 /* undocumented extra padding */); if (uref) { @@ -594,7 +594,7 @@ static struct upipe *upipe_srt_sender_alloc(struct upipe_mgr *mgr, upipe_srt_sender_init_uref_mgr(upipe); ulist_init(&upipe_srt_sender->queue); upipe_srt_sender->latency = UCLOCK_FREQ; /* 1 sec */ - upipe_srt_sender->socket_id = 0; + upipe_srt_sender->socket_id = UINT64_MAX; upipe_srt_sender->seqnum = 0; upipe_srt_sender->establish_time = 0; From 2ffc85d6a8172681baf35125f6f29a24684331bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 16:51:14 +0100 Subject: [PATCH 227/231] srth: do not keep sending handshakes --- lib/upipe-srt/upipe_srt_handshake.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index b7ac0b479..8f0a351b9 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -1457,6 +1457,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { upipe_err_va(upipe, "Expected induction, ignore hs type %s", get_hs_type(hs_type)); upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); + upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1480,6 +1481,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); + upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } From 7e5cfbe88776124e8be13a792f87f2c34dfddda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 22 Nov 2024 17:50:14 +0100 Subject: [PATCH 228/231] srts: fix socket_id check --- lib/upipe-srt/upipe_srt_sender.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/upipe-srt/upipe_srt_sender.c b/lib/upipe-srt/upipe_srt_sender.c index f8745c90f..be95a3c3f 100644 --- a/lib/upipe-srt/upipe_srt_sender.c +++ b/lib/upipe-srt/upipe_srt_sender.c @@ -507,7 +507,7 @@ static int upipe_srt_sender_input_set_flow_def(struct upipe *upipe, struct uref if (upipe_srt_sender->sek_len[0] || upipe_srt_sender->sek_len[1]) { upipe_dbg_va(upipe, "Using %s key", even_key ? "even" : "odd"); } else { - if (upipe_srt_sender->socket_id) + if (upipe_srt_sender->socket_id != UINT64_MAX) upipe_dbg(upipe, "No encryption key in handshake"); } @@ -632,7 +632,7 @@ static inline void upipe_srt_sender_input(struct upipe *upipe, struct uref *uref return; } - if (upipe_srt_sender->socket_id == 0) { + if (upipe_srt_sender->socket_id == UINT64_MAX) { uref_free(uref); return; } From 5419615371501b93da48a7da781433fea46a9e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Thu, 12 Sep 2024 08:53:45 +0000 Subject: [PATCH 229/231] srtr: send RTT in stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit a899a14505386ab7c2cbad6398b1014a6122aa86) Signed-off-by: Rafaël Carré --- include/upipe-srt/upipe_srt_receiver.h | 6 +++--- lib/upipe-srt/upipe_srt_receiver.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/upipe-srt/upipe_srt_receiver.h b/include/upipe-srt/upipe_srt_receiver.h index 81bace532..6aae36b05 100644 --- a/include/upipe-srt/upipe_srt_receiver.h +++ b/include/upipe-srt/upipe_srt_receiver.h @@ -42,18 +42,18 @@ extern "C" { enum upipe_srt_receiver_command { UPIPE_SRTR_SENTINEL = UPIPE_CONTROL_LOCAL, - /** get counters (unsigned *, unsigned *, size_t *, size_t *, size_t *, size_t *, size_t *) */ + /** get counters (unsigned *, unsigned *, size_t *, size_t *, size_t *, size_t *, size_t *, unsigned *) */ UPIPE_SRTR_GET_STATS, }; static inline int upipe_srt_receiver_get_stats(struct upipe *upipe, unsigned *expected_seqnum, unsigned *last_output_seqnum, size_t *buffered, size_t *nacks, size_t *repaired, - size_t *lost, size_t *duplicates) + size_t *lost, size_t *duplicates, unsigned *rtt) { return upipe_control(upipe, UPIPE_SRTR_GET_STATS, UPIPE_SRT_RECEIVER_SIGNATURE, expected_seqnum, last_output_seqnum, - buffered, nacks, repaired, lost, duplicates); + buffered, nacks, repaired, lost, duplicates, rtt); } diff --git a/lib/upipe-srt/upipe_srt_receiver.c b/lib/upipe-srt/upipe_srt_receiver.c index 9dcfc8b2e..678acb5a3 100644 --- a/lib/upipe-srt/upipe_srt_receiver.c +++ b/lib/upipe-srt/upipe_srt_receiver.c @@ -987,6 +987,7 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, size_t *repaired = va_arg(args, size_t*); size_t *loss = va_arg(args, size_t*); size_t *dups = va_arg(args, size_t*); + unsigned *rtt = va_arg(args, unsigned*); struct upipe_srt_receiver *upipe_srt_receiver = upipe_srt_receiver_from_upipe(upipe); *buffered = upipe_srt_receiver->buffered; @@ -996,6 +997,7 @@ static int _upipe_srt_receiver_control(struct upipe *upipe, *repaired = upipe_srt_receiver->repaired; *loss = upipe_srt_receiver->loss; *dups = upipe_srt_receiver->dups; + *rtt = upipe_srt_receiver->rtt * 1000 / UCLOCK_FREQ; upipe_srt_receiver->nacks = 0; upipe_srt_receiver->repaired = 0; From 3ad75d93a76465cc05a0e4ed74f38980b67d16e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 20 Dec 2024 14:14:03 +0100 Subject: [PATCH 230/231] srth: sync with rogue changes --- include/upipe-srt/upipe_srt_handshake.h | 2 +- lib/upipe-srt/upipe_srt_handshake.c | 123 +++++++++++++++++------- 2 files changed, 91 insertions(+), 34 deletions(-) diff --git a/include/upipe-srt/upipe_srt_handshake.h b/include/upipe-srt/upipe_srt_handshake.h index b6ea502eb..88d7cd188 100644 --- a/include/upipe-srt/upipe_srt_handshake.h +++ b/include/upipe-srt/upipe_srt_handshake.h @@ -59,7 +59,7 @@ enum upipe_srt_handshake_command { enum uprobe_srt_handshake_event { UPROBE_SRT_HANDSHAKE_SENTINEL = UPROBE_LOCAL, - /** connection status changed (bool) */ + /** connection status changed (bool, bool, bool) */ UPROBE_SRT_HANDSHAKE_CONNECTED, }; diff --git a/lib/upipe-srt/upipe_srt_handshake.c b/lib/upipe-srt/upipe_srt_handshake.c index 8f0a351b9..d2bf4dfd9 100644 --- a/lib/upipe-srt/upipe_srt_handshake.c +++ b/lib/upipe-srt/upipe_srt_handshake.c @@ -131,6 +131,8 @@ struct upipe_srt_handshake { uint64_t last_hs_sent; + bool end; + /** public upipe structure */ struct upipe upipe; }; @@ -303,28 +305,66 @@ static void upipe_srt_handshake_kmreq(struct upump *upump) upipe_srt_handshake_output(&upipe_srt_handshake->upipe, uref_dup(kmreq), NULL); } -static void upipe_srt_handshake_keepalive_timeout(struct upump *upump) +static int upipe_srt_handshake_set_flow_def(struct upipe *upipe, struct uref *flow_def); +static void upipe_srt_handshake_timeout(struct upump *upump); + +static void upipe_srt_handshake_disconnect(struct upipe *upipe, bool end, bool blacklist) { - struct upipe *upipe = upump_get_opaque(upump, struct upipe *); struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); - upipe_err(upipe, "No data in 10s"); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); + /* Connection has just been aborted already */ + + /* No need to keep waiting for keepalives */ + upipe_srt_handshake_set_upump_keepalive_timeout(upipe, NULL); + /* No need to keep sending KMREQ packets */ + upipe_srt_handshake_set_upump_kmreq(upipe, NULL); + /* No need to keep sending handshake packets */ + upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); + + if (upipe_srt_handshake->upump_handshake_timeout) /* if timeout was running we die */ + end = true; + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false, blacklist, end); upipe_srt_handshake->expect_conclusion = false; + + if (end) { + upipe_throw_source_end(upipe); + upipe_srt_handshake->end = true; + /* No need to wait for a timeout */ + upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); + } else { + /* (new) connection has to succeed within 3 seconds */ + struct upump *upump = + upump_alloc_timer(upipe_srt_handshake->upump_mgr, + upipe_srt_handshake_timeout, + upipe, upipe->refcount, + 3 * UCLOCK_FREQ, 0); + upump_start(upump); + upipe_srt_handshake_set_upump_handshake_timeout(upipe, upump); + } + + struct uref *flow_def = uref_block_flow_alloc_def(upipe_srt_handshake->uref_mgr, ""); + if (flow_def) { + upipe_srt_handshake_set_flow_def(upipe, flow_def); + /* force sending flow definition immediately */ + upipe_srt_handshake_output(upipe, NULL, NULL); + } +} + +static void upipe_srt_handshake_keepalive_timeout(struct upump *upump) +{ + struct upipe *upipe = upump_get_opaque(upump, struct upipe *); + + upipe_err(upipe, "No data in 10s"); + upipe_srt_handshake_disconnect(upipe, true, false); } static void upipe_srt_handshake_timeout(struct upump *upump) { struct upipe *upipe = upump_get_opaque(upump, struct upipe *); - struct upipe_srt_handshake *upipe_srt_handshake = upipe_srt_handshake_from_upipe(upipe); upipe_err(upipe, "Connection timed out"); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_srt_handshake_set_upump_handshake_timeout(upipe, NULL); - upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); - upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake_disconnect(upipe, false, false); } static void upipe_srt_handshake_send_timer(struct upump *upump) @@ -460,6 +500,7 @@ static struct upipe *upipe_srt_handshake_alloc(struct upipe_mgr *mgr, upipe_srt_handshake->password = NULL; upipe_srt_handshake->establish_time = 0; + upipe_srt_handshake->end = false; upipe_throw_ready(upipe); return upipe; @@ -1161,7 +1202,7 @@ static struct uref *upipe_srt_handshake_handle_hs_caller_conclusion(struct upipe size -= ext_len; } - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, true); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, true, false, false); upipe_srt_handshake_finalize(upipe); return NULL; @@ -1254,8 +1295,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (hs_packet->syn_cookie != upipe_srt_handshake->syn_cookie) { upipe_err(upipe, "Malformed conclusion handshake (invalid syn cookie)"); - upipe_srt_handshake->expect_conclusion = false; - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); + upipe_srt_handshake_disconnect(upipe, false, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1263,8 +1303,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi /* At least HSREQ is expected */ if (hs_packet->version == SRT_HANDSHAKE_VERSION && size < SRT_HANDSHAKE_CIF_EXTENSION_MIN_SIZE + SRT_HANDSHAKE_HSREQ_SIZE) { upipe_err(upipe, "Malformed conclusion handshake (size)"); - upipe_srt_handshake->expect_conclusion = false; - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); + upipe_srt_handshake_disconnect(upipe, false, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1297,6 +1336,13 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi upipe_err_va(upipe, "Malformed HSREQ: %u < %u\n", ext_len, SRT_HANDSHAKE_HSREQ_SIZE); } else if (ext_type == SRT_HANDSHAKE_EXT_TYPE_KMREQ) { + if (!upipe_srt_handshake->password) { + upipe_err(upipe, "Password not specified but remote requested encryption."); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false, true, false); + upipe_srt_handshake->expect_conclusion = false; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_BADSECRET); + } got_key = upipe_srt_handshake_parse_kmreq(upipe, ext, ext_len, &wrap, &wrap_len); } @@ -1306,8 +1352,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi if (upipe_srt_handshake->password && !got_key) { upipe_err(upipe, "Password specified but could not get streaming key"); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake_disconnect(upipe, false, true); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet->remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_BADSECRET); } @@ -1374,7 +1419,7 @@ static struct uref *upipe_srt_handshake_handle_hs_listener_conclusion(struct upi #endif } - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, true); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, true, false); upipe_srt_handshake_finalize(upipe); uref_block_unmap(uref, 0); @@ -1426,9 +1471,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin upipe_err_va(upipe, "Remote rejected handshake (%s)", get_hs_error(hs_type)); if (!upipe_srt_handshake->listener) upipe_srt_handshake->syn_cookie = 0; - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); - upipe_srt_handshake->expect_conclusion = false; + upipe_srt_handshake_disconnect(upipe, true, false); return NULL; } @@ -1456,8 +1499,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (hs_type != SRT_HANDSHAKE_TYPE_INDUCTION) { upipe_err_va(upipe, "Expected induction, ignore hs type %s", get_hs_type(hs_type)); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); + upipe_srt_handshake_disconnect(upipe, false, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1480,8 +1522,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin if (hs_packet.version != SRT_HANDSHAKE_VERSION || hs_packet.dst_socket_id != upipe_srt_handshake->socket_id) { upipe_err_va(upipe, "Malformed handshake (%08x != %08x)", hs_packet.dst_socket_id, upipe_srt_handshake->socket_id); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_srt_handshake_set_upump_handshake_send(upipe, NULL); + upipe_srt_handshake_disconnect(upipe, false, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1498,7 +1539,7 @@ static struct uref *upipe_srt_handshake_handle_hs(struct upipe *upipe, const uin hs_packet.extension != SRT_HANDSHAKE_EXT_KMREQ || hs_packet.syn_cookie != 0 || hs_packet.dst_socket_id != 0) { upipe_err_va(upipe, "Malformed first handshake syn %u dst_id %u", hs_packet.syn_cookie, hs_packet.dst_socket_id); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); + upipe_srt_handshake_disconnect(upipe, false, false); return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, hs_packet.remote_socket_id, SRT_HANDSHAKE_TYPE_REJ_UNKNOWN); } @@ -1544,6 +1585,14 @@ static struct uref *upipe_srt_handshake_handle_user(struct upipe *upipe, const u const uint8_t *cif = srt_get_control_packet_cif(buf); size -= SRT_HEADER_SIZE; + if (!upipe_srt_handshake->password) { + upipe_err(upipe, "Password not specified but remote requested encryption in user packet."); + upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false, true, false); + upipe_srt_handshake->expect_conclusion = false; + return upipe_srt_handshake_alloc_hs_reject(upipe, timestamp, + srt_get_packet_dst_socket_id(buf), SRT_HANDSHAKE_TYPE_REJ_BADSECRET); + } + if (!upipe_srt_handshake_parse_kmreq(upipe, cif, size, &wrap, &wrap_len)) { return NULL; } @@ -1653,8 +1702,7 @@ static struct uref *upipe_srt_handshake_input_control(struct upipe *upipe, const case SRT_CONTROL_TYPE_SHUTDOWN: upipe_err_va(upipe, "shutdown requested"); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); + upipe_srt_handshake_disconnect(upipe, true, false); break; case SRT_CONTROL_TYPE_DROPREQ: @@ -1686,14 +1734,21 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, upipe_warn(upipe, "No upump mgr"); upipe_srt_handshake_check(upipe, NULL); uref_free(uref); + return; } if (!upipe_srt_handshake->uclock) { upipe_warn(upipe, "No uclock"); upipe_srt_handshake_check(upipe, NULL); uref_free(uref); + return; } + /* Pipe is gonna die soon */ + if (upipe_srt_handshake->end) { + uref_free(uref); + return; + } size_t total_size; ubase_assert(uref_block_size(uref, &total_size)); @@ -1716,11 +1771,14 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, if (dst_socket_id == 0) { uint16_t type = srt_get_control_packet_type(buf); if (!control || type != SRT_CONTROL_TYPE_HANDSHAKE) { - upipe_dbg(upipe, "dst socket id unset"); + upipe_dbg_va(upipe, "dst socket id unset (%s)", + control ? get_ctrl_type(type) : "data"); ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); + // blacklist? + // XXX: find out who is sending shutdown without dst socket set + // XXX: sometimes the legitimate caller does it too + upipe_srt_handshake_disconnect(upipe, true, false); return; } } @@ -1730,8 +1788,7 @@ static void upipe_srt_handshake_input(struct upipe *upipe, struct uref *uref, upipe_srt_handshake->socket_id); ubase_assert(uref_block_unmap(uref, 0)); uref_free(uref); - upipe_throw(upipe, UPROBE_SRT_HANDSHAKE_CONNECTED, UPIPE_SRT_HANDSHAKE_SIGNATURE, false); - upipe_throw_source_end(upipe); + upipe_srt_handshake_disconnect(upipe, true, false); return; } From e05d9d34b4ab2afbc0aaa535552796d9b66ae647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= Date: Fri, 20 Dec 2024 14:22:13 +0100 Subject: [PATCH 231/231] srt_rx: apply latency to dejitter --- examples/srt_rx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/srt_rx.c b/examples/srt_rx.c index 4a1c44926..ac29c2692 100644 --- a/examples/srt_rx.c +++ b/examples/srt_rx.c @@ -168,6 +168,7 @@ static struct upipe *upipe_srtr_sub; static struct uprobe uprobe_udp; static struct uprobe uprobe_srt; static struct uprobe *logger; +static struct uprobe *uprobe_dejitter; static char *dirpath; static char *srcpath; @@ -344,6 +345,13 @@ static int catch_srt(struct uprobe *uprobe, struct upipe *upipe, if (!ubase_check(upipe_set_option(upipe_srtr, "latency", latency_ms_str))) upipe_err(upipe, "Couldn't set receiver latency"); } + if (uprobe_dejitter) { + const uint64_t deviation = latency_ms * UCLOCK_FREQ / 1000 / 3; // actual delay is 3 * this + uprobe_dejitter_set(uprobe_dejitter, true, 1); + uprobe_dejitter_set_minimum_deviation(uprobe_dejitter, deviation); + uprobe_dejitter_set_maximum_deviation(uprobe_dejitter, deviation); + uprobe_dejitter_set_maximum_jitter(uprobe_dejitter, (uint64_t)latency_ms * UCLOCK_FREQ / 1000 / 2); + } } return uprobe_throw_next(uprobe, upipe, event, args); @@ -441,7 +449,7 @@ int main(int argc, char *argv[]) logger = uprobe_stdio_alloc(NULL, stdout, loglevel); assert(logger != NULL); const uint64_t deviation = UCLOCK_FREQ / 30; // actual delay is 3 * this - struct uprobe *uprobe_dejitter = uprobe_dejitter_alloc(logger, true /* enabled */, deviation); + uprobe_dejitter = uprobe_dejitter_alloc(logger, true /* enabled */, deviation); uprobe_dejitter_set_minimum_deviation(uprobe_dejitter, deviation); uprobe_dejitter_set_maximum_deviation(uprobe_dejitter, deviation); assert(uprobe_dejitter != NULL);